Skip to content

Commit 0c2cc8b

Browse files
Merge pull request #4 from allegro/feature/compile-time-tsstrict-checking
Feature/compile time tsstrict checking
2 parents dab452b + 2f524b8 commit 0c2cc8b

35 files changed

+11955
-1172
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
66
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.0] - 2021-06-15
9+
10+
### Added
11+
12+
- Adds cli tool to check strict files during build time
13+
814
## [1.0.1] - 2021-06-01
915

1016
### Fixed

README.md

+25-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ Typescript plugin that allows turning on strict mode in specific files or direct
44

55
## Do i need this plugin?
66
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-
NOTE: this plugin doesn't work in compile time. It will show errors in your IDE but they won't appear during compilation.
7+
Plugins in general doesn't work in compile time. They will show errors in your IDE but they won't appear during compilation.
8+
To check strict errors in marked files you can use our script `tsc-strict`.
9+
This command line tool is created to check for files that should be checked with strict rules in compilation time.
10+
It finds all files with `//@ts-strict` comment and files specified in `paths` parameter and checks for strict typescript errors only for that files.
11+
Therefore, we have strict errors inside our files and during build time.
12+
813

914
## How to install
1015

@@ -33,7 +38,7 @@ and add plugin to your `tsconfig.json`:
3338
That's it! You should be able to use `@ts-strict` comment to strictly check your files.
3439

3540
## Configuration
36-
Plugin takes one extra non mandatory argument `paths` that is an array of relative or absolute paths of directories that should be included.
41+
Plugin takes one extra non-mandatory argument `paths` that is an array of relative or absolute paths of directories that should be included.
3742
```json
3843
{
3944
"compilerOptions": {
@@ -51,7 +56,24 @@ Plugin takes one extra non mandatory argument `paths` that is an array of relati
5156
}
5257
}
5358
```
54-
All files contained in those paths will be be strictly checked. Yay!
59+
All files contained in those paths will be strictly checked. Yay!
60+
61+
To add cli tool to your build time you can add a script to scripts list in package.json
62+
```json
63+
{
64+
"scripts": {
65+
...,
66+
"typecheck": "tsc && tsc-strict",
67+
},
68+
}
69+
```
70+
71+
Then you can simply run
72+
```shell
73+
yarn tsc-strict
74+
```
75+
76+
All your strict files should be checked from command line.
5577

5678
## Examples
5779
Let's consider this type and a variable

babel.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
3+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import execa from 'execa';
2+
import { join } from 'path';
3+
4+
const runInPath = async (path: string): Promise<string> => {
5+
const cwd = process.cwd();
6+
const cli = join(cwd, 'dist/compile-time-tool/cli.js');
7+
8+
process.chdir(path);
9+
return execa('node', [cli], {
10+
env: {
11+
//the assertions break in an environment that supports color
12+
//override chalk color detection https://github.com/chalk/supports-color/blob/master/index.js
13+
FORCE_COLOR: 'false',
14+
},
15+
})
16+
.then((response) => {
17+
console.log('Response', response);
18+
return response.stdout;
19+
})
20+
.catch((error) => error.stdout)
21+
.finally(() => process.chdir(cwd));
22+
};
23+
24+
test('files are detected correctly', async () => {
25+
jest.setTimeout(20000);
26+
const path = process.cwd() + '/e2e/compile-time-tool-tests/repository';
27+
28+
await runInPath(path).then((stdout) => {
29+
expect(stdout).toMatch(/notOnPath.ts/);
30+
expect(stdout).toMatch(/onPath.ts/);
31+
expect(stdout).toMatch(/TS2532: Object is possibly 'undefined'/);
32+
expect(stdout).toMatch(/Found 2 strict files/);
33+
expect(stdout).toMatch(/2 errors found/);
34+
});
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface TestType {
2+
bar: string;
3+
}
4+
5+
const foo: TestType | undefined = undefined;
6+
7+
const boo = foo.bar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@ts-strict
2+
interface TestType {
3+
bar: string;
4+
}
5+
6+
const foo1: TestType | undefined = undefined;
7+
8+
const boo1 = foo.bar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es5",
4+
"module": "commonjs",
5+
"plugins": [
6+
{
7+
"name": "typescript-strict-plugin",
8+
"paths": ["./lib"]
9+
}
10+
]
11+
}
12+
}

e2e/fixtures/lang-server.js renamed to e2e/plugin-tests/fixtures/lang-server.ts

+32-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,30 @@ const { fork } = require('child_process');
33
const path = require('path');
44
const { EventEmitter } = require('events');
55

