Skip to content

Commit 26e3af9

Browse files
authored
Merge pull request #1 from kamkry/strict-plugin
Strict plugin beta
2 parents f927cdf + f307cf8 commit 26e3af9

32 files changed

+4458
-158
lines changed

.eslintignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
dist
3+
sample-project
4+
e2e

.eslintrc

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": [
5+
"@typescript-eslint"
6+
],
7+
"extends": [
8+
"eslint:recommended",
9+
"plugin:@typescript-eslint/eslint-recommended",
10+
"plugin:@typescript-eslint/recommended"
11+
],
12+
"rules": {
13+
"@typescript-eslint/explicit-module-boundary-types": "off",
14+
"@typescript-eslint/ban-ts-comment": "warn"
15+
}
16+
}

.github/workflows/ci.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: CI
2+
3+
on:
4+
[push, pull_request]
5+
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- uses: actions/checkout@v2
12+
- name: Use Node.js 14.x
13+
uses: actions/setup-node@v1
14+
with:
15+
node-version: '14.x'
16+
- run: npm i
17+
- run: npm run build
18+
- run: npm run e2e

.github/workflows/package.yml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: NPM Package
2+
on:
3+
release:
4+
types: [created]
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v2
10+
# Setup .npmrc file to publish to npm
11+
- uses: actions/setup-node@v2
12+
with:
13+
node-version: '12.x'
14+
registry-url: 'https://registry.npmjs.org'
15+
- run: npm install
16+
- run: npm run build
17+
- run: npm publish
18+
env:
19+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
tsserver.log
21
node_modules
3-
dist/**/*
4-
.idea/**/*
5-
.DS_Store
2+
dist
3+
e2e_coverage

.prettierignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist
3+
sample-project

.prettierrc

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
{
2-
"arrowParens": "always",
2+
"printWidth": 100,
3+
"tabWidth": 2,
4+
"useTabs": false,
35
"semi": true,
6+
"singleQuote": true,
47
"trailingComma": "all",
5-
"singleQuote": true
8+
"bracketSpacing": true,
9+
"jsxBracketSameLine": false,
10+
"arrowParens": "always",
11+
"proseWrap": "always"
612
}

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Jarosław Glegoła Kamil Krysiak
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Typescript strict mode plugin
2+
3+
Typescript plugin that allows turning on strict mode in specific files or directories.
4+
5+
## Do i need this plugin?
6+
This plugin was created for bigger repositories that want to incorporate typescript strict mode, but project is so big that refactoring everything would take ages. This plugin allows user to simply put `//@ts-strict` comment to a top of a file and turn a strict mode to that file. If needed, strict mode can be turned on to directories too.
7+
8+
## How to install
9+
10+
Use `npm`:
11+
```bash
12+
npm i --save-dev typescript-strict-plugin
13+
```
14+
or yarn
15+
```bash
16+
yarn add -D typescript-strict-plugin
17+
```
18+
and add plugin to your `tsconfig.json`:
19+
```json
20+
{
21+
"compilerOptions": {
22+
...
23+
"strict": false,
24+
"plugins": [
25+
{
26+
"name": "typescript-strict-plugin"
27+
}
28+
]
29+
}
30+
}
31+
```
32+
That's it! You should be able to use `@ts-strict` comment to strictly check your files.
33+
34+
## Configuration
35+
Plugin takes one extra non mandatory argument `paths` that is an array of relative or absolute paths of directories that should be included.
36+
```json
37+
{
38+
"compilerOptions": {
39+
...
40+
"strict": false,
41+
"plugins": [
42+
{
43+
"name": "typescript-strict-plugin",
44+
"paths": [
45+
"./src",
46+
"/absolute/path/to/source/"
47+
]
48+
}
49+
]
50+
}
51+
}
52+
```
53+
All files contained in those paths will be be strictly checked. Yay!
54+
55+
## Examples
56+
Let's consider this type and a variable
57+
```typescript
58+
interface TestType {
59+
bar: string;
60+
}
61+
62+
const foo: TestType | undefined = undefined;
63+
```
64+
1. No `paths` argument
65+
With `tsconfig.json` like this:
66+
```json
67+
{
68+
"compilerOptions": {
69+
...
70+
"strict": false,
71+
"plugins": [
72+
{
73+
"name": "typescript-strict-plugin"
74+
}
75+
]
76+
}
77+
}
78+
```
79+
Typescript will produce errors:
80+
```typescript
81+
//@ts-strict
82+
...
83+
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
84+
```
85+
Or not, depending on whether we used `ts-strict` or not:
86+
```typescript
87+
//no strict comment here
88+
...
89+
const boo = foo.bar; // no error here
90+
```
91+
92+
2. With `paths` argument
93+
With `tsconfig.json` like this:
94+
```json
95+
{
96+
"compilerOptions": {
97+
...
98+
"strict": false,
99+
"plugins": [
100+
{
101+
"name": "typescript-strict-plugin",
102+
"path": "./src"
103+
}
104+
]
105+
}
106+
}
107+
```
108+
If file is in the directory typescript will produce errors even if `ts-strict` comment is not in the file :
109+
```typescript
110+
// ./src/index.ts
111+
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
112+
```
113+
If file is not in the diretory there will be no error
114+
```typescript
115+
// ./lib/index.ts
116+
const boo = foo.bar; // no error here
117+
```
118+
If file is not in the diretory but there is `ts-strict` file will be check with strict mode:
119+
```typescript
120+
// ./lib/index.ts
121+
//@ts-strict
122+
...
123+
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
124+
```
125+
126+
## Testing the plugin
127+
### Manually
128+
run
129+
```bash
130+
npm i
131+
```
132+
inside root folder and `sample-project` folder and then run
133+
```bash
134+
npm run build
135+
```
136+
or
137+
```bash
138+
npm run dev
139+
```
140+
and restart typescript service inside `sample-project`. Files in `sample-project` folder should use a local plugin.
141+
After you made changes to a plugin you should probably restart typescript service in order to reload the plugin.
142+
143+
### E2E tests
144+
In order to run e2e tests run
145+
146+
```bash
147+
npm run build && npm run e2e
148+
```
149+
150+
## Contributing
151+
Feel free to create PR's and issues.

