Skip to content

Commit 865dd9a

Browse files
committed
feat: add implicit compilerOptions
1 parent b671a94 commit 865dd9a

File tree

11 files changed

+299
-88
lines changed

11 files changed

+299
-88
lines changed

src/parse-tsconfig/index.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,167 @@ const compilerFieldsWithConfigDir = [
256256
'tsBuildInfoFile',
257257
] as const;
258258

259+
const normalizeCompilerOptions = (
260+
compilerOptions: TsConfigJson.CompilerOptions,
261+
) => {
262+
if (compilerOptions.strict) {
263+
const strictOptions = [
264+
'noImplicitAny',
265+
'noImplicitThis',
266+
'strictNullChecks',
267+
'strictFunctionTypes',
268+
'strictBindCallApply',
269+
'strictPropertyInitialization',
270+
'strictBuiltinIteratorReturn',
271+
'alwaysStrict',
272+
'useUnknownInCatchVariables',
273+
] as const;
274+
275+
for (const key of strictOptions) {
276+
if (compilerOptions[key] === undefined) {
277+
compilerOptions[key] = true;
278+
}
279+
}
280+
}
281+
282+
if (compilerOptions.target) {
283+
let target = compilerOptions.target.toLowerCase() as TsConfigJson.CompilerOptions.Target;
284+
285+
if (target === 'es2015') {
286+
target = 'es6';
287+
}
288+
289+
// Lower case
290+
compilerOptions.target = target;
291+
292+
if (target === 'esnext') {
293+
compilerOptions.module ??= 'es6';
294+
compilerOptions.moduleResolution ??= 'classic';
295+
compilerOptions.useDefineForClassFields ??= true;
296+
}
297+
298+
if (
299+
target === 'es6'
300+
|| target === 'es2016'
301+
|| target === 'es2017'
302+
|| target === 'es2018'
303+
|| target === 'es2019'
304+
|| target === 'es2020'
305+
|| target === 'es2021'
306+
|| target === 'es2022'
307+
|| target === 'es2023'
308+
|| target === 'es2024'
309+
) {
310+
compilerOptions.module ??= 'es6';
311+
compilerOptions.moduleResolution ??= 'classic';
312+
}
313+
314+
if (
315+
target === 'es2022'
316+
|| target === 'es2023'
317+
|| target === 'es2024'
318+
) {
319+
compilerOptions.useDefineForClassFields ??= true;
320+
}
321+
}
322+
323+
if (compilerOptions.module) {
324+
let module = compilerOptions.module.toLowerCase() as TsConfigJson.CompilerOptions.Module;
325+
326+
if (module === 'es2015') {
327+
module = 'es6';
328+
}
329+
330+
compilerOptions.module = module;
331+
332+
if (
333+
module === 'es6'
334+
|| module === 'es2020'
335+
|| module === 'es2022'
336+
|| module === 'esnext'
337+
|| module === 'none'
338+
|| module === 'system'
339+
|| module === 'umd'
340+
|| module === 'amd'
341+
) {
342+
compilerOptions.moduleResolution ??= 'classic';
343+
}
344+
345+
if (module === 'system') {
346+
compilerOptions.allowSyntheticDefaultImports ??= true;
347+
}
348+
349+
if (
350+
module === 'node16'
351+
|| module === 'nodenext'
352+
|| module === 'preserve'
353+
) {
354+
compilerOptions.esModuleInterop ??= true;
355+
compilerOptions.allowSyntheticDefaultImports ??= true;
356+
}
357+
358+
if (
359+
module === 'node16'
360+
|| module === 'nodenext'
361+
) {
362+
compilerOptions.moduleDetection ??= 'force';
363+
compilerOptions.useDefineForClassFields ??= true;
364+
}
365+
366+
if (module === 'node16') {
367+
compilerOptions.target ??= 'es2022';
368+
compilerOptions.moduleResolution ??= 'node16';
369+
}
370+
371+
if (module === 'nodenext') {
372+
compilerOptions.target ??= 'esnext';
373+
compilerOptions.moduleResolution ??= 'nodenext';
374+
}
375+
376+
if (module === 'preserve') {
377+
compilerOptions.moduleResolution ??= 'bundler';
378+
}
379+
}
380+
381+
if (compilerOptions.moduleResolution) {
382+
let moduleResolution = compilerOptions.moduleResolution.toLowerCase() as
383+
TsConfigJson.CompilerOptions.ModuleResolution;
384+
385+
if (moduleResolution === 'node') {
386+
moduleResolution = 'node10';
387+
}
388+
389+
compilerOptions.moduleResolution = moduleResolution;
390+
391+
if (
392+
moduleResolution === 'node16'
393+
|| moduleResolution === 'nodenext'
394+
|| moduleResolution === 'bundler'
395+
) {
396+
compilerOptions.resolvePackageJsonExports ??= true;
397+
compilerOptions.resolvePackageJsonImports ??= true;
398+
}
399+
400+
if (moduleResolution === 'bundler') {
401+
compilerOptions.allowSyntheticDefaultImports ??= true;
402+
compilerOptions.resolveJsonModule ??= true;
403+
}
404+
}
405+
406+
if (compilerOptions.esModuleInterop) {
407+
compilerOptions.allowSyntheticDefaultImports ??= true;
408+
}
409+
410+
if (compilerOptions.verbatimModuleSyntax) {
411+
compilerOptions.isolatedModules ??= true;
412+
compilerOptions.preserveConstEnums ??= true;
413+
}
414+
415+
if (compilerOptions.isolatedModules) {
416+
compilerOptions.preserveConstEnums ??= true;
417+
}
418+
};
419+
259420
/**
260421
* Parses a tsconfig file at a given path
261422
*
@@ -299,6 +460,8 @@ export const parseTsconfig = (
299460
);
300461
}
301462
}
463+
464+
normalizeCompilerOptions(compilerOptions);
302465
}
303466

304467
for (const property of filesProperties) {

tests/fixtures/yarn-pnp/a.ts

Whitespace-only changes.

tests/fixtures/yarn-pnp/index.js

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
const { parseTsconfig } = require('get-tsconfig');
2-
const tests = [
3-
() => parseTsconfig('./tsconfig.package.json'),
4-
() => parseTsconfig('./tsconfig.package-path.json'),
5-
() => parseTsconfig('./tsconfig.package-path-directory.json'),
6-
() => parseTsconfig('./tsconfig.org-package.json'),
7-
() => parseTsconfig('./tsconfig.missing-extends.json'),
8-
() => parseTsconfig('./tsconfig.invalid-extends.json'),
9-
];
102

11-
for (const test of tests) {
12-
try {
13-
console.log(test());
14-
} catch (error) {
15-
console.log('Error:', error.message);
16-
process.exitCode = 1;
17-
}
3+
const tsconfigPath = process.argv[2];
4+
5+
try {
6+
const parsed = parseTsconfig(tsconfigPath);
7+
console.log(JSON.stringify(parsed));
8+
} catch (error) {
9+
console.error(error);
1810
}

tests/specs/get-tsconfig.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'node:path';
22
import { testSuite, expect } from 'manten';
33
import { createFixture } from 'fs-fixture';
44
import slash from 'slash';
5+
import { getTscTsconfig } from '../utils.js';
56
import { getTsconfig } from '#get-tsconfig';
67

78
const compilerOptions = {
@@ -33,48 +34,64 @@ export default testSuite(({ describe }) => {
3334
test('from directory path', async () => {
3435
await using fixture = await createFixture({
3536
'tsconfig.json': tsconfigJson,
37+
'a.ts': '',
3638
});
3739

40+
const expected = await getTscTsconfig(fixture.path);
41+
delete expected.files;
42+
3843
const tsconfig = getTsconfig(fixture.path);
3944
expect(tsconfig).toStrictEqual({
4045
path: slash(fixture.getPath('tsconfig.json')),
41-
config: { compilerOptions },
46+
config: expected,
4247
});
4348
});
4449

4550
test('from index.js path', async () => {
4651
await using fixture = await createFixture({
4752
'tsconfig.json': tsconfigJson,
53+
'a.ts': '',
4854
});
4955

56+
const expected = await getTscTsconfig(fixture.path);
57+
delete expected.files;
58+
5059
const tsconfig = getTsconfig(fixture.getPath('index.js'));
5160
expect(tsconfig).toStrictEqual({
5261
path: slash(fixture.getPath('tsconfig.json')),
53-
config: { compilerOptions },
62+
config: expected,
5463
});
5564
});
5665

5766
test('custom name', async () => {
5867
const customName = 'tsconfig-custom-name.json';
5968
await using fixture = await createFixture({
6069
[customName]: tsconfigJson,
70+
'a.ts': '',
6171
});
6272

73+
const expected = await getTscTsconfig(fixture.path, customName);
74+
delete expected.files;
75+
6376
const tsconfig = getTsconfig(fixture.path, customName);
6477
expect(tsconfig).toStrictEqual({
6578
path: slash(path.join(fixture.path, customName)),
66-
config: { compilerOptions },
79+
config: expected,
6780
});
6881
});
6982

7083
test('cache', async () => {
7184
await using fixture = await createFixture({
7285
'tsconfig.json': tsconfigJson,
86+
'a.ts': '',
7387
});
7488

89+
const expected = await getTscTsconfig(fixture.path);
90+
delete expected.files;
91+
7592
const expectedResult = {
7693
path: slash(fixture.getPath('tsconfig.json')),
77-
config: { compilerOptions },
94+
config: expected,
7895
};
7996

8097
const cache = new Map();

tests/specs/parse-tsconfig/extends/merges.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ export default testSuite(({ describe }) => {
111111

112112
const tsconfig = parseTsconfig(fixture.getPath('tsconfig.json'));
113113

114-
// TODO: TS 5.5 --showConfig returns extra default fields
115-
expect(expectedTsconfig).toMatchObject(tsconfig);
114+
expect(expectedTsconfig).toStrictEqual(tsconfig);
116115
});
117116

118117
describe('files', ({ test }) => {
@@ -424,8 +423,8 @@ export default testSuite(({ describe }) => {
424423
delete expectedTsconfig.files;
425424

426425
const tsconfig = parseTsconfig(fixture.getPath('tsconfig.json'));
427-
// TODO: TS 5.5 --showConfig returns extra default fields
428-
expect(expectedTsconfig).toMatchObject(tsconfig);
426+
427+
expect(expectedTsconfig).toStrictEqual(tsconfig);
429428
});
430429

431430
test('watchOptions', async () => {

tests/specs/parse-tsconfig/extends/resolves/absolute-path.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export default testSuite(({ describe }) => {
2323
delete expectedTsconfig.files;
2424

2525
const tsconfig = parseTsconfig(fixture.getPath('tsconfig.json'));
26-
// TODO: TS 5.5 --showConfig returns extra default fields
27-
expect(expectedTsconfig).toMatchObject(tsconfig);
26+
27+
expect(expectedTsconfig).toStrictEqual(tsconfig);
2828
});
2929

3030
test('no extension', async () => {
@@ -45,8 +45,8 @@ export default testSuite(({ describe }) => {
4545
delete expectedTsconfig.files;
4646

4747
const tsconfig = parseTsconfig(fixture.getPath('tsconfig.json'));
48-
// TODO: TS 5.5 --showConfig returns extra default fields
49-
expect(expectedTsconfig).toMatchObject(tsconfig);
48+
49+
expect(expectedTsconfig).toStrictEqual(tsconfig);
5050
});
5151

5252
test('arbitrary extension', async () => {
@@ -67,8 +67,8 @@ export default testSuite(({ describe }) => {
6767
delete expectedTsconfig.files;
6868

6969
const tsconfig = parseTsconfig(fixture.getPath('tsconfig.json'));
70-
// TODO: TS 5.5 --showConfig returns extra default fields
71-
expect(expectedTsconfig).toMatchObject(tsconfig);
70+
71+
expect(expectedTsconfig).toStrictEqual(tsconfig);
7272
});
7373
});
7474
});

0 commit comments

Comments
 (0)