6-
class TSServer {
6+
export interface ServerResponse {
7+
command: string;
8+
event: string;
9+
type: string;
10+
body: any;
11+
}
12+
13+
export interface ServerRequest {
14+
command?: string;
15+
event?: string;
16+
type?: string;
17+
arguments: any;
18+
}
19+
20+
export class TSServer {
21+
public responses: ServerResponse[];
22+
23+
private _responseEventEmitter: NodeJS.EventEmitter;
24+
private _responseCommandEmitter: NodeJS.EventEmitter;
25+
private _exitPromise: Promise<string>;
26+
private _isClosed: boolean;
27+
private _server: any;
28+
private _seq: number;
29+
730
constructor() {
831
this._responseEventEmitter = new EventEmitter();
932
this._responseCommandEmitter = new EventEmitter();
@@ -16,13 +39,13 @@ class TSServer {
1639
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
1740
});
1841
this._exitPromise = new Promise((resolve, reject) => {
19-
server.on('exit', (code) => resolve(code));
20-
server.on('error', (reason) => reject(reason));
42+
server.on('exit', (code: string) => resolve(code));
43+
server.on('error', (reason: string) => reject(reason));
2144
});
2245
server.stdout.setEncoding('utf-8');
23-
server.stdout.on('data', (data) => {
46+
server.stdout.on('data', (data: string) => {
2447
const [, , res] = data.split('\n');
25-
const obj = JSON.parse(res);
48+
const obj = JSON.parse(res) as ServerResponse;
2649
if (obj.type === 'event') {
2750
this._responseEventEmitter.emit(obj.event, obj);
2851
} else if (obj.type === 'response') {
@@ -36,7 +59,7 @@ class TSServer {
3659
this.responses = [];
3760
}
3861

39-
send(command) {
62+
send(command: ServerRequest) {
4063
const seq = ++this._seq;
4164
const req = JSON.stringify(Object.assign({ seq: seq, type: 'request' }, command)) + '\n';
4265
this._server.stdin.write(req);
@@ -50,13 +73,13 @@ class TSServer {
5073
return this._exitPromise;
5174
}
5275

53-
waitEvent(eventName) {
54-
return new Promise((res) => this._responseEventEmitter.once(eventName, () => res()));
76+
waitEvent(eventName: string) {
77+
return new Promise((res) => this._responseEventEmitter.once(eventName, () => res(undefined)));
5578
}
5679
}
5780

5881
function createServer() {
5982
return new TSServer();
6083
}
6184

62-
module.exports = createServer;
85+
module.exports = { createServer };

e2e/it.js renamed to e2e/plugin-tests/it.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
import { ServerResponse, TSServer } from './fixtures/lang-server';
2+
13
const assert = require('assert');
24
const path = require('path');
35

4-
function findResponse(responses, eventName) {
6+
function findResponse(responses: ServerResponse[], eventName: string) {
57
return responses.find((response) => response.event === eventName);
68
}
79

8-
async function it(fileName, server, fileContent, assertionCallback) {
10+
async function it(
11+
fileName: string,
12+
server: TSServer,
13+
fileContent: string,
14+
assertionCallback: (args: any[]) => void,
15+
) {
916
const file = path.resolve(__dirname, './project-fixture/' + fileName);
1017

1118
server.send({ command: 'open', arguments: { file, fileContent, scriptKindName: 'TS' } });
@@ -19,7 +26,7 @@ async function it(fileName, server, fileContent, assertionCallback) {
1926
return server.close().then(() => {
2027
const semanticDiagEvent = findResponse(server.responses, 'semanticDiag');
2128
assert(!!semanticDiagEvent);
22-
assertionCallback(semanticDiagEvent.body.diagnostics);
29+
assertionCallback(semanticDiagEvent?.body.diagnostics);
2330
});
2431
}
2532

e2e/project-fixture/tsconfig.json renamed to e2e/plugin-tests/project-fixture/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"noImplicitAny": true,
1111
"plugins": [
1212
{
13-
"name": "../../dist",
13+
"name": "../../dist/plugin",
1414
"paths": [
1515
"./lib"
1616
]

e2e/run.js renamed to e2e/plugin-tests/run.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import { TSServer } from './fixtures/lang-server';
2+
13
const path = require('path');
24
const glob = require('glob');
3-
const createServer = require('./fixtures/lang-server');
5+
const { createServer } = require('./fixtures/lang-server');
46

57
async function runLangServerSpecs() {
6-
const langServerSpecFiles = glob.sync('tests/*.js', { cwd: __dirname });
8+
const langServerSpecFiles = glob.sync('tests/*.ts', { cwd: __dirname });
79
console.log('Start lang server e2e testing.');
8-
let server;
10+
let server: TSServer;
911
await langServerSpecFiles.reduce(
10-
(queue, file) =>
12+
(queue: Promise<void>, file: string) =>
1113
queue.then(() =>
1214
require(path.join(__dirname, file))((server = createServer())).then(() => server.close()),
1315
),

e2e/tests/fileWithTsStrictNotOnPath.js renamed to e2e/plugin-tests/tests/fileWithTsStrictNotOnPath.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TSServer } from '../fixtures/lang-server';
2+
13
const assert = require('assert');
24
const it = require('../it');
35

@@ -12,8 +14,8 @@ const foo: TestType | undefined = undefined;
1214
const boo = foo.bar;
1315
`;
1416

15-
async function run(server) {
16-
await it('src/notOnPath.ts', server, fileContent, (diagnostics) => {
17+
async function run(server: TSServer) {
18+
await it('src/notOnPath.ts', server, fileContent, (diagnostics: any[]) => {
1719
assert.strictEqual(diagnostics.length, 1);
1820
assert.strictEqual(diagnostics[0].text, "Object is possibly 'undefined'.");
1921
});

e2e/tests/fileWithTsStrictOnPath.js renamed to e2e/plugin-tests/tests/fileWithTsStrictOnPath.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TSServer } from '../fixtures/lang-server';
2+
13
const assert = require('assert');
24
const it = require('../it');
35

@@ -12,8 +14,8 @@ const foo: TestType | undefined = undefined;
1214
const boo = foo.bar;
1315
`;
1416

15-
async function run(server) {
16-
await it('lib/onPath.ts', server, fileContent, (diagnostics) => {
17+
async function run(server: TSServer) {
18+
await it('lib/onPath.ts', server, fileContent, (diagnostics: any[]) => {
1719
assert.strictEqual(diagnostics.length, 1);
1820
assert.strictEqual(diagnostics[0].text, "Object is possibly 'undefined'.");
1921
});

e2e/tests/fileWithoutTsStrictNotOnPath.js renamed to e2e/plugin-tests/tests/fileWithoutTsStrictNotOnPath.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TSServer } from '../fixtures/lang-server';
2+
13
const assert = require('assert');
24
const it = require('../it');
35

@@ -11,8 +13,8 @@ const foo: TestType | undefined = undefined;
1113
const boo = foo.bar;
1214
`;
1315

14-
async function run(server) {
15-
await it('src/notOnPath.ts', server, fileContent, (diagnostics) => {
16+
async function run(server: TSServer) {
17+
await it('src/notOnPath.ts', server, fileContent, (diagnostics: any[]) => {
1618
assert.strictEqual(diagnostics.length, 0);
1719
});
1820
}

e2e/tests/fileWithoutTsStrictOnPath.js renamed to e2e/plugin-tests/tests/fileWithoutTsStrictOnPath.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TSServer } from '../fixtures/lang-server';
2+
13
const assert = require('assert');
24
const it = require('../it');
35

@@ -11,8 +13,8 @@ const foo: TestType | undefined = undefined;
1113
const boo = foo.bar;
1214
`;
1315

14-
async function run(server) {
15-
await it('lib/onPath.ts', server, fileContent, (diagnostics) => {
16+
async function run(server: TSServer) {
17+
await it('lib/onPath.ts', server, fileContent, (diagnostics: any[]) => {
1618
assert.strictEqual(diagnostics.length, 1);
1719
assert.strictEqual(diagnostics[0].text, "Object is possibly 'undefined'.");
1820
});

e2e/tests/twoFilesCheckedAtTheSameTime.js renamed to e2e/plugin-tests/tests/twoFilesCheckedAtTheSameTime.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { ServerResponse, TSServer } from '../fixtures/lang-server';
2+
13
const assert = require('assert');
24
const path = require('path');
3-
const it = require('../it');
45

56
const fileContent = `
67
//@ts-strict
@@ -19,11 +20,11 @@ const foo1: TestType | undefined = undefined;
1920
const boo1 = foo1.bar;
2021
`;
2122

22-
function findResponse(responses, eventName) {
23+
function findResponse(responses: ServerResponse[], eventName: string) {
2324
return responses.filter((response) => response.event === eventName);
2425
}
2526

26-
async function run(server) {
27+
async function run(server: TSServer) {
2728
const rootPath = path.resolve(__dirname, '../project-fixture/');
2829
const file = path.resolve(__dirname, '../project-fixture/' + 'src/notOnPath.ts');
2930
const otherFile = path.resolve(__dirname, '../project-fixture/' + 'src/otherFileNotOnPath.ts');

0 commit comments

Comments
 (0)