@css-modules-kit/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/checker.d.ts +9 -2
  2. package/dist/checker.d.ts.map +1 -1
  3. package/dist/checker.js +16 -14
  4. package/dist/checker.js.map +1 -1
  5. package/dist/config.d.ts +6 -32
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +60 -59
  8. package/dist/config.js.map +1 -1
  9. package/dist/diagnostic.d.ts.map +1 -1
  10. package/dist/diagnostic.js +8 -18
  11. package/dist/diagnostic.js.map +1 -1
  12. package/dist/{dts-creator.d.ts → dts-generator.d.ts} +6 -10
  13. package/dist/dts-generator.d.ts.map +1 -0
  14. package/dist/{dts-creator.js → dts-generator.js} +63 -25
  15. package/dist/dts-generator.js.map +1 -0
  16. package/dist/error.js +2 -7
  17. package/dist/error.js.map +1 -1
  18. package/dist/export-builder.js +1 -4
  19. package/dist/export-builder.js.map +1 -1
  20. package/dist/file.js +17 -30
  21. package/dist/file.js.map +1 -1
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +12 -44
  25. package/dist/index.js.map +1 -1
  26. package/dist/parser/at-import-parser.js +3 -9
  27. package/dist/parser/at-import-parser.js.map +1 -1
  28. package/dist/parser/at-value-parser.js +1 -4
  29. package/dist/parser/at-value-parser.js.map +1 -1
  30. package/dist/parser/css-module-parser.d.ts +8 -7
  31. package/dist/parser/css-module-parser.d.ts.map +1 -1
  32. package/dist/parser/css-module-parser.js +41 -39
  33. package/dist/parser/css-module-parser.js.map +1 -1
  34. package/dist/parser/key-frame-parser.js +1 -4
  35. package/dist/parser/key-frame-parser.js.map +1 -1
  36. package/dist/parser/rule-parser.js +7 -13
  37. package/dist/parser/rule-parser.js.map +1 -1
  38. package/dist/path.d.ts +0 -1
  39. package/dist/path.d.ts.map +1 -1
  40. package/dist/path.js +16 -31
  41. package/dist/path.js.map +1 -1
  42. package/dist/resolver.d.ts.map +1 -1
  43. package/dist/resolver.js +12 -38
  44. package/dist/resolver.js.map +1 -1
  45. package/dist/type.d.ts +2 -0
  46. package/dist/type.d.ts.map +1 -1
  47. package/dist/type.js +1 -2
  48. package/dist/util.d.ts +1 -0
  49. package/dist/util.d.ts.map +1 -1
  50. package/dist/util.js +6 -8
  51. package/dist/util.js.map +1 -1
  52. package/package.json +2 -2
  53. package/src/checker.ts +20 -16
  54. package/src/config.ts +58 -47
  55. package/src/diagnostic.ts +2 -4
  56. package/src/{dts-creator.ts → dts-generator.ts} +65 -27
  57. package/src/index.ts +5 -4
  58. package/src/parser/css-module-parser.ts +32 -30
  59. package/src/path.ts +0 -3
  60. package/src/resolver.ts +5 -26
  61. package/src/type.ts +2 -0
  62. package/src/util.ts +4 -0
  63. package/dist/dts-creator.d.ts.map +0 -1
  64. package/dist/dts-creator.js.map +0 -1
