Skip to content

Commit 8ed4e01

Browse files
kamkryKamil Krysiak
and
Kamil Krysiak
authored
(v2.0) Strict mode by default (#19)
* tests-jest | Converts tests to jest * tests-jest | Type fixes * tests-jest | Fixes cli test * ts-strict | Adds file ignoring with @ts-strict-ignore comment * ts-strict | Adds insert ignore comment functionality * ts-strict | Unifies cli and plugin logic * ts-strict | Adds file updating * ts-strict | Unifies function declarations * ts-strict | 2.0 init * ts-strict | Readme update 1.0 * ts-strict | Readme update migration part * ts-strict | Updated user messages * ts-strict | Fixes test variable names * ts-strict | Fixes type error * ts-strict | Updates changelog * ts-strict | Removes updateComments tests for now * Refactor * Bugfixes * comments refactor * Adds pluralization and cli unit tests * Adds process exit expects to tsc-strict root files * Fixes failing tests * e2e fixture refactor * typo fixes * typo fixes * cli structure refactor * final test addition * Fixes e2e test name * fixes bin scripts paths Co-authored-by: Kamil Krysiak <[email protected]>
1 parent 268d9f0 commit 8ed4e01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+5539
-17352
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
22
dist
3+
.idea

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ 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+
## [2.0.0] - 2021-29-11
9+
10+
### Changed
11+
- Strict by default without `@ts-strict` comment
12+
- Ignores file with `@ts-strict-ignore` comment
13+
- Migration tool `update-strict-comments` which updates comments in files which contain at least 1 strict error
14+
815
## [1.1.2] - 2021-06-15
916

1017
### Added

README.md

+20-77
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
Typescript plugin that allows turning on strict mode in specific files or directories.
44

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-
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.
5+
## Do I need this plugin?
6+
`typescript-strict-plugin` was created mainly for existing projects that want to incorporate typescript strict mode, but project is so big that refactoring everything would take ages.
7+
8+
9+
Our plugin allows adding strict mode to a TypeScript project without fixing all the errors at once. By adding `//@ts-strict-ignore` comment at the top of a file, its whole content will be removed from strict type checking. To ease migrating a project to use this plugin, you can use `tsc-strict --updateComment` script, which adds the ignore comment to all files that contain at least one strict error.
10+
11+
12+
TypeScript plugins don't work at compile-time. They will show errors in your IDE, but they won't appear during compilation.
13+
To check strict errors in marked files you can use `tsc-strict` script. This command line tool is created to check for files that should be checked with strict rules in compilation time.
14+
It finds all relevant files and checks for strict typescript errors only for that files.
1115
Therefore, we have strict errors inside our files and during build time.
1216

1317

@@ -21,7 +25,7 @@ or yarn
2125
```bash
2226
yarn add -D typescript-strict-plugin
2327
```
24-
and add plugin to your `tsconfig.json`:
28+
add plugin to your `tsconfig.json`:
2529
```json
2630
{
2731
"compilerOptions": {
@@ -35,10 +39,14 @@ and add plugin to your `tsconfig.json`:
3539
}
3640
}
3741
```
38-
That's it! You should be able to use `@ts-strict` comment to strictly check your files.
42+
and run the migration script
43+
```
44+
tsc-strict --updateComments
45+
```
46+
That's it! You should be able to see strict typechecking in files without the `@ts-strict-ignore` comment. To make these files strict too, just remove its' ignore comments.
3947

4048
## Configuration
41-
Plugin takes one extra non-mandatory argument `paths` that is an array of relative or absolute paths of directories that should be included.
49+
Plugin takes one extra non-mandatory argument `paths` that is an array of relative or absolute paths of directories that should be included. To add strict mode to files from ignored paths you can insert `//@ts-strict` comment.
4250
```json
4351
{
4452
"compilerOptions": {
@@ -82,75 +90,10 @@ yarn tsc-strict --strictNullChecks false
8290
would not check for the strict null check in your files. The `tsc-strict` accepts all the arguments that regular `tsc` command
8391
accepts.
8492

85-
## Examples
86-
Let's consider this type and a variable
87-
```typescript
88-
interface TestType {
89-
bar: string;
90-
}
91-
92-
const foo: TestType | undefined = undefined;
93-
```
94-
1. No `paths` argument
95-
With `tsconfig.json` like this:
96-
```json
97-
{
98-
"compilerOptions": {
99-
...
100-
"strict": false,
101-
"plugins": [
102-
{
103-
"name": "typescript-strict-plugin"
104-
}
105-
]
106-
}
107-
}
108-
```
109-
Typescript will produce errors:
110-
```typescript
111-
//@ts-strict
112-
...
113-
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
114-
```
115-
Or not, depending on whether we used `ts-strict` or not:
116-
```typescript
117-
//no strict comment here
118-
...
119-
const boo = foo.bar; // no error here
120-
```
121-
122-
2. With `paths` argument
123-
With `tsconfig.json` like this:
124-
```json
125-
{
126-
"compilerOptions": {
127-
...
128-
"strict": false,
129-
"plugins": [
130-
{
131-
"name": "typescript-strict-plugin",
132-
"path": "./src"
133-
}
134-
]
135-
}
136-
}
137-
```
138-
If file is in the directory typescript will produce errors even if `ts-strict` comment is not in the file :
139-
```typescript
140-
// ./src/index.ts
141-
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
142-
```
143-
If file is not in the diretory there will be no error
144-
```typescript
145-
// ./lib/index.ts
146-
const boo = foo.bar; // no error here
93+
## Migrating to v2
94+
Because of difficulties with migrating large projects to strict mode with original `//@ts-strict` comment, we've taken an another approach. Now in version 2.0+ typescript files are strict by default, and to ignore a file, you can use special `//@ts-strict-ignore` comment. It allows to have strict mode in newly created files without remembering about adding strict comment at the top of it. With version 2.0 script `tsc-strict` comes with a new flag, which detects all files with at least one strict error and adds the ignore comment to ease the migration. To update from v1 to v2, you just need to run:
14795
```
148-
If file is not in the diretory but there is `ts-strict` file will be check with strict mode:
149-
```typescript
150-
// ./lib/index.ts
151-
//@ts-strict
152-
...
153-
const boo = foo.bar; // TS2532: Object is possibly 'undefined'.
96+
tsc-strict --updateComments
15497
```
15598

15699
## Testing the plugin
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @ts-strict-ignore
2+
const text: string = null;
3+
4+
export {};

e2e/fixtures/default-config/strict.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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/plugin"
14+
}
15+
]
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"typescript.tsdk": "node_modules/typescript/lib"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @ts-strict
2+
const text: string = null;
3+
4+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};

e2e/fixtures/paths.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import path from 'path';
2+
3+
export const fixtureWithDefaultConfig = {
4+
projectPath: path.resolve(__dirname, 'default-config'),
5+
filePaths: {
6+
strict: 'strict.ts',
7+
ignored: 'ignored.ts',
8+
},
9+
};
10+
11+
export const fixtureWithPathConfig = {
12+
projectPath: path.resolve(__dirname, 'path-config'),
13+
filePaths: {
14+
included: 'included/included.ts',
15+
included2: 'included/included2.ts',
16+
excluded: 'excluded/excluded.ts',
17+
excluded2: 'excluded/excluded2.ts',
18+
excludedWithStrictComment: 'excluded/excludedWithStrictComment.ts',
19+
},
20+
};

e2e/plugin/multipleFile.spec.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { getMultipleDiagnostics } from './utils/getMultipleDiagnostics';
2+
import { fixtureWithDefaultConfig } from '../fixtures/paths';
3+
4+
it('should show errors only on file with strict comment', async () => {
5+
// given
6+
const { projectPath, filePaths } = fixtureWithDefaultConfig;
7+
const fileList = [filePaths.strict, filePaths.ignored];
8+
9+
// when
10+
const diagnostics = await getMultipleDiagnostics(projectPath, fileList);
11+
12+
// then
13+
expect(diagnostics[0]).toHaveLength(1);
14+
expect(diagnostics[1]).toHaveLength(0);
15+
});

e2e/plugin/singleFile.spec.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { getDiagnostics } from './utils/getDiagnostics';
2+
import { fixtureWithDefaultConfig, fixtureWithPathConfig } from '../fixtures/paths';
3+
4+
describe('single file diagnostics', () => {
5+
it('should enable strict mode by default in project without config', async () => {
6+
// given
7+
const { projectPath, filePaths } = fixtureWithDefaultConfig;
8+
9+
// when
10+
const diagnostics = await getDiagnostics(projectPath, filePaths.strict);
11+
12+
// then
13+
expect(diagnostics).toHaveLength(1);
14+
});
15+
16+
it('should not enable strict mode in ignored file', async () => {
17+
// given
18+
const { projectPath, filePaths } = fixtureWithDefaultConfig;
19+
20+
// when
21+
const diagnostics = await getDiagnostics(projectPath, filePaths.ignored);
22+
23+
// then
24+
expect(diagnostics).toHaveLength(0);
25+
});
26+
27+
it('should not enable strict mode when file is not on path', async () => {
28+
// given
29+
const { projectPath, filePaths } = fixtureWithPathConfig;
30+
31+
// when
32+
const diagnostics = await getDiagnostics(projectPath, filePaths.excluded);
33+
34+
// then
35+
expect(diagnostics).toHaveLength(0);
36+
});
37+
38+
it('should enable strict mode when file is not on path and contains strict comment', async () => {
39+
// given
40+
const { projectPath, filePaths } = fixtureWithPathConfig;
41+
42+
// when
43+
const diagnostics = await getDiagnostics(projectPath, filePaths.excludedWithStrictComment);
44+
45+
// then
46+
expect(diagnostics).toHaveLength(1);
47+
});
48+
});

test/plugin/fixtures/lang-server.ts e2e/plugin/utils/TSServer.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@ export class TSServer {
3232
this._responseCommandEmitter = new EventEmitter();
3333
const tsserverPath = require.resolve('typescript/lib/tsserver');
3434

35-
// to create ts log from tests
36-
// process.env['TSS_LOG'] = '-logToFile true -file /path/typescript-strict-plugin/log1.txt -level verbose';
3735
const server = fork(tsserverPath, {
38-
cwd: join(__dirname, '../project-fixture/src'),
3936
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
37+
// env: { TSS_LOG: '-logToFile true -file ./ts.log -level verbose' }, // creates tsserver log from tests
4038
});
4139
this._exitPromise = new Promise((resolve, reject) => {
4240
server.on('exit', (code: string) => resolve(code));

test/plugin/getDiagnostics.ts e2e/plugin/utils/getDiagnostics.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { ServerResponse, TSServer } from './fixtures/lang-server';
2-
import path from 'path';
1+
import { ServerResponse, TSServer } from './TSServer';
2+
import path, { resolve } from 'path';
3+
import { readFileSync } from 'fs';
34

45
function findResponse(responses: ServerResponse[], eventName: string) {
56
return responses.find((response) => response.event === eventName);
67
}
78

8-
export async function getDiagnostics(fileContent: string, fileName = 'src/notOnPath.ts') {
9+
export async function getDiagnostics(projectPath: string, filePath: string) {
910
const server = new TSServer();
1011

11-
const file = path.resolve(__dirname, 'project-fixture', fileName);
12+
const file = resolve(projectPath, filePath);
13+
14+
const fileContent = readFileSync(file, 'utf-8');
1215

1316
server.send({ command: 'open', arguments: { file, fileContent, scriptKindName: 'TS' } });
1417

@@ -21,5 +24,6 @@ export async function getDiagnostics(fileContent: string, fileName = 'src/notOnP
2124
await server.close();
2225

2326
const semanticDiagEvent = findResponse(server.responses, 'semanticDiag');
27+
2428
return semanticDiagEvent?.body.diagnostics;
2529
}

test/plugin/getMultipleDiagnostics.ts e2e/plugin/utils/getMultipleDiagnostics.ts

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
1-
import { ServerResponse, TSServer } from './fixtures/lang-server';
1+
import { ServerResponse, TSServer } from './TSServer';
22
import path from 'path';
3-
4-
interface FileInfo {
5-
fileContent: string;
6-
fileName: string;
7-
}
3+
import * as fs from 'fs';
84

95
function findResponses(responses: ServerResponse[], eventName: string) {
106
return responses.filter((response) => response.event === eventName);
117
}
128

13-
export async function getMultipleDiagnostics(fileInfoList: FileInfo[], rootPath: string) {
9+
export async function getMultipleDiagnostics(projectPath: string, filePaths: string[]) {
1410
const server = new TSServer();
1511

16-
const openFiles = fileInfoList.map((fileInfo) => ({
17-
file: path.resolve(rootPath, fileInfo.fileName),
18-
fileContent: fileInfo.fileContent,
19-
projectRootPath: rootPath,
20-
scriptKindName: 'TS',
21-
}));
12+
const openFiles = filePaths.map((filePath) => {
13+
const file = path.resolve(projectPath, filePath);
14+
return {
15+
file,
16+
fileContent: fs.readFileSync(file, 'utf-8'),
17+
projectRootPath: projectPath,
18+
scriptKindName: 'TS',
19+
};
20+
});
2221

2322
const openFilePaths = openFiles.map((file) => file.file);
2423

0 commit comments

Comments
 (0)