Skip to content

feat(core): Support ${configDir}#370

Merged
mizdra merged 7 commits intomizdra:mainfrom
InSyncWithFoo:main
Apr 21, 2026
Merged

feat(core): Support ${configDir}#370
mizdra merged 7 commits intomizdra:mainfrom
InSyncWithFoo:main

Conversation

@InSyncWithFoo
Copy link
Copy Markdown
Contributor

Resolves #368.

Included and excluded paths using ${configDir} are now resolved correctly. The variable, recognized only if placed at the very start, is case-insensitively replaced with ./; the path is then joined with the base directory's path as usual.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: 8f28ecc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@css-modules-kit/core Minor
@css-modules-kit/codegen Minor
@css-modules-kit/eslint-plugin Minor
@css-modules-kit/stylelint-plugin Minor
@css-modules-kit/ts-plugin Minor
css-modules-kit-vscode Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

mizdra added 6 commits April 21, 2026 23:31
- Use the same function names as in TypeScript
- To prevent the function from being redefined every time `readConfigFile` is executed
- Users can also specify a path for `cmkOptions.dtsOutDir`. They would likely expect `${configDir}` to be supported there as well.
const result = readConfigFile(iff.join('app'));
expect(result.includes).toEqual([iff.join('src')]);
expect(result.excludes).toEqual([iff.join('dist')]);
expect(result.dtsOutDir).toBe(iff.join('generated'));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this test fails. There seems to be a bug. I’ll fix it later, so I’ll leave it as is in this pull request.

 FAIL   unit  packages/core/src/config.test.ts > readConfigFile > inheritance > resolves relative paths against the defining tsconfig directory
AssertionError: expected '/var/folders/1b/v674402d0n1d90hz22pbz…' to be '/var/folders/1b/v674402d0n1d90hz22pbz…' // Object.is equality

Expected: "/var/folders/1b/v674402d0n1d90hz22pbz_tr0000gn/T/css-modules-kit/12/da8a9946-a88c-4612-920f-a8e84e4a23eb/generated"
Received: "/var/folders/1b/v674402d0n1d90hz22pbz_tr0000gn/T/css-modules-kit/12/da8a9946-a88c-4612-920f-a8e84e4a23eb/app/generated"

 ❯ packages/core/src/config.test.ts:292:32
    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|     });
    294|   });
 ❯ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.1.16_@types+node@25.5.2_esbuild@0.27.7_tsx@4.21.0_typesc_d9d6de7afd15cc08c9d54a997cfe644c/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/chunk-artifact.js:1893:22

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON content is passed through convertToJson(), which reads from getTsconfigRootOptionsMap() via parseOwnConfigOfJsonSourceFile(). Only options that are declared to be paths (look for isFilePath: true and .isFilePath in commandLineParser.ts) get the special treatment.

I tried this hack, to no avail:

const tsConfigSourceFile = ts.readJsonConfigFile(fileName, path => {
  const originalContent = ts.sys.readFile(path);
  let parsed: unknown;

  try {
    parsed = JSON.parse(originalContent ?? '');
  } catch {
    return originalContent;
  }

  if (typeof parsed === 'object' && parsed !== null && 'cmkOptions' in parsed) {
    let compilerOptions: { cmkOptions?: any };
    if ('compilerOptions' in parsed) {
      if (typeof parsed.compilerOptions !== 'object' || parsed.compilerOptions === null) {
        console.log('compo2')
        return originalContent;
      }
      compilerOptions = parsed.compilerOptions;
    } else {
      compilerOptions = {};
      Object.assign(parsed, { compilerOptions });
    }
    compilerOptions!.cmkOptions = parsed.cmkOptions;
  }

  return JSON.stringify(parsed, null, '  ');
});

if ('optionsDeclaration' in ts && ts.optionsDeclaration instanceof Array) {
  ts.optionsDeclaration.push({
    name: 'cmkOptions',
    type: 'object',
    elementOptions: new Map(Object.entries({
      'dtsOutDir': {
        name: 'dtsOutDir',
        type: 'string',
        isFilePath: true
      }
    }))
  });
} 

All subcomponents of _tsconfigRootOptions, compilerOptions included, are built at import time, so it was too late.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bug is resolved in #373.

Copy link
Copy Markdown
Owner

@mizdra mizdra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you for contributing!

@mizdra mizdra enabled auto-merge (squash) April 21, 2026 15:26
@mizdra mizdra disabled auto-merge April 21, 2026 15:26
@mizdra mizdra merged commit d51cf0f into mizdra:main Apr 21, 2026
16 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Feature New Feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The file specified in tsconfig.json not found (configDir not supported?)

2 participants