package/src/config.ts CHANGED
@@ -13,6 +13,7 @@ const DEFAULT_INCLUDE_SPEC = '**/*';
13
13
  export interface CMKConfig {
14
14
  includes: string[];
15
15
  excludes: string[];
16
+ enabled: boolean | undefined;
16
17
  dtsOutDir: string;
17
18
  arbitraryExtensions: boolean;
18
19
  namedExports: boolean;
@@ -58,6 +59,8 @@ export interface CMKConfig {
58
59
  basePath: string;
59
60
  configFileName: string;
60
61
  compilerOptions: ts.CompilerOptions;
62
+ /** The directories to watch when watch mode is enabled. */
63
+ wildcardDirectories: { fileName: string; recursive: boolean }[];
61
64
  /** The diagnostics that occurred while reading the config file. */
62
65
  diagnostics: Diagnostic[];
63
66
  }
@@ -69,6 +72,7 @@ export interface CMKConfig {
69
72
  interface UnnormalizedRawConfig {
70
73
  includes?: string[];
71
74
  excludes?: string[];
75
+ enabled?: boolean;
72
76
  dtsOutDir?: string;
73
77
  arbitraryExtensions?: boolean;
74
78
  namedExports?: boolean;
@@ -84,7 +88,7 @@ interface ParsedRawData {
84
88
  diagnostics: Diagnostic[];
85
89
  }
86
90
 
87
- export function findTsConfigFile(project: string): string | undefined {
91
+ function findTsConfigFile(project: string): string | undefined {
88
92
  const configFile =
89
93
  ts.sys.directoryExists(project) ?
90
94
  ts.findConfigFile(project, ts.sys.fileExists.bind(ts.sys), 'tsconfig.json')
@@ -93,6 +97,11 @@ export function findTsConfigFile(project: string): string | undefined {
93
97
  return resolve(configFile);
94
98
  }
95
99
 
100
+ function isTsConfigFileExists(fileName: string): boolean {
101
+ return ts.findConfigFile(dirname(fileName), ts.sys.fileExists.bind(ts.sys), basename(fileName)) !== undefined;
102
+ }
103
+
104
+ // eslint-disable-next-line complexity
96
105
  function parseRawData(raw: unknown, tsConfigSourceFile: ts.TsConfigSourceFile): ParsedRawData {
97
106
  const result: ParsedRawData = {
98
107
  config: {},
@@ -118,6 +127,16 @@ function parseRawData(raw: unknown, tsConfigSourceFile: ts.TsConfigSourceFile):
118
127
  // MEMO: The errors for this option are reported by `tsc` or `tsserver`, so we don't need to report.
119
128
  }
120
129
  if ('cmkOptions' in raw && typeof raw.cmkOptions === 'object' && raw.cmkOptions !== null) {
130
+ if ('enabled' in raw.cmkOptions) {
131
+ if (typeof raw.cmkOptions.enabled === 'boolean') {
132
+ result.config.enabled = raw.cmkOptions.enabled;
133
+ } else {
134
+ result.diagnostics.push({
135
+ category: 'error',
136
+ text: `\`enabled\` in ${tsConfigSourceFile.fileName} must be a boolean.`,
137
+ });
138
+ }
139
+ }
121
140
  if ('dtsOutDir' in raw.cmkOptions) {
122
141
  if (typeof raw.cmkOptions.dtsOutDir === 'string') {
123
142
  result.config.dtsOutDir = raw.cmkOptions.dtsOutDir;
@@ -175,21 +194,9 @@ function parseRawData(raw: unknown, tsConfigSourceFile: ts.TsConfigSourceFile):
175
194
  }
176
195
  return result;
177
196
  }
178
- export { parseRawData as parseRawDataForTest };
179
-
180
- /**
181
- * @throws {TsConfigFileNotFoundError}
182
- */
183
- export function readTsConfigFile(project: string): {
184
- configFileName: string;
185
- config: UnnormalizedRawConfig;
186
- compilerOptions: ts.CompilerOptions;
187
- diagnostics: Diagnostic[];
188
- } {
189
- const configFileName = findTsConfigFile(project);
190
- if (!configFileName) throw new TsConfigFileNotFoundError();
191
197
 
192
- const tsConfigSourceFile = ts.readJsonConfigFile(configFileName, ts.sys.readFile.bind(ts.sys));
198
+ function parseTsConfigFile(fileName: string) {
199
+ const tsConfigSourceFile = ts.readJsonConfigFile(fileName, ts.sys.readFile.bind(ts.sys));
193
200
  // MEMO: `tsConfigSourceFile.parseDiagnostics` (Internal API) contains a syntax error for `tsconfig.json`.
194
201
  // However, it is ignored so that ts-plugin will work even if `tsconfig.json` is somewhat broken.
195
202
  // Also, this error is reported to the user by `tsc` or `tsserver`.
@@ -198,9 +205,9 @@ export function readTsConfigFile(project: string): {
198
205
  const parsedCommandLine = ts.parseJsonSourceFileConfigFileContent(
199
206
  tsConfigSourceFile,
200
207
  ts.sys,
201
- dirname(configFileName),
208
+ dirname(fileName),
202
209
  undefined,
203
- configFileName,
210
+ fileName,
204
211
  undefined,
205
212
  [
206
213
  {
@@ -211,29 +218,15 @@ export function readTsConfigFile(project: string): {
211
218
  ],
212
219
  );
213
220
  // Read options from `parsedCommandLine.raw`
214
- let parsedRawData = parseRawData(parsedCommandLine.raw, tsConfigSourceFile);
215
-
216
- // The options read from `parsedCommandLine.raw` do not inherit values from the file specified in `extends`.
217
- // So here we read the options from those files and merge them into `parsedRawData`.
218
- if (tsConfigSourceFile.extendedSourceFiles) {
219
- for (const extendedSourceFile of tsConfigSourceFile.extendedSourceFiles) {
220
- let base: ParsedRawData;
221
- try {
222
- base = readTsConfigFile(extendedSourceFile);
223
- } catch (error) {
224
- if (error instanceof TsConfigFileNotFoundError) continue;
225
- throw error;
226
- }
227
- parsedRawData = {
228
- config: { ...base.config, ...parsedRawData.config },
229
- diagnostics: [...base.diagnostics, ...parsedRawData.diagnostics],
230
- };
231
- }
232
- }
221
+ const parsedRawData = parseRawData(parsedCommandLine.raw, tsConfigSourceFile);
233
222
 
234
223
  return {
235
- configFileName,
224
+ extendedSourceFiles: tsConfigSourceFile.extendedSourceFiles,
236
225
  compilerOptions: parsedCommandLine.options,
226
+ wildcardDirectories: Object.entries(parsedCommandLine.wildcardDirectories ?? {}).map(([fileName, flags]) => ({
227
+ fileName,
228
+ recursive: (flags & ts.WatchDirectoryFlags.Recursive) !== 0,
229
+ })),
237
230
  ...parsedRawData,
238
231
  };
239
232
  }
@@ -247,21 +240,39 @@ export function readTsConfigFile(project: string): {
247
240
  * @throws {TsConfigFileNotFoundError}
248
241
  */
249
242
  export function readConfigFile(project: string): CMKConfig {
250
- const { configFileName, config, compilerOptions, diagnostics } = readTsConfigFile(project);
243
+ const configFileName = findTsConfigFile(project);
244
+ if (!configFileName) throw new TsConfigFileNotFoundError();
245
+
246
+ const parsedTsConfig = parseTsConfigFile(configFileName);
247
+
248
+ // The options read from `parsedCommandLine.raw` do not inherit values from the file specified in `extends`.
249
+ // So here we read the options from those files and merge them into `parsedRawData`.
250
+ if (parsedTsConfig.extendedSourceFiles) {
251
+ for (const extendedSourceFile of parsedTsConfig.extendedSourceFiles) {
252
+ if (isTsConfigFileExists(extendedSourceFile)) {
253
+ const base = parseTsConfigFile(extendedSourceFile);
254
+ parsedTsConfig.config = { ...base.config, ...parsedTsConfig.config };
255
+ parsedTsConfig.diagnostics = [...base.diagnostics, ...parsedTsConfig.diagnostics];
256
+ }
257
+ }
258
+ }
259
+
251
260
  const basePath = dirname(configFileName);
252
261
  return {
253
262
  // If `include` is not specified, fallback to the default include spec。
254
263
  // ref: https://github.com/microsoft/TypeScript/blob/caf1aee269d1660b4d2a8b555c2d602c97cb28d7/src/compiler/commandLineParser.ts#L3102
255
- includes: (config.includes ?? [DEFAULT_INCLUDE_SPEC]).map((i) => join(basePath, i)),
256
- excludes: (config.excludes ?? []).map((e) => join(basePath, e)),
257
- dtsOutDir: join(basePath, config.dtsOutDir ?? 'generated'),
258
- arbitraryExtensions: config.arbitraryExtensions ?? false,
259
- namedExports: config.namedExports ?? false,
260
- prioritizeNamedImports: config.prioritizeNamedImports ?? false,
261
- keyframes: config.keyframes ?? true,
264
+ includes: (parsedTsConfig.config.includes ?? [DEFAULT_INCLUDE_SPEC]).map((i) => join(basePath, i)),
265
+ excludes: (parsedTsConfig.config.excludes ?? []).map((e) => join(basePath, e)),
266
+ dtsOutDir: join(basePath, parsedTsConfig.config.dtsOutDir ?? 'generated'),
267
+ arbitraryExtensions: parsedTsConfig.config.arbitraryExtensions ?? false,
268
+ namedExports: parsedTsConfig.config.namedExports ?? false,
269
+ prioritizeNamedImports: parsedTsConfig.config.prioritizeNamedImports ?? false,
270
+ keyframes: parsedTsConfig.config.keyframes ?? true,
271
+ enabled: parsedTsConfig.config.enabled,
262
272
  basePath,
263
273
  configFileName,
264
- compilerOptions,
265
- diagnostics,
274
+ compilerOptions: parsedTsConfig.compilerOptions,
275
+ wildcardDirectories: parsedTsConfig.wildcardDirectories,
276
+ diagnostics: parsedTsConfig.diagnostics,
266
277
  };
267
278
  }
package/src/diagnostic.ts CHANGED
@@ -1,20 +1,18 @@
1
1
  import ts from 'typescript';
2
2
  import type { SystemError } from './error.js';
3
- import type { Diagnostic, DiagnosticSourceFile, DiagnosticWithLocation } from './type.js';
3
+ import type { Diagnostic, DiagnosticCategory, DiagnosticSourceFile, DiagnosticWithLocation } from './type.js';
4
4
 
5
5
  /** The error code used by tsserver to display the css-modules-kit error in the editor. */
6
6
  const TS_ERROR_CODE = 0;
7
7
 
8
8
  const TS_ERROR_SOURCE = 'css-modules-kit';
9
9
 
10
- function convertErrorCategory(category: 'error' | 'warning' | 'suggestion'): ts.DiagnosticCategory {
10
+ function convertErrorCategory(category: DiagnosticCategory): ts.DiagnosticCategory {
11
11
  switch (category) {
12
12
  case 'error':
13
13
  return ts.DiagnosticCategory.Error;
14
14
  case 'warning':
15
15
  return ts.DiagnosticCategory.Warning;
16
- case 'suggestion':
17
- return ts.DiagnosticCategory.Suggestion;
18
16
  default:
19
17
  throw new Error(`Unknown category: ${String(category)}`);
20
18
  }
@@ -1,14 +1,9 @@
1
- import type { CSSModule, MatchesPattern, Resolver, Token, TokenImporter } from './type.js';
2
- import { isValidAsJSIdentifier } from './util.js';
1
+ import type { CSSModule, Token, TokenImporter } from './type.js';
2
+ import { isURLSpecifier, isValidAsJSIdentifier } from './util.js';
3
3
 
4
4
  export const STYLES_EXPORT_NAME = 'styles';
5
5
 
6
- export interface CreateDtsHost {
7
- resolver: Resolver;
8
- matchesPattern: MatchesPattern;
9
- }
10
-
11
- export interface CreateDtsOptions {
6
+ export interface GenerateDtsOptions {
12
7
  namedExports: boolean;
13
8
  prioritizeNamedImports: boolean;
14
9
  /** Generate .d.ts for ts-plugin */
@@ -37,19 +32,19 @@ interface LinkedCodeMapping extends CodeMapping {
37
32
  generatedLengths: number[];
38
33
  }
39
34
 
40
- interface CreateDtsResult {
35
+ interface GenerateDtsResult {
41
36
  text: string;
42
37
  mapping: CodeMapping;
43
38
  linkedCodeMapping: LinkedCodeMapping;
44
39
  }
45
40
 
46
41
  /**
47
- * Create a d.ts file.
42
+ * Generate .d.ts from `CSSModule`.
48
43
  */
49
- export function createDts(cssModules: CSSModule, host: CreateDtsHost, options: CreateDtsOptions): CreateDtsResult {
44
+ export function generateDts(cssModule: CSSModule, options: GenerateDtsOptions): GenerateDtsResult {
50
45
  // Exclude invalid tokens
51
- const localTokens = cssModules.localTokens.filter((token) => isValidName(token.name, options));
52
- const tokenImporters = cssModules.tokenImporters
46
+ const localTokens = cssModule.localTokens.filter((token) => isValidName(token.name, options));
47
+ const tokenImporters = cssModule.tokenImporters
53
48
  // Exclude invalid imported tokens
54
49
  .map((tokenImporter) => {
55
50
  if (tokenImporter.type === 'value') {
@@ -65,21 +60,54 @@ export function createDts(cssModules: CSSModule, host: CreateDtsHost, options: C
65
60
  return tokenImporter;
66
61
  }
67
62
  })
68
- // Exclude token importers for external files
69
63
  .filter((tokenImporter) => {
70
- const resolved = host.resolver(tokenImporter.from, { request: cssModules.fileName });
71
- return resolved !== undefined && host.matchesPattern(resolved);
64
+ /**
65
+ * In principle, token importers with specifiers that cannot be resolved are still included in the type
66
+ * definitions. For example, consider the following:
67
+ *
68
+ * ```css
69
+ * // src/a.module.css
70
+ * @import './unresolved.module.css';
71
+ * @import './unmatched.css';
72
+ * .a_1 { color: red; }
73
+ * ```
74
+ *
75
+ * In this case, CSS Modules Kit generates the following type definitions:
76
+ *
77
+ * ```ts
78
+ * // generated/src/a.module.css.d.ts
79
+ * // @ts-nocheck
80
+ * declare const styles = {
81
+ * a_1: '' as readonly string,
82
+ * ...(await import('./unresolved.module.css')).default,
83
+ * ...(await import('./unmatched.css')).default,
84
+ * };
85
+ * ```
86
+ *
87
+ * Even if `./unresolved.module.css` or `./unmatched.css` does not exist, the same type definitions are
88
+ * generated. It is important that the generated type definitions do not change depending on whether the
89
+ * files exist. This provides the following benefits:
90
+ *
91
+ * - Simplifies the watch mode implementation
92
+ * - Only the type definitions for changed files need to be regenerated
93
+ * - Makes it easier to parallelize code generation
94
+ * - Type definitions can be generated independently per file
95
+ *
96
+ * However, as an exception, URL specifiers are not included in the type definitions, because URL
97
+ * specifiers are typically resolved at runtime.
98
+ */
99
+ return !isURLSpecifier(tokenImporter.from);
72
100
  });
73
101
 
74
102
  if (options.namedExports) {
75
- return createNamedExportsDts(localTokens, tokenImporters, options);
103
+ return generateNamedExportsDts(localTokens, tokenImporters, options);
76
104
  } else {
77
- return createDefaultExportDts(localTokens, tokenImporters);
105
+ return generateDefaultExportDts(localTokens, tokenImporters);
78
106
  }
79
107
  }
80
108
 
81
109
  /**
82
- * Create a d.ts file with named exports.
110
+ * Generate a d.ts file with named exports.
83
111
  * @example
84
112
  * If the CSS module file is:
85
113
  * ```css
@@ -100,10 +128,10 @@ export function createDts(cssModules: CSSModule, host: CreateDtsHost, options: C
100
128
  * } from './b.module.css';
101
129
  * ```
102
130
  */
103
- function createNamedExportsDts(
131
+ function generateNamedExportsDts(
104
132
  localTokens: Token[],
105
133
  tokenImporters: TokenImporter[],
106
- options: CreateDtsOptions,
134
+ options: GenerateDtsOptions,
107
135
  ): { text: string; mapping: CodeMapping; linkedCodeMapping: LinkedCodeMapping } {
108
136
  const mapping: CodeMapping = { sourceOffsets: [], lengths: [], generatedOffsets: [] };
109
137
  const linkedCodeMapping: LinkedCodeMapping = {
@@ -176,7 +204,7 @@ function createNamedExportsDts(
176
204
  }
177
205
 
178
206
  /**
179
- * Create a d.ts file with a default export.
207
+ * Generate a d.ts file with a default export.
180
208
  * @example
181
209
  * If the CSS module file is:
182
210
  * ```css
@@ -198,7 +226,7 @@ function createNamedExportsDts(
198
226
  * export default styles;
199
227
  * ```
200
228
  */
201
- function createDefaultExportDts(
229
+ function generateDefaultExportDts(
202
230
  localTokens: Token[],
203
231
  tokenImporters: TokenImporter[],
204
232
  ): { text: string; mapping: CodeMapping; linkedCodeMapping: LinkedCodeMapping } {
@@ -215,8 +243,18 @@ function createDefaultExportDts(
215
243
  //
216
244
  // If `--skipLibCheck` is false, those errors will be reported by `tsc`. However, these are negligible errors.
217
245
  // Therefore, `@ts-nocheck` is added to the generated type definition file.
218
- let text = `// @ts-nocheck\ndeclare const ${STYLES_EXPORT_NAME} = {\n`;
246
+ let text = `// @ts-nocheck\n`;
247
+
248
+ // This is a workaround to avoid the issue described as a "Drawbacks" in https://github.com/mizdra/css-modules-kit/pull/302.
249
+ // It uses the technique from https://stackoverflow.com/a/55541672 to fall back from `any` to `{}`.
250
+ // However, the import type for an unresolvable specifier becomes a special `any` type called `errorType`.
251
+ // The technique from https://stackoverflow.com/a/55541672 does not work with `errorType`.
252
+ // Therefore, this combines it with the approach from https://github.com/microsoft/TypeScript/issues/62972.
253
+ if (tokenImporters.some((importer) => importer.type === 'import')) {
254
+ text += `function blockErrorType<T>(val: T): [0] extends [(1 & T)] ? {} : T;\n`;
255
+ }
219
256
 
257
+ text += `declare const ${STYLES_EXPORT_NAME} = {\n`;
220
258
  for (const token of localTokens) {
221
259
  text += ` `;
222
260
  mapping.sourceOffsets.push(token.loc.start.offset);
@@ -226,11 +264,11 @@ function createDefaultExportDts(
226
264
  }
227
265
  for (const tokenImporter of tokenImporters) {
228
266
  if (tokenImporter.type === 'import') {
229
- text += ` ...(await import(`;
267
+ text += ` ...blockErrorType((await import(`;
230
268
  mapping.sourceOffsets.push(tokenImporter.fromLoc.start.offset - 1);
231
269
  mapping.lengths.push(tokenImporter.from.length + 2);
232
270
  mapping.generatedOffsets.push(text.length);
233
- text += `'${tokenImporter.from}')).default,\n`;
271
+ text += `'${tokenImporter.from}')).default),\n`;
234
272
  } else {
235
273
  // eslint-disable-next-line no-loop-func
236
274
  tokenImporter.values.forEach((value, i) => {
@@ -263,7 +301,7 @@ function createDefaultExportDts(
263
301
  return { text, mapping, linkedCodeMapping };
264
302
  }
265
303
 
266
- function isValidName(name: string, options: CreateDtsOptions): boolean {
304
+ function isValidName(name: string, options: GenerateDtsOptions): boolean {
267
305
  if (!isValidAsJSIdentifier(name)) return false;
268
306
  if (name === '__proto__') return false;
269
307
  if (options.namedExports && name === 'default') return false;
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export type { CMKConfig } from './config.js';
2
2
  export { readConfigFile } from './config.js';
3
3
  export { TsConfigFileNotFoundError, SystemError } from './error.js';
4
- export { parseCSSModule, type ParseCSSModuleOptions, type ParseCSSModuleResult } from './parser/css-module-parser.js';
4
+ export { parseCSSModule, type ParseCSSModuleOptions } from './parser/css-module-parser.js';
5
5
  export { parseRule } from './parser/rule-parser.js';
6
6
  export {
7
7
  type Location,
@@ -15,13 +15,14 @@ export {
15
15
  type Resolver,
16
16
  type MatchesPattern,
17
17
  type ExportBuilder,
18
+ type ExportRecord,
18
19
  type DiagnosticSourceFile,
19
20
  type Diagnostic,
20
21
  type DiagnosticWithLocation,
21
22
  type DiagnosticCategory,
22
23
  type DiagnosticPosition,
23
24
  } from './type.js';
24
- export { type CreateDtsOptions, createDts, STYLES_EXPORT_NAME } from './dts-creator.js';
25
+ export { type GenerateDtsOptions, generateDts, STYLES_EXPORT_NAME } from './dts-generator.js';
25
26
  export { createResolver } from './resolver.js';
26
27
  export {
27
28
  CSS_MODULE_EXTENSION,
@@ -33,8 +34,8 @@ export {
33
34
  createMatchesPattern,
34
35
  getFileNamesByPattern,
35
36
  } from './file.js';
36
- export { checkCSSModule } from './checker.js';
37
+ export { checkCSSModule, type CheckerArgs } from './checker.js';
37
38
  export { createExportBuilder } from './export-builder.js';
38
- export { join, resolve, relative, dirname, basename, parse, isAbsolute } from './path.js';
39
+ export { join, resolve, relative, dirname, basename, parse } from './path.js';
39
40
  export { findUsedTokenNames } from './util.js';
40
41
  export { convertDiagnostic, convertDiagnosticWithLocation, convertSystemError } from './diagnostic.js';
@@ -78,48 +78,50 @@ function collectTokens(ast: Root, keyframes: boolean) {
78
78
 
79
79
  export interface ParseCSSModuleOptions {
80
80
  fileName: string;
81
- safe: boolean;
81
+ /** Whether to include syntax errors from diagnostics */
82
+ includeSyntaxError: boolean;
82
83
  keyframes: boolean;
83
84
  }
84
-
85
- export interface ParseCSSModuleResult {
86
- cssModule: CSSModule;
87
- diagnostics: DiagnosticWithLocation[];
88
- }
89
-
85
+ /**
86
+ * Parse CSS Module text.
87
+ * If a syntax error is detected in the text, it is re-parsed using `postcss-safe-parser`, and `localTokens` are collected as much as possible.
88
+ */
90
89
  export function parseCSSModule(
91
90
  text: string,
92
- { fileName, safe, keyframes }: ParseCSSModuleOptions,
93
- ): ParseCSSModuleResult {
91
+ { fileName, includeSyntaxError, keyframes }: ParseCSSModuleOptions,
92
+ ): CSSModule {
94
93
  let ast: Root;
95
- const diagnosticSourceFile = { fileName, text };
96
- try {
97
- const parser = safe ? safeParser : parse;
98
- ast = parser(text, { from: fileName });
99
- } catch (e) {
100
- if (e instanceof CssSyntaxError) {
94
+ const diagnosticFile = { fileName, text };
95
+ const allDiagnostics: DiagnosticWithLocation[] = [];
96
+ if (includeSyntaxError) {
97
+ try {
98
+ ast = parse(text, { from: fileName });
99
+ } catch (e) {
100
+ if (!(e instanceof CssSyntaxError)) throw e;
101
+ // If syntax error, try to parse with safe parser. While this incurs a cost
102
+ // due to parsing the file twice, it rarely becomes an issue since files
103
+ // with syntax errors are usually few in number.
104
+ ast = safeParser(text, { from: fileName });
101
105
  const { line, column, endColumn } = e.input!;
102
- return {
103
- cssModule: { fileName, text, localTokens: [], tokenImporters: [] },
104
- diagnostics: [
105
- {
106
- file: diagnosticSourceFile,
107
- start: { line, column },
108
- length: endColumn !== undefined ? endColumn - column : 1,
109
- text: e.reason,
110
- category: 'error',
111
- },
112
- ],
113
- };
106
+ allDiagnostics.push({
107
+ file: diagnosticFile,
108
+ start: { line, column },
109
+ length: endColumn !== undefined ? endColumn - column : 1,
110
+ text: e.reason,
111
+ category: 'error',
112
+ });
114
113
  }
115
- throw e;
114
+ } else {
115
+ ast = safeParser(text, { from: fileName });
116
116
  }
117
+
117
118
  const { localTokens, tokenImporters, diagnostics } = collectTokens(ast, keyframes);
118
- const cssModule = {
119
+ allDiagnostics.push(...diagnostics.map((diagnostic) => ({ ...diagnostic, file: diagnosticFile })));
120
+ return {
119
121
  fileName,
120
122
  text,
121
123
  localTokens,
122
124
  tokenImporters,
125
+ diagnostics: allDiagnostics,
123
126
  };
124
- return { cssModule, diagnostics: diagnostics.map((diagnostic) => ({ ...diagnostic, file: diagnosticSourceFile })) };
125
127
  }
package/src/path.ts CHANGED
@@ -32,6 +32,3 @@ export function parse(path: string): ParsedPath {
32
32
  const { root, dir, base, name, ext } = nodePath.parse(path);
33
33
  return { root: slash(root), dir: slash(dir), base, name, ext };
34
34
  }
35
-
36
- // eslint-disable-next-line @typescript-eslint/unbound-method
37
- export const isAbsolute = nodePath.isAbsolute;
package/src/resolver.ts CHANGED
@@ -1,16 +1,14 @@
1
- import { fileURLToPath, pathToFileURL } from 'node:url';
2
1
  import type { CompilerOptions } from 'typescript';
3
2
  import ts from 'typescript';
4
- import { isAbsolute, resolve } from './path.js';
5
3
  import type { Resolver, ResolverOptions } from './type.js';
4
+ import { isURLSpecifier } from './util.js';
6
5
 
7
6
  export function createResolver(
8
7
  compilerOptions: CompilerOptions,
9
8
  moduleResolutionCache: ts.ModuleResolutionCache | undefined,
10
9
  ): Resolver {
11
- return (_specifier: string, options: ResolverOptions) => {
12
- let specifier = _specifier;
13
-
10
+ return (specifier: string, options: ResolverOptions) => {
11
+ if (isURLSpecifier(specifier)) return undefined;
14
12
  const host: ts.ModuleResolutionHost = {
15
13
  ...ts.sys,
16
14
  fileExists: (fileName) => {
@@ -29,27 +27,8 @@ export function createResolver(
29
27
  );
30
28
  if (resolvedModule) {
31
29
  // TODO: Logging that the paths is used.
32
- specifier = resolvedModule.resolvedFileName.replace(/\.module\.d\.css\.ts$/u, '.module.css');
33
- }
34
- if (isAbsolute(specifier)) {
35
- return resolve(specifier);
36
- } else if (isRelativeSpecifier(specifier)) {
37
- // Convert the specifier to an absolute path
38
- // NOTE: Node.js resolves relative specifier with standard relative URL resolution semantics. So we will follow that here as well.
39
- // ref: https://nodejs.org/docs/latest-v23.x/api/esm.html#terminology
40
- return resolve(fileURLToPath(new URL(specifier, pathToFileURL(options.request)).href));
41
- } else {
42
- // Do not support URL or bare specifiers
43
- // TODO: Logging that the specifier could not resolve.
44
- return undefined;
30
+ return resolvedModule.resolvedFileName.replace(/\.module\.d\.css\.ts$/u, '.module.css');
45
31
  }
32
+ return undefined;
46
33
  };
47
34
  }
48
-
49
- /**
50
- * Check if the specifier is a relative specifier.
51
- * @see https://nodejs.org/docs/latest-v23.x/api/esm.html#terminology
52
- */
53
- function isRelativeSpecifier(specifier: string): boolean {
54
- return specifier.startsWith('./') || specifier.startsWith('../');
55
- }
package/src/type.ts CHANGED
@@ -116,6 +116,8 @@ export interface CSSModule {
116
116
  * Token importer is a statement that imports tokens from another file.
117
117
  */
118
118
  tokenImporters: TokenImporter[];
119
+ /** Diagnostics found during parsing. */
120
+ diagnostics: DiagnosticWithLocation[];
119
121
  }
120
122
 
121
123
  export interface ResolverOptions {
package/src/util.ts CHANGED
@@ -25,3 +25,7 @@ export function findUsedTokenNames(componentText: string): Set<string> {
25
25
  }
26
26
  return usedClassNames;
27
27
  }
28
+
29
+ export function isURLSpecifier(specifier: string): boolean {
30
+ return URL.canParse(specifier);
31
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"dts-creator.d.ts","sourceRoot":"","sources":["../src/dts-creator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAwB,MAAM,WAAW,CAAC;AAG3F,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,sBAAsB,EAAE,OAAO,CAAC;IAChC,mCAAmC;IACnC,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,WAAW;IACnB,iEAAiE;IACjE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,8CAA8C;AAE9C,UAAU,iBAAkB,SAAQ,WAAW;IAC7C,iDAAiD;IACjD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,iDAAiD;IACjD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA8BhH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dts-creator.js","sourceRoot":"","sources":["../src/dts-creator.ts"],"names":[],"mappings":"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"}