@knighted/css 1.0.0-rc.9 → 1.0.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.
@@ -13,10 +13,12 @@ const node_module_1 = require("node:module");
13
13
  const node_url_1 = require("node:url");
14
14
  const es_module_lexer_1 = require("es-module-lexer");
15
15
  const node_module_type_1 = require("node-module-type");
16
+ const get_tsconfig_1 = require("get-tsconfig");
17
+ const tsconfig_paths_1 = require("tsconfig-paths");
16
18
  const css_js_1 = require("./css.cjs");
17
- const loaderInternals_js_1 = require("./loaderInternals.cjs");
18
19
  const stableSelectorsLiteral_js_1 = require("./stableSelectorsLiteral.cjs");
19
20
  const stableNamespace_js_1 = require("./stableNamespace.cjs");
21
+ let activeCssWithMeta = css_js_1.cssWithMeta;
20
22
  const DEFAULT_SKIP_DIRS = new Set([
21
23
  'node_modules',
22
24
  '.git',
@@ -40,12 +42,14 @@ const SUPPORTED_EXTENSIONS = new Set([
40
42
  '.mjs',
41
43
  '.cjs',
42
44
  ]);
45
+ let moduleTypeDetector = node_module_type_1.moduleType;
46
+ let importMetaUrlProvider = getImportMetaUrl;
43
47
  function resolvePackageRoot() {
44
- const detectedType = (0, node_module_type_1.moduleType)();
48
+ const detectedType = moduleTypeDetector();
45
49
  if (detectedType === 'commonjs' && typeof __dirname === 'string') {
46
50
  return node_path_1.default.resolve(__dirname, '..');
47
51
  }
48
- const moduleUrl = getImportMetaUrl();
52
+ const moduleUrl = importMetaUrlProvider();
49
53
  if (moduleUrl) {
50
54
  return node_path_1.default.resolve(node_path_1.default.dirname((0, node_url_1.fileURLToPath)(moduleUrl)), '..');
51
55
  }
@@ -60,61 +64,55 @@ function getImportMetaUrl() {
60
64
  }
61
65
  }
62
66
  const PACKAGE_ROOT = resolvePackageRoot();
63
- const DEFAULT_TYPES_ROOT = node_path_1.default.join(PACKAGE_ROOT, 'types-stub');
64
- const DEFAULT_OUT_DIR = node_path_1.default.join(PACKAGE_ROOT, 'node_modules', '.knighted-css');
67
+ const SELECTOR_REFERENCE = '.knighted-css';
68
+ const SELECTOR_MODULE_SUFFIX = '.knighted-css.ts';
65
69
  async function generateTypes(options = {}) {
66
70
  const rootDir = node_path_1.default.resolve(options.rootDir ?? process.cwd());
67
71
  const include = normalizeIncludeOptions(options.include, rootDir);
68
- const outDir = node_path_1.default.resolve(options.outDir ?? DEFAULT_OUT_DIR);
69
- const typesRoot = node_path_1.default.resolve(options.typesRoot ?? DEFAULT_TYPES_ROOT);
72
+ const cacheDir = node_path_1.default.resolve(options.outDir ?? node_path_1.default.join(rootDir, '.knighted-css'));
73
+ const tsconfig = loadTsconfigResolutionContext(rootDir);
70
74
  await es_module_lexer_1.init;
71
- await promises_1.default.mkdir(outDir, { recursive: true });
72
- await promises_1.default.mkdir(typesRoot, { recursive: true });
75
+ await promises_1.default.mkdir(cacheDir, { recursive: true });
73
76
  const internalOptions = {
74
77
  rootDir,
75
78
  include,
76
- outDir,
77
- typesRoot,
79
+ cacheDir,
78
80
  stableNamespace: options.stableNamespace,
81
+ tsconfig,
79
82
  };
80
83
  return generateDeclarations(internalOptions);
81
84
  }
82
85
  async function generateDeclarations(options) {
83
86
  const peerResolver = createProjectPeerResolver(options.rootDir);
84
87
  const files = await collectCandidateFiles(options.include);
85
- const manifestPath = node_path_1.default.join(options.outDir, 'manifest.json');
86
- const previousManifest = await readManifest(manifestPath);
87
- const nextManifest = {};
88
+ const selectorModulesManifestPath = node_path_1.default.join(options.cacheDir, 'selector-modules.json');
89
+ const previousSelectorManifest = await readManifest(selectorModulesManifestPath);
90
+ const nextSelectorManifest = {};
88
91
  const selectorCache = new Map();
89
- const processedSpecifiers = new Set();
90
- const declarations = [];
92
+ const processedSelectors = new Set();
91
93
  const warnings = [];
92
- let writes = 0;
94
+ let selectorModuleWrites = 0;
93
95
  for (const filePath of files) {
94
96
  const matches = await findSpecifierImports(filePath);
95
97
  for (const match of matches) {
96
98
  const cleaned = match.specifier.trim();
97
99
  const inlineFree = stripInlineLoader(cleaned);
98
- if (!inlineFree.includes('?knighted-css'))
99
- continue;
100
- const { resource, query } = splitResourceAndQuery(inlineFree);
101
- if (!query || !(0, loaderInternals_js_1.hasQueryFlag)(query, loaderInternals_js_1.TYPES_QUERY_FLAG)) {
102
- continue;
103
- }
104
- if (processedSpecifiers.has(cleaned)) {
100
+ const { resource } = splitResourceAndQuery(inlineFree);
101
+ const selectorSource = extractSelectorSourceSpecifier(resource);
102
+ if (!selectorSource) {
105
103
  continue;
106
104
  }
107
105
  const resolvedNamespace = (0, stableNamespace_js_1.resolveStableNamespace)(options.stableNamespace);
108
- const resolvedPath = await resolveImportPath(resource, match.importer, options.rootDir);
106
+ const resolvedPath = await resolveImportPath(selectorSource, match.importer, options.rootDir, options.tsconfig);
109
107
  if (!resolvedPath) {
110
- warnings.push(`Unable to resolve ${resource} referenced by ${relativeToRoot(match.importer, options.rootDir)}.`);
108
+ warnings.push(`Unable to resolve ${selectorSource} referenced by ${relativeToRoot(match.importer, options.rootDir)}.`);
111
109
  continue;
112
110
  }
113
111
  const cacheKey = `${resolvedPath}::${resolvedNamespace}`;
114
112
  let selectorMap = selectorCache.get(cacheKey);
115
113
  if (!selectorMap) {
116
114
  try {
117
- const { css } = await (0, css_js_1.cssWithMeta)(resolvedPath, {
115
+ const { css } = await activeCssWithMeta(resolvedPath, {
118
116
  cwd: options.rootDir,
119
117
  peerResolver,
120
118
  });
@@ -131,38 +129,28 @@ async function generateDeclarations(options) {
131
129
  }
132
130
  selectorCache.set(cacheKey, selectorMap);
133
131
  }
134
- const variant = (0, loaderInternals_js_1.determineSelectorVariant)(query);
135
- const declaration = formatModuleDeclaration(cleaned, variant, selectorMap);
136
- const declarationHash = hashContent(declaration);
137
- const fileName = buildDeclarationFileName(cleaned);
138
- const targetPath = node_path_1.default.join(options.outDir, fileName);
139
- const previousEntry = previousManifest[cleaned];
140
- const needsWrite = previousEntry?.hash !== declarationHash || !(await fileExists(targetPath));
141
- if (needsWrite) {
142
- await promises_1.default.writeFile(targetPath, declaration, 'utf8');
143
- writes += 1;
132
+ if (!isWithinRoot(resolvedPath, options.rootDir)) {
133
+ warnings.push(`Skipping selector module for ${relativeToRoot(resolvedPath, options.rootDir)} because it is outside the project root.`);
134
+ continue;
135
+ }
136
+ const manifestKey = buildSelectorModuleManifestKey(resolvedPath);
137
+ if (processedSelectors.has(manifestKey)) {
138
+ continue;
144
139
  }
145
- nextManifest[cleaned] = { file: fileName, hash: declarationHash };
146
- if (needsWrite) {
147
- declarations.push({ specifier: cleaned, filePath: targetPath });
140
+ const moduleWrite = await ensureSelectorModule(resolvedPath, selectorMap, previousSelectorManifest, nextSelectorManifest);
141
+ if (moduleWrite) {
142
+ selectorModuleWrites += 1;
148
143
  }
149
- processedSpecifiers.add(cleaned);
144
+ processedSelectors.add(manifestKey);
150
145
  }
151
146
  }
152
- const removed = await removeStaleDeclarations(previousManifest, nextManifest, options.outDir);
153
- await writeManifest(manifestPath, nextManifest);
154
- const typesIndexPath = node_path_1.default.join(options.typesRoot, 'index.d.ts');
155
- await writeTypesIndex(typesIndexPath, nextManifest, options.outDir);
156
- if (Object.keys(nextManifest).length === 0) {
157
- declarations.length = 0;
158
- }
147
+ const selectorModulesRemoved = await removeStaleSelectorModules(previousSelectorManifest, nextSelectorManifest);
148
+ await writeManifest(selectorModulesManifestPath, nextSelectorManifest);
159
149
  return {
160
- written: writes,
161
- removed,
162
- declarations,
150
+ selectorModulesWritten: selectorModuleWrites,
151
+ selectorModulesRemoved,
163
152
  warnings,
164
- outDir: options.outDir,
165
- typesIndexPath,
153
+ manifestPath: selectorModulesManifestPath,
166
154
  };
167
155
  }
168
156
  function normalizeIncludeOptions(include, rootDir) {
@@ -220,18 +208,18 @@ async function findSpecifierImports(filePath) {
220
208
  catch {
221
209
  return [];
222
210
  }
223
- if (!source.includes('?knighted-css')) {
211
+ if (!source.includes(SELECTOR_REFERENCE)) {
224
212
  return [];
225
213
  }
226
214
  const matches = [];
227
215
  const [imports] = (0, es_module_lexer_1.parse)(source, filePath);
228
216
  for (const record of imports) {
229
217
  const specifier = record.n ?? source.slice(record.s, record.e);
230
- if (specifier && specifier.includes('?knighted-css')) {
218
+ if (specifier && specifier.includes(SELECTOR_REFERENCE)) {
231
219
  matches.push({ specifier, importer: filePath });
232
220
  }
233
221
  }
234
- const requireRegex = /require\((['"])([^'"`]+?\?knighted-css[^'"`]*)\1\)/g;
222
+ const requireRegex = /require\((['"])([^'"`]+?\.knighted-css[^'"`]*)\1\)/g;
235
223
  let reqMatch;
236
224
  while ((reqMatch = requireRegex.exec(source)) !== null) {
237
225
  const spec = reqMatch[2];
@@ -254,8 +242,23 @@ function splitResourceAndQuery(specifier) {
254
242
  }
255
243
  return { resource: trimmed.slice(0, queryIndex), query: trimmed.slice(queryIndex) };
256
244
  }
245
+ function extractSelectorSourceSpecifier(specifier) {
246
+ const markerIndex = specifier.indexOf(SELECTOR_REFERENCE);
247
+ if (markerIndex < 0) {
248
+ return undefined;
249
+ }
250
+ const suffix = specifier.slice(markerIndex + SELECTOR_REFERENCE.length);
251
+ if (suffix.length > 0 && !/\.(?:[cm]?[tj]s|[tj]sx)$/.test(suffix)) {
252
+ return undefined;
253
+ }
254
+ const base = specifier.slice(0, markerIndex);
255
+ if (!base) {
256
+ return undefined;
257
+ }
258
+ return base;
259
+ }
257
260
  const projectRequireCache = new Map();
258
- async function resolveImportPath(resourceSpecifier, importerPath, rootDir) {
261
+ async function resolveImportPath(resourceSpecifier, importerPath, rootDir, tsconfig) {
259
262
  if (!resourceSpecifier)
260
263
  return undefined;
261
264
  if (resourceSpecifier.startsWith('.')) {
@@ -264,6 +267,10 @@ async function resolveImportPath(resourceSpecifier, importerPath, rootDir) {
264
267
  if (resourceSpecifier.startsWith('/')) {
265
268
  return node_path_1.default.resolve(rootDir, resourceSpecifier.slice(1));
266
269
  }
270
+ const tsconfigResolved = await resolveWithTsconfigPaths(resourceSpecifier, tsconfig);
271
+ if (tsconfigResolved) {
272
+ return tsconfigResolved;
273
+ }
267
274
  const requireFromRoot = getProjectRequire(rootDir);
268
275
  try {
269
276
  return requireFromRoot.resolve(resourceSpecifier);
@@ -272,47 +279,29 @@ async function resolveImportPath(resourceSpecifier, importerPath, rootDir) {
272
279
  return undefined;
273
280
  }
274
281
  }
275
- function buildDeclarationFileName(specifier) {
276
- const digest = node_crypto_1.default.createHash('sha1').update(specifier).digest('hex').slice(0, 12);
277
- return `knt-${digest}.d.ts`;
278
- }
279
- function formatModuleDeclaration(specifier, variant, selectors) {
280
- const literalSpecifier = JSON.stringify(specifier);
281
- const selectorType = formatSelectorType(selectors);
282
- const header = `declare module ${literalSpecifier} {`;
283
- const footer = '}';
284
- if (variant === 'types') {
285
- return `${header}
286
- export const knightedCss: string
287
- export const stableSelectors: ${selectorType}
288
- ${footer}
289
- `;
290
- }
291
- const stableLine = ` export const stableSelectors: ${selectorType}`;
292
- const shared = ` const combined: KnightedCssCombinedModule<Record<string, unknown>>
293
- export const knightedCss: string
294
- ${stableLine}`;
295
- if (variant === 'combined') {
296
- return `${header}
297
- ${shared}
298
- export default combined
299
- ${footer}
300
- `;
301
- }
302
- return `${header}
303
- ${shared}
304
- ${footer}
305
- `;
282
+ function buildSelectorModuleManifestKey(resolvedPath) {
283
+ return resolvedPath.split(node_path_1.default.sep).join('/');
306
284
  }
307
- function formatSelectorType(selectors) {
308
- if (selectors.size === 0) {
309
- return 'Readonly<Record<string, string>>';
310
- }
285
+ function buildSelectorModulePath(resolvedPath) {
286
+ return `${resolvedPath}${SELECTOR_MODULE_SUFFIX}`;
287
+ }
288
+ function formatSelectorModuleSource(selectors) {
289
+ const header = '// Generated by @knighted/css/generate-types\n// Do not edit.\n';
311
290
  const entries = Array.from(selectors.entries()).sort(([a], [b]) => a.localeCompare(b));
312
- const lines = entries.map(([token, selector]) => ` readonly ${JSON.stringify(token)}: ${JSON.stringify(selector)}`);
313
- return `Readonly<{
291
+ const lines = entries.map(([token, selector]) => ` ${JSON.stringify(token)}: ${JSON.stringify(selector)},`);
292
+ const literal = lines.length > 0
293
+ ? `{
314
294
  ${lines.join('\n')}
315
- }>`;
295
+ } as const`
296
+ : '{} as const';
297
+ return `${header}
298
+ export const stableSelectors = ${literal}
299
+
300
+ export type KnightedCssStableSelectors = typeof stableSelectors
301
+ export type KnightedCssStableSelectorToken = keyof typeof stableSelectors
302
+
303
+ export default stableSelectors
304
+ `;
316
305
  }
317
306
  function hashContent(content) {
318
307
  return node_crypto_1.default.createHash('sha1').update(content).digest('hex');
@@ -329,13 +318,12 @@ async function readManifest(manifestPath) {
329
318
  async function writeManifest(manifestPath, manifest) {
330
319
  await promises_1.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
331
320
  }
332
- async function removeStaleDeclarations(previous, next, outDir) {
333
- const stale = Object.entries(previous).filter(([specifier]) => !next[specifier]);
321
+ async function removeStaleSelectorModules(previous, next) {
322
+ const stale = Object.entries(previous).filter(([key]) => !next[key]);
334
323
  let removed = 0;
335
324
  for (const [, entry] of stale) {
336
- const targetPath = node_path_1.default.join(outDir, entry.file);
337
325
  try {
338
- await promises_1.default.unlink(targetPath);
326
+ await promises_1.default.unlink(entry.file);
339
327
  removed += 1;
340
328
  }
341
329
  catch {
@@ -344,25 +332,6 @@ async function removeStaleDeclarations(previous, next, outDir) {
344
332
  }
345
333
  return removed;
346
334
  }
347
- async function writeTypesIndex(indexPath, manifest, outDir) {
348
- const header = '// Generated by @knighted/css/generate-types\n// Do not edit.\n';
349
- const references = Object.values(manifest)
350
- .sort((a, b) => a.file.localeCompare(b.file))
351
- .map(entry => {
352
- const rel = node_path_1.default
353
- .relative(node_path_1.default.dirname(indexPath), node_path_1.default.join(outDir, entry.file))
354
- .split(node_path_1.default.sep)
355
- .join('/');
356
- return `/// <reference path="${rel}" />`;
357
- });
358
- const content = references.length > 0
359
- ? `${header}
360
- ${references.join('\n')}
361
- `
362
- : `${header}
363
- `;
364
- await promises_1.default.writeFile(indexPath, content, 'utf8');
365
- }
366
335
  function formatErrorMessage(error) {
367
336
  if (error instanceof Error && typeof error.message === 'string') {
368
337
  return error.message;
@@ -372,6 +341,23 @@ function formatErrorMessage(error) {
372
341
  function relativeToRoot(filePath, rootDir) {
373
342
  return node_path_1.default.relative(rootDir, filePath) || filePath;
374
343
  }
344
+ function isWithinRoot(filePath, rootDir) {
345
+ const relative = node_path_1.default.relative(rootDir, filePath);
346
+ return relative === '' || (!relative.startsWith('..') && !node_path_1.default.isAbsolute(relative));
347
+ }
348
+ async function ensureSelectorModule(resolvedPath, selectors, previousManifest, nextManifest) {
349
+ const manifestKey = buildSelectorModuleManifestKey(resolvedPath);
350
+ const targetPath = buildSelectorModulePath(resolvedPath);
351
+ const source = formatSelectorModuleSource(selectors);
352
+ const hash = hashContent(source);
353
+ const previousEntry = previousManifest[manifestKey];
354
+ const needsWrite = previousEntry?.hash !== hash || !(await fileExists(targetPath));
355
+ if (needsWrite) {
356
+ await promises_1.default.writeFile(targetPath, source, 'utf8');
357
+ }
358
+ nextManifest[manifestKey] = { file: targetPath, hash };
359
+ return needsWrite;
360
+ }
375
361
  async function fileExists(target) {
376
362
  try {
377
363
  await promises_1.default.access(target);
@@ -381,6 +367,78 @@ async function fileExists(target) {
381
367
  return false;
382
368
  }
383
369
  }
370
+ async function resolveWithTsconfigPaths(specifier, tsconfig) {
371
+ if (!tsconfig) {
372
+ return undefined;
373
+ }
374
+ if (tsconfig.matchPath) {
375
+ const matched = tsconfig.matchPath(specifier);
376
+ if (matched && (await fileExists(matched))) {
377
+ return matched;
378
+ }
379
+ }
380
+ if (tsconfig.absoluteBaseUrl && isNonRelativeSpecifier(specifier)) {
381
+ const candidate = node_path_1.default.join(tsconfig.absoluteBaseUrl, specifier.split('/').join(node_path_1.default.sep));
382
+ if (await fileExists(candidate)) {
383
+ return candidate;
384
+ }
385
+ }
386
+ return undefined;
387
+ }
388
+ function loadTsconfigResolutionContext(rootDir, loader = get_tsconfig_1.getTsconfig) {
389
+ let result;
390
+ try {
391
+ result = loader(rootDir);
392
+ }
393
+ catch {
394
+ return undefined;
395
+ }
396
+ if (!result) {
397
+ return undefined;
398
+ }
399
+ const compilerOptions = result.config.compilerOptions ?? {};
400
+ const configDir = node_path_1.default.dirname(result.path);
401
+ const absoluteBaseUrl = compilerOptions.baseUrl
402
+ ? node_path_1.default.resolve(configDir, compilerOptions.baseUrl)
403
+ : undefined;
404
+ const normalizedPaths = normalizeTsconfigPaths(compilerOptions.paths);
405
+ const matchPath = absoluteBaseUrl && normalizedPaths
406
+ ? (0, tsconfig_paths_1.createMatchPath)(absoluteBaseUrl, normalizedPaths)
407
+ : undefined;
408
+ if (!absoluteBaseUrl && !matchPath) {
409
+ return undefined;
410
+ }
411
+ return { absoluteBaseUrl, matchPath };
412
+ }
413
+ function normalizeTsconfigPaths(paths) {
414
+ if (!paths) {
415
+ return undefined;
416
+ }
417
+ const normalized = {};
418
+ for (const [pattern, replacements] of Object.entries(paths)) {
419
+ if (!replacements) {
420
+ continue;
421
+ }
422
+ const values = Array.isArray(replacements) ? replacements : [replacements];
423
+ if (values.length === 0) {
424
+ continue;
425
+ }
426
+ normalized[pattern] = values;
427
+ }
428
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
429
+ }
430
+ function isNonRelativeSpecifier(specifier) {
431
+ if (!specifier) {
432
+ return false;
433
+ }
434
+ if (specifier.startsWith('.') || specifier.startsWith('/')) {
435
+ return false;
436
+ }
437
+ if (/^[a-z][\w+.-]*:/i.test(specifier)) {
438
+ return false;
439
+ }
440
+ return true;
441
+ }
384
442
  function createProjectPeerResolver(rootDir) {
385
443
  const resolver = getProjectRequire(rootDir);
386
444
  return async (name) => {
@@ -423,7 +481,6 @@ async function runGenerateTypesCli(argv = process.argv.slice(2)) {
423
481
  rootDir: parsed.rootDir,
424
482
  include: parsed.include,
425
483
  outDir: parsed.outDir,
426
- typesRoot: parsed.typesRoot,
427
484
  stableNamespace: parsed.stableNamespace,
428
485
  });
429
486
  reportCliResult(result);
@@ -438,12 +495,11 @@ function parseCliArgs(argv) {
438
495
  let rootDir = process.cwd();
439
496
  const include = [];
440
497
  let outDir;
441
- let typesRoot;
442
498
  let stableNamespace;
443
499
  for (let i = 0; i < argv.length; i += 1) {
444
500
  const arg = argv[i];
445
501
  if (arg === '--help' || arg === '-h') {
446
- return { rootDir, include, outDir, typesRoot, stableNamespace, help: true };
502
+ return { rootDir, include, outDir, stableNamespace, help: true };
447
503
  }
448
504
  if (arg === '--root' || arg === '-r') {
449
505
  const value = argv[++i];
@@ -469,14 +525,6 @@ function parseCliArgs(argv) {
469
525
  outDir = value;
470
526
  continue;
471
527
  }
472
- if (arg === '--types-root') {
473
- const value = argv[++i];
474
- if (!value) {
475
- throw new Error('Missing value for --types-root');
476
- }
477
- typesRoot = value;
478
- continue;
479
- }
480
528
  if (arg === '--stable-namespace') {
481
529
  const value = argv[++i];
482
530
  if (!value) {
@@ -490,7 +538,7 @@ function parseCliArgs(argv) {
490
538
  }
491
539
  include.push(arg);
492
540
  }
493
- return { rootDir, include, outDir, typesRoot, stableNamespace };
541
+ return { rootDir, include, outDir, stableNamespace };
494
542
  }
495
543
  function printHelp() {
496
544
  console.log(`Usage: knighted-css-generate-types [options]
@@ -498,32 +546,59 @@ function printHelp() {
498
546
  Options:
499
547
  -r, --root <path> Project root directory (default: cwd)
500
548
  -i, --include <path> Additional directories/files to scan (repeatable)
501
- --out-dir <path> Output directory for generated declarations
502
- --types-root <path> Directory for generated @types entrypoint
549
+ --out-dir <path> Directory to store selector module manifest cache
503
550
  --stable-namespace <name> Stable namespace prefix for generated selector maps
504
551
  -h, --help Show this help message
505
552
  `);
506
553
  }
507
554
  function reportCliResult(result) {
508
- if (result.written === 0 && result.removed === 0) {
509
- console.log('[knighted-css] No changes to ?knighted-css&types declarations (cache is up to date).');
555
+ if (result.selectorModulesWritten === 0 && result.selectorModulesRemoved === 0) {
556
+ console.log('[knighted-css] Selector modules are up to date.');
510
557
  }
511
558
  else {
512
- console.log(`[knighted-css] Updated ${result.written} declaration(s), removed ${result.removed}, output in ${result.outDir}.`);
559
+ console.log(`[knighted-css] Selector modules updated: wrote ${result.selectorModulesWritten}, removed ${result.selectorModulesRemoved}.`);
513
560
  }
514
- console.log(`[knighted-css] Type references: ${result.typesIndexPath}`);
561
+ console.log(`[knighted-css] Manifest: ${result.manifestPath}`);
515
562
  for (const warning of result.warnings) {
516
563
  console.warn(`[knighted-css] ${warning}`);
517
564
  }
518
565
  }
566
+ function setCssWithMetaImplementation(impl) {
567
+ activeCssWithMeta = impl ?? css_js_1.cssWithMeta;
568
+ }
569
+ function setModuleTypeDetector(detector) {
570
+ moduleTypeDetector = detector ?? node_module_type_1.moduleType;
571
+ }
572
+ function setImportMetaUrlProvider(provider) {
573
+ importMetaUrlProvider = provider ?? getImportMetaUrl;
574
+ }
519
575
  exports.__generateTypesInternals = {
520
576
  stripInlineLoader,
521
577
  splitResourceAndQuery,
522
- buildDeclarationFileName,
523
- formatModuleDeclaration,
524
- formatSelectorType,
578
+ extractSelectorSourceSpecifier,
579
+ findSpecifierImports,
580
+ resolveImportPath,
581
+ resolvePackageRoot,
582
+ relativeToRoot,
583
+ collectCandidateFiles,
525
584
  normalizeIncludeOptions,
585
+ normalizeTsconfigPaths,
586
+ setCssWithMetaImplementation,
587
+ setModuleTypeDetector,
588
+ setImportMetaUrlProvider,
589
+ isNonRelativeSpecifier,
590
+ createProjectPeerResolver,
591
+ getProjectRequire,
592
+ loadTsconfigResolutionContext,
593
+ resolveWithTsconfigPaths,
526
594
  parseCliArgs,
527
595
  printHelp,
528
596
  reportCliResult,
597
+ buildSelectorModuleManifestKey,
598
+ buildSelectorModulePath,
599
+ formatSelectorModuleSource,
600
+ ensureSelectorModule,
601
+ removeStaleSelectorModules,
602
+ readManifest,
603
+ writeManifest,
529
604
  };
@@ -1,54 +1,103 @@
1
- import { type SelectorTypeVariant } from './loaderInternals.cjs';
2
- interface DeclarationRecord {
1
+ import { createRequire } from 'node:module';
2
+ import { moduleType } from 'node-module-type';
3
+ import { getTsconfig } from 'get-tsconfig';
4
+ import { type MatchPath } from 'tsconfig-paths';
5
+ import { cssWithMeta } from './css.cjs';
6
+ interface ImportMatch {
3
7
  specifier: string;
4
- filePath: string;
8
+ importer: string;
5
9
  }
10
+ interface ManifestEntry {
11
+ file: string;
12
+ hash: string;
13
+ }
14
+ type SelectorModuleManifest = Record<string, ManifestEntry>;
15
+ interface TsconfigResolutionContext {
16
+ absoluteBaseUrl?: string;
17
+ matchPath?: MatchPath;
18
+ }
19
+ type CssWithMetaFn = typeof cssWithMeta;
6
20
  export interface GenerateTypesResult {
7
- written: number;
8
- removed: number;
9
- declarations: DeclarationRecord[];
21
+ selectorModulesWritten: number;
22
+ selectorModulesRemoved: number;
10
23
  warnings: string[];
11
- outDir: string;
12
- typesIndexPath: string;
24
+ manifestPath: string;
13
25
  }
14
26
  export interface GenerateTypesOptions {
15
27
  rootDir?: string;
16
28
  include?: string[];
17
29
  outDir?: string;
18
- typesRoot?: string;
19
30
  stableNamespace?: string;
20
31
  }
32
+ type ModuleTypeDetector = () => ReturnType<typeof moduleType>;
33
+ declare function resolvePackageRoot(): string;
21
34
  export declare function generateTypes(options?: GenerateTypesOptions): Promise<GenerateTypesResult>;
22
35
  declare function normalizeIncludeOptions(include: string[] | undefined, rootDir: string): string[];
36
+ declare function collectCandidateFiles(entries: string[]): Promise<string[]>;
37
+ declare function findSpecifierImports(filePath: string): Promise<ImportMatch[]>;
23
38
  declare function stripInlineLoader(specifier: string): string;
24
39
  declare function splitResourceAndQuery(specifier: string): {
25
40
  resource: string;
26
41
  query: string;
27
42
  };
28
- declare function buildDeclarationFileName(specifier: string): string;
29
- declare function formatModuleDeclaration(specifier: string, variant: SelectorTypeVariant, selectors: Map<string, string>): string;
30
- declare function formatSelectorType(selectors: Map<string, string>): string;
43
+ declare function extractSelectorSourceSpecifier(specifier: string): string | undefined;
44
+ declare function resolveImportPath(resourceSpecifier: string, importerPath: string, rootDir: string, tsconfig?: TsconfigResolutionContext): Promise<string | undefined>;
45
+ declare function buildSelectorModuleManifestKey(resolvedPath: string): string;
46
+ declare function buildSelectorModulePath(resolvedPath: string): string;
47
+ declare function formatSelectorModuleSource(selectors: Map<string, string>): string;
48
+ declare function readManifest(manifestPath: string): Promise<SelectorModuleManifest>;
49
+ declare function writeManifest(manifestPath: string, manifest: SelectorModuleManifest): Promise<void>;
50
+ declare function removeStaleSelectorModules(previous: SelectorModuleManifest, next: SelectorModuleManifest): Promise<number>;
51
+ declare function relativeToRoot(filePath: string, rootDir: string): string;
52
+ declare function ensureSelectorModule(resolvedPath: string, selectors: Map<string, string>, previousManifest: SelectorModuleManifest, nextManifest: SelectorModuleManifest): Promise<boolean>;
53
+ declare function resolveWithTsconfigPaths(specifier: string, tsconfig?: TsconfigResolutionContext): Promise<string | undefined>;
54
+ declare function loadTsconfigResolutionContext(rootDir: string, loader?: typeof getTsconfig): TsconfigResolutionContext | undefined;
55
+ declare function normalizeTsconfigPaths(paths: Record<string, string[] | string> | undefined): Record<string, string[]> | undefined;
56
+ declare function isNonRelativeSpecifier(specifier: string): boolean;
57
+ declare function createProjectPeerResolver(rootDir: string): (name: string) => Promise<any>;
58
+ declare function getProjectRequire(rootDir: string): ReturnType<typeof createRequire>;
31
59
  export declare function runGenerateTypesCli(argv?: string[]): Promise<void>;
32
60
  export interface ParsedCliArgs {
33
61
  rootDir: string;
34
62
  include?: string[];
35
63
  outDir?: string;
36
- typesRoot?: string;
37
64
  stableNamespace?: string;
38
65
  help?: boolean;
39
66
  }
40
67
  declare function parseCliArgs(argv: string[]): ParsedCliArgs;
41
68
  declare function printHelp(): void;
42
69
  declare function reportCliResult(result: GenerateTypesResult): void;
70
+ declare function setCssWithMetaImplementation(impl?: CssWithMetaFn): void;
71
+ declare function setModuleTypeDetector(detector?: ModuleTypeDetector): void;
72
+ declare function setImportMetaUrlProvider(provider?: () => string | undefined): void;
43
73
  export declare const __generateTypesInternals: {
44
74
  stripInlineLoader: typeof stripInlineLoader;
45
75
  splitResourceAndQuery: typeof splitResourceAndQuery;
46
- buildDeclarationFileName: typeof buildDeclarationFileName;
47
- formatModuleDeclaration: typeof formatModuleDeclaration;
48
- formatSelectorType: typeof formatSelectorType;
76
+ extractSelectorSourceSpecifier: typeof extractSelectorSourceSpecifier;
77
+ findSpecifierImports: typeof findSpecifierImports;
78
+ resolveImportPath: typeof resolveImportPath;
79
+ resolvePackageRoot: typeof resolvePackageRoot;
80
+ relativeToRoot: typeof relativeToRoot;
81
+ collectCandidateFiles: typeof collectCandidateFiles;
49
82
  normalizeIncludeOptions: typeof normalizeIncludeOptions;
83
+ normalizeTsconfigPaths: typeof normalizeTsconfigPaths;
84
+ setCssWithMetaImplementation: typeof setCssWithMetaImplementation;
85
+ setModuleTypeDetector: typeof setModuleTypeDetector;
86
+ setImportMetaUrlProvider: typeof setImportMetaUrlProvider;
87
+ isNonRelativeSpecifier: typeof isNonRelativeSpecifier;
88
+ createProjectPeerResolver: typeof createProjectPeerResolver;
89
+ getProjectRequire: typeof getProjectRequire;
90
+ loadTsconfigResolutionContext: typeof loadTsconfigResolutionContext;
91
+ resolveWithTsconfigPaths: typeof resolveWithTsconfigPaths;
50
92
  parseCliArgs: typeof parseCliArgs;
51
93
  printHelp: typeof printHelp;
52
94
  reportCliResult: typeof reportCliResult;
95
+ buildSelectorModuleManifestKey: typeof buildSelectorModuleManifestKey;
96
+ buildSelectorModulePath: typeof buildSelectorModulePath;
97
+ formatSelectorModuleSource: typeof formatSelectorModuleSource;
98
+ ensureSelectorModule: typeof ensureSelectorModule;
99
+ removeStaleSelectorModules: typeof removeStaleSelectorModules;
100
+ readManifest: typeof readManifest;
101
+ writeManifest: typeof writeManifest;
53
102
  };
54
103
  export {};
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asKnightedCssCombinedModule = asKnightedCssCombinedModule;
4
+ function asKnightedCssCombinedModule(module) {
5
+ return module;
6
+ }