Skip to content

Commit a8ef90e

Browse files
committed
only check / annotate plugin-enabled files
1 parent 0361d48 commit a8ef90e

15 files changed

Lines changed: 334 additions & 172 deletions

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ts-migrating",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Progressively Upgrade `tsconfigs.json`",
55
"author": "Jason Yu <me@ycmjason.com>",
66
"license": "MIT",
@@ -41,13 +41,14 @@
4141
"biome.config.json"
4242
],
4343
"scripts": {
44-
"test": "vitest run",
4544
"build": "tsup src/cli/main.ts src/api/mod.ts src/plugin/mod.ts --sourcemap --format esm,cjs --clean --cjsInterop --splitting",
4645
"build:watch": "pnpm build --watch",
4746
"check": "pnpm check:lint && pnpm check:type && pnpm test",
48-
"check:type": "tsc",
4947
"check:lint": "biome check .",
50-
"check:lint:fix": "pnpm check:lint --write"
48+
"check:lint:fix": "pnpm check:lint --write",
49+
"check:type": "tsc",
50+
"test": "vitest run",
51+
"test:watch": "vitest"
5152
},
5253
"devDependencies": {
5354
"@biomejs/biome": "^1.9.4",

src/api/getSemanticDiagnostics.test.ts

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -163,48 +163,88 @@ enum FRUITS {
163163
`);
164164
});
165165

166-
it('should ignore ts files without any tsconfig that includes them', async () => {
167-
const tmpDir = await setupTmpDir({
168-
'./tsconfig.json': JSON.stringify({
169-
compilerOptions: {
170-
target: 'ES2020',
171-
module: 'commonjs',
172-
outDir: './dist',
173-
rootDir: './src',
174-
strict: false,
175-
esModuleInterop: true,
176-
forceConsistentCasingInFileNames: true,
177-
plugins: [
178-
{
179-
// ts will look up from the node_modules that the ts server is running from. e.g. ../../node_modules/ts-migrating
180-
// this is why we add `ts-migrating` as dev dependency of itself.
181-
name: 'ts-migrating',
182-
compilerOptions: {
183-
erasableSyntaxOnly: true,
166+
describe('ignoring files', () => {
167+
it('should ignore ts files without any tsconfig that includes them', async () => {
168+
const tmpDir = await setupTmpDir({
169+
'./tsconfig.json': JSON.stringify({
170+
compilerOptions: {
171+
target: 'ES2020',
172+
module: 'commonjs',
173+
outDir: './dist',
174+
rootDir: './src',
175+
strict: false,
176+
esModuleInterop: true,
177+
forceConsistentCasingInFileNames: true,
178+
plugins: [
179+
{
180+
// ts will look up from the node_modules that the ts server is running from. e.g. ../../node_modules/ts-migrating
181+
// this is why we add `ts-migrating` as dev dependency of itself.
182+
name: 'ts-migrating',
183+
compilerOptions: {
184+
erasableSyntaxOnly: true,
185+
},
184186
},
185-
},
187+
],
188+
skipLibCheck: true,
189+
},
190+
include: ['.'],
191+
exclude: [
192+
'node_modules',
193+
'dist',
194+
// excluding `ignored` directory!!!
195+
'ignored',
186196
],
187-
skipLibCheck: true,
188-
},
189-
include: ['.'],
190-
exclude: [
191-
'node_modules',
192-
'dist',
193-
// excluding `ignored` directory!!!
194-
'ignored',
195-
],
196-
}),
197-
'./src/index.ts': `// @ts-migrating
197+
}),
198+
'./src/index.ts': `// @ts-migrating
198199
enum FRUITS {
199200
APPLE,
200201
BANANA,
201202
// @ts-migrating
202203
KIWI,
203204
}
204205
`,
205-
'./ignored/index.ts': 'laksdjflkj oiwejflaskdjf',
206+
'./ignored/index.ts': 'laksdjflkj oiwejflaskdjf',
207+
});
208+
209+
const diagnostics = getSemanticDiagnosticsForFile(join(tmpDir, 'ignored/index.ts'));
210+
expect(diagnostics).toHaveLength(0);
206211
});
207212