e2e/fixtures/lang-server.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* implementation taken from https://github.com/Quramy/ts-graphql-plugin/blob/master/e2e/fixtures/lang-server.js */
2+
const { fork } = require('child_process');
3+
const path = require('path');
4+
const { EventEmitter } = require('events');
5+
6+
class TSServer {
7+
constructor() {
8+
this._responseEventEmitter = new EventEmitter();
9+
this._responseCommandEmitter = new EventEmitter();
10+
const tsserverPath = require.resolve('typescript/lib/tsserver');
11+
12+
// to create ts log from tests
13+
// process.env['TSS_LOG'] = '-logToFile true -file /path/typescript-strict-plugin/log1.txt -level verbose';
14+
const server = fork(tsserverPath, {
15+
cwd: path.join(__dirname, '../project-fixture/src'),
16+
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
17+
});
18+
this._exitPromise = new Promise((resolve, reject) => {
19+
server.on('exit', (code) => resolve(code));
20+
server.on('error', (reason) => reject(reason));
21+
});
22+
server.stdout.setEncoding('utf-8');
23+
server.stdout.on('data', (data) => {
24+
const [, , res] = data.split('\n');
25+
const obj = JSON.parse(res);
26+
if (obj.type === 'event') {
27+
this._responseEventEmitter.emit(obj.event, obj);
28+
} else if (obj.type === 'response') {
29+
this._responseCommandEmitter.emit(obj.command, obj);
30+
}
31+
this.responses.push(obj);
32+
});
33+
this._isClosed = false;
34+
this._server = server;
35+
this._seq = 0;
36+
this.responses = [];
37+
}
38+
39+
send(command) {
40+
const seq = ++this._seq;
41+
const req = JSON.stringify(Object.assign({ seq: seq, type: 'request' }, command)) + '\n';
42+
this._server.stdin.write(req);
43+
}
44+
45+
close() {
46+
if (!this._isClosed) {
47+
this._isClosed = true;
48+
this._server.stdin.end();
49+
}
50+
return this._exitPromise;
51+
}
52+
53+
waitEvent(eventName) {
54+
return new Promise((res) => this._responseEventEmitter.once(eventName, () => res()));
55+
}
56+
}
57+
58+
function createServer() {
59+
return new TSServer();
60+
}
61+
62+
module.exports = createServer;

e2e/it.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const assert = require('assert');
2+
const path = require('path');
3+
4+
function findResponse(responses, eventName) {
5+
return responses.find((response) => response.event === eventName);
6+
}
7+
8+
async function it(fileName, server, fileContent, assertionCallback) {
9+
const file = path.resolve(__dirname, './project-fixture/' + fileName);
10+
11+
server.send({ command: 'open', arguments: { file, fileContent, scriptKindName: 'TS' } });
12+
13+
await server.waitEvent('projectLoadingFinish');
14+
15+
server.send({ command: 'geterr', arguments: { files: [file], delay: 0 } });
16+
17+
await server.waitEvent('semanticDiag');
18+
19+
return server.close().then(() => {
20+
const semanticDiagEvent = findResponse(server.responses, 'semanticDiag');
21+
assert(!!semanticDiagEvent);
22+
assertionCallback(semanticDiagEvent.body.diagnostics);
23+
});
24+
}
25+
26+
module.exports = it;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"typescript.tsdk": "node_modules/typescript/lib"
3+
}

e2e/project-fixture/lib/onPath.ts

Whitespace-only changes.

e2e/project-fixture/src/notOnPath.ts

Whitespace-only changes.

e2e/project-fixture/tsconfig.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2018",
4+
"module": "commonjs",
5+
"lib": ["es2018"],
6+
"baseUrl": "./",
7+
"outDir": "./dist",
8+
"strict": false,
9+
"esModuleInterop": true,
10+
"noImplicitAny": true,
11+
"plugins": [
12+
{
13+
"name": "../../dist",
14+
"paths": [
15+
"./lib"
16+
]
17+
}
18+
]
19+
}
20+
}

0 commit comments

Comments
 (0)