Skip to content

Commit d51cf0f

Browse files
feat(core): Support ${configDir} (#370)
* feat(core): Support ${configDir} * refactor: refactor the code - Use the same function names as in TypeScript - To prevent the function from being redefined every time `readConfigFile` is executed * feat: support `${configDir}` in `cmkOptions.dtsOutDir` - Users can also specify a path for `cmkOptions.dtsOutDir`. They would likely expect `${configDir}` to be supported there as well. * test: refactor test * test: add test cases * test: add failed test * chore: fix changeset --------- Co-authored-by: mizdra <pp.mizdra@gmail.com>
1 parent 34a3174 commit d51cf0f

3 files changed

Lines changed: 89 additions & 3 deletions

File tree

.changeset/cute-files-pump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@css-modules-kit/core': minor
3+
---
4+
5+
feat(core): support `${configDir}` in tsconfig options

packages/core/src/config.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,29 @@ describe('readConfigFile', () => {
268268
}),
269269
);
270270
});
271+
// FIXME
272+
test.fails('resolves relative paths against the defining tsconfig directory', async () => {
273+
const iff = await createIFF({
274+
'tsconfig.base.json': dedent`
275+
{
276+
"include": ["src"],
277+
"exclude": ["dist"],
278+
"cmkOptions": {
279+
"dtsOutDir": "generated"
280+
}
281+
}
282+
`,
283+
'app/tsconfig.json': dedent`
284+
{
285+
"extends": "../tsconfig.base.json"
286+
}
287+
`,
288+
});
289+
const result = readConfigFile(iff.join('app'));
290+
expect(result.includes).toEqual([iff.join('src')]);
291+
expect(result.excludes).toEqual([iff.join('dist')]);
292+
expect(result.dtsOutDir).toBe(iff.join('generated'));
293+
});
271294
});
272295
describe('diagnostics', () => {
273296
test('returns diagnostics and a config object with error values excluded if config file has semantic errors', async () => {
@@ -378,4 +401,54 @@ describe('readConfigFile', () => {
378401
]);
379402
});
380403
});
404+
describe('configDir template variable', () => {
405+
// oxlint-disable-next-line no-template-curly-in-string
406+
test('resolve ${configDir} with the entry tsconfig directory', async () => {
407+
const iff = await createIFF({
408+
'tsconfig.base.json': dedent`
409+
{
410+
"include": ["\${configDir}/src"],
411+
"exclude": ["\${configDir}/dist"],
412+
"cmkOptions": {
413+
"dtsOutDir": "\${configDir}/generated"
414+
}
415+
}
416+
`,
417+
'app/tsconfig.json': dedent`
418+
{
419+
"extends": "../tsconfig.base.json",
420+
}
421+
`,
422+
});
423+
const result = readConfigFile(iff.join('app'));
424+
expect(result.includes).toEqual([iff.join('app/src')]);
425+
expect(result.excludes).toEqual([iff.join('app/dist')]);
426+
expect(result.dtsOutDir).toBe(iff.join('app/generated'));
427+
});
428+
// oxlint-disable-next-line no-template-curly-in-string
429+
test('does not replace ${configDir} if it is not at the start of the path', async () => {
430+
const iff = await createIFF({
431+
'tsconfig.json': dedent`
432+
{
433+
"include": ["./\${configDir}/src"]
434+
}
435+
`,
436+
});
437+
const result = readConfigFile(iff.rootDir);
438+
// oxlint-disable-next-line no-template-curly-in-string
439+
expect(result.includes).toEqual([iff.join('${configDir}/src')]);
440+
});
441+
// oxlint-disable-next-line no-template-curly-in-string
442+
test('replaces ${configDir} case-insensitively', async () => {
443+
const iff = await createIFF({
444+
'tsconfig.json': dedent`
445+
{
446+
"include": ["\${CONFIGDIR}/src"]
447+
}
448+
`,
449+
});
450+
const result = readConfigFile(iff.rootDir);
451+
expect(result.includes).toEqual([iff.join('src')]);
452+
});
453+
});
381454
});

packages/core/src/config.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ function parseTsConfigFile(fileName: string) {
229229
};
230230
}
231231

232+
// https://github.com/microsoft/TypeScript/blob/55423abe4d029017f19b6e4c32097591994836b4/src/compiler/commandLineParser.ts#L3299-L3328
233+
function getSubstitutedPath(path: string, basePath: string) {
234+
return join(basePath, path.replace(/^\$\{configDir}/i, './'));
235+
}
236+
232237
/**
233238
* Reads the `tsconfig.json` file and returns the normalized config.
234239
* Even if the `tsconfig.json` file contains syntax or semantic errors,
@@ -256,12 +261,15 @@ export function readConfigFile(project: string): CMKConfig {
256261
}
257262

258263
const basePath = dirname(configFileName);
264+
259265
return {
260266
// If `include` is not specified, fallback to the default include spec。
261267
// ref: https://github.com/microsoft/TypeScript/blob/caf1aee269d1660b4d2a8b555c2d602c97cb28d7/src/compiler/commandLineParser.ts#L3102
262-
includes: (parsedTsConfig.config.includes ?? [DEFAULT_INCLUDE_SPEC]).map((i) => join(basePath, i)),
263-
excludes: (parsedTsConfig.config.excludes ?? []).map((e) => join(basePath, e)),
264-
dtsOutDir: join(basePath, parsedTsConfig.config.dtsOutDir ?? 'generated'),
268+
includes: (parsedTsConfig.config.includes ?? [DEFAULT_INCLUDE_SPEC]).map((path) =>
269+
getSubstitutedPath(path, basePath),
270+
),
271+
excludes: (parsedTsConfig.config.excludes ?? []).map((path) => getSubstitutedPath(path, basePath)),
272+
dtsOutDir: getSubstitutedPath(parsedTsConfig.config.dtsOutDir ?? 'generated', basePath),
265273
arbitraryExtensions: parsedTsConfig.config.arbitraryExtensions ?? false,
266274
namedExports: parsedTsConfig.config.namedExports ?? false,
267275
prioritizeNamedImports: parsedTsConfig.config.prioritizeNamedImports ?? false,

0 commit comments

Comments
 (0)