208-
const diagnostics = getSemanticDiagnosticsForFile(join(tmpDir, 'ignored/index.ts'));
209-
expect(diagnostics).toHaveLength(0);
213+
it('should ignore projects without `ts-migrating` plugin', async () => {
214+
const tmpDir = await setupTmpDir({
215+
'./tsconfig.json': JSON.stringify({
216+
compilerOptions: {
217+
target: 'ES2020',
218+
module: 'commonjs',
219+
outDir: './dist',
220+
rootDir: './src',
221+
strict: false,
222+
esModuleInterop: true,
223+
forceConsistentCasingInFileNames: true,
224+
plugins: [
225+
// no plugin!
226+
],
227+
skipLibCheck: true,
228+
},
229+
include: ['.'],
230+
exclude: [
231+
'node_modules',
232+
'dist',
233+
// excluding `ignored` directory!!!
234+
'ignored',
235+
],
236+
}),
237+
'./src/index.ts': `// @ts-migrating
238+
enum FRUITS {
239+
APPLE,
240+
BANANA,
241+
// @ts-migrating
242+
KIWI,
243+
}
244+
`,
245+
});
246+
247+
const diagnostics = getSemanticDiagnosticsForFile(join(tmpDir, 'src/index.ts'));
248+
expect(diagnostics).toHaveLength(0);
249+
});
210250
});

src/api/getSemanticDiagnostics.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import path from 'node:path';
22
import ts from 'typescript/lib/tsserverlibrary';
3-
import { createProjectService } from './typescript/createProjectService';
3+
import { isPluginEnabled } from './getTSInfoForFile';
4+
import { projectService } from './typescript/projectService';
45

5-
const PROJECT_KIND_CONFIGURED = 1;
6-
const projectService = createProjectService();
76
/**
8-
* Returns the {@link Diagnostic} of a given file. This function only check for files that has a tsconfig that includes them.
7+
* Returns a list of {@link ts.Diagnostic} of a given file.
8+
*
9+
* This function returns `[]` if the tsconfig for the file does not list `ts-migrating` in the plugin.
910
*/
1011
export function getSemanticDiagnosticsForFile(targetFile: string): ts.Diagnostic[] {
1112
const file = ts.server.toNormalizedPath(path.resolve(process.cwd(), targetFile));
1213

1314
const projects = [...projectService.configuredProjects.values()];
14-
if (!projects.some(project => project.containsFile(file))) {
15+
if (projects.every(project => !project.containsFile(file))) {
1516
// clear existing projects to avoid running out of memory
1617
for (const project of projects) {
1718
project.close();
@@ -21,16 +22,16 @@ export function getSemanticDiagnosticsForFile(targetFile: string): ts.Diagnostic
2122

2223
projectService.openClientFile(file);
2324

24-
const project = projectService.getDefaultProjectForFile(file, false);
25-
26-
if (project?.projectKind !== PROJECT_KIND_CONFIGURED) {
27-
return [];
28-
}
29-
25+
const project = projectService.getDefaultProjectForFile(file, true);
3026
if (!project) {
3127
throw new Error('Expect project to exist');
3228
}
3329

30+
if (!isPluginEnabled(project.getCompilerOptions())) {
31+
// tsconfig that this file uses does not have `ts-migrating` declared in the plugin.
32+
return [];
33+
}
34+
3435
const diagnostics = project.getLanguageService().getSemanticDiagnostics(file);
3536

3637
projectService.closeClientFile(file);

src/api/getTSInfoForFile.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import path from 'node:path';
2+
import ts from 'typescript/lib/tsserverlibrary';
3+
import { getPluginsFromCompilerOptions } from './typescript/getPluginsFromCompilerOptions';
4+
import { projectService } from './typescript/projectService';
5+
6+
type TSInfo = {
7+
tsconfigPath: string;
8+
pluginEnabled: boolean;
9+
};
10+
11+
export const getTSInfoForFile = (filePath: string): TSInfo => {
12+
const file = ts.server.toNormalizedPath(path.resolve(process.cwd(), filePath));
13+
projectService.openClientFile(file);
14+
15+
const tsInfo = (() => {
16+
const project = projectService.getDefaultProjectForFile(file, true);
17+
const compilerOptions = project?.getCompilerOptions() ?? {};
18+
return {
19+
tsconfigPath: (compilerOptions.configFilePath as string) ?? '[not found]',
20+
pluginEnabled: isPluginEnabled(compilerOptions),
21+
};
22+
})();
23+
24+
projectService.closeClientFile(file);
25+
return tsInfo;
26+
};
27+
28+
export const isPluginEnabled = (compilerOptions: ts.CompilerOptions): boolean =>
29+
getPluginsFromCompilerOptions(compilerOptions).some(({ name }) => name === 'ts-migrating');

src/api/mod.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { getSemanticDiagnosticsForFile } from './getSemanticDiagnostics';
2-
import { isPluginDiagnostic } from './isPluginDiagnostic';
3-
4-
export { getSemanticDiagnosticsForFile, isPluginDiagnostic };
1+
export { getSemanticDiagnosticsForFile } from './getSemanticDiagnostics';
2+
export { getTSInfoForFile } from './getTSInfoForFile';
3+
export { isPluginDiagnostic } from './isPluginDiagnostic';

src/api/typescript/createProjectService.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type ts from 'typescript/lib/tsserverlibrary';
2+
3+
export const getPluginsFromCompilerOptions = (
4+
compilerOptions: ts.CompilerOptions,
5+
): ts.PluginImport[] => {
6+
return (compilerOptions.plugins ?? []) as ts.PluginImport[];
7+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import ts from 'typescript/lib/tsserverlibrary';
2+
3+
export const projectService = new ts.server.ProjectService({
4+
host: {
5+
...ts.sys,
6+
setTimeout,
7+
clearTimeout,
8+
setImmediate,
9+
clearImmediate,
10+
watchDirectory: () => ({ close: () => {} }),
11+
watchFile: () => ({ close: () => {} }),
12+
},
13+
session: undefined,
14+
logger: {
15+
close: () => {},
16+
hasLevel: () => false,
17+
loggingEnabled: () => false,
18+
perftrc: () => {},
19+
info: () => {},
20+
startGroup: () => {},
21+
endGroup: () => {},
22+
msg: () => {},
23+
getLogFileName: () => undefined,
24+
},
25+
cancellationToken: ts.server.nullCancellationToken,
26+
useSingleInferredProject: true,
27+
useInferredProjectPerProjectRoot: true,
28+
typingsInstaller: ts.server.nullTypingsInstaller,
29+
allowLocalPluginLoads: true,
30+
});

src/cli/commands/annotate.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,10 @@ import { getLineNumberGivenPosition } from '../../api/utils/getLineNumberGivenPo
55
import { DIRECTIVE } from '../../plugin/constants/DIRECTIVE';
66
import { UNUSED_DIRECTIVE_DIAGNOSTIC_CODE } from '../../plugin/constants/UNUSED_DIRECTIVE_DIAGNOSTIC_CODE';
77
import { ANNOTATE_WARNING } from '../constants/annotate-warning';
8-
import { expandTSFilePaths } from '../expandTSFilePaths';
8+
import { getPluginEnabledTSFilePaths } from '../ops/getPluginEnabledTSFilePaths';
99

1010
export const annotate = async ({ verbose }: { verbose: boolean }, ...inputPaths: string[]) => {
11-
const files = expandTSFilePaths(inputPaths);
12-
console.log(
13-
`🔍 Annotating ${files.length} file${files.length === 1 ? '' : 's'}...${!verbose ? ' (use --verbose to see the list)' : ''}`,
14-
);
15-
if (verbose) {
16-
console.log('Files to annotate:');
17-
console.log(files.map(file => ` • ${file}`).join('\n'));
18-
}
11+
const files = getPluginEnabledTSFilePaths(inputPaths, { verbose });
1912

2013
console.log(ANNOTATE_WARNING);
2114

0 commit comments

Comments
 (0)