@knighted/css 1.1.1 → 1.2.0-rc.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.
- package/README.md +49 -2
- package/dist/cjs/generateTypes.cjs +340 -38
- package/dist/cjs/generateTypes.cjs.map +1 -1
- package/dist/cjs/generateTypes.d.cts +33 -0
- package/dist/cjs/lexer.cjs +64 -2
- package/dist/cjs/lexer.cjs.map +1 -1
- package/dist/cjs/lexer.d.cts +1 -0
- package/dist/cjs/plugin.cjs +485 -0
- package/dist/cjs/plugin.cjs.map +1 -0
- package/dist/cjs/plugin.d.cts +135 -0
- package/dist/generateTypes.d.ts +33 -0
- package/dist/generateTypes.js +340 -38
- package/dist/generateTypes.js.map +1 -1
- package/dist/lexer.d.ts +1 -0
- package/dist/lexer.js +64 -2
- package/dist/lexer.js.map +1 -1
- package/dist/plugin.d.ts +135 -0
- package/dist/plugin.js +477 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +9 -2
package/dist/generateTypes.js
CHANGED
|
@@ -58,6 +58,7 @@ function getImportMetaUrl() {
|
|
|
58
58
|
}
|
|
59
59
|
const SELECTOR_REFERENCE = '.knighted-css';
|
|
60
60
|
const SELECTOR_MODULE_SUFFIX = '.knighted-css.ts';
|
|
61
|
+
const DECLARATION_SUFFIX = '.d.ts';
|
|
61
62
|
const STYLE_EXTENSIONS = DEFAULT_EXTENSIONS.map(ext => ext.toLowerCase());
|
|
62
63
|
const SCRIPT_EXTENSIONS = Array.from(SUPPORTED_EXTENSIONS);
|
|
63
64
|
const RESOLUTION_EXTENSIONS = Array.from(new Set([...SCRIPT_EXTENSIONS, ...STYLE_EXTENSIONS]));
|
|
@@ -67,11 +68,16 @@ const EXTENSION_FALLBACKS = {
|
|
|
67
68
|
'.cjs': ['.cts', '.cjs', '.js', '.ts', '.tsx'],
|
|
68
69
|
'.jsx': ['.tsx', '.jsx'],
|
|
69
70
|
};
|
|
71
|
+
const DECLARATION_MODE_WARNING = 'Declaration mode requires a resolver plugin to append ?knighted-css (and &combined when applicable) so runtime exports match the generated types.';
|
|
70
72
|
export async function generateTypes(options = {}) {
|
|
71
73
|
const rootDir = await resolveRootDir(path.resolve(options.rootDir ?? process.cwd()));
|
|
72
74
|
const include = normalizeIncludeOptions(options.include, rootDir);
|
|
73
75
|
const cacheDir = path.resolve(options.outDir ?? path.join(rootDir, '.knighted-css'));
|
|
74
76
|
const tsconfig = loadTsconfigResolutionContext(rootDir);
|
|
77
|
+
const mode = options.mode ?? 'module';
|
|
78
|
+
const manifestPath = options.manifestPath
|
|
79
|
+
? path.resolve(rootDir, options.manifestPath)
|
|
80
|
+
: undefined;
|
|
75
81
|
await fs.mkdir(cacheDir, { recursive: true });
|
|
76
82
|
const internalOptions = {
|
|
77
83
|
rootDir,
|
|
@@ -82,6 +88,8 @@ export async function generateTypes(options = {}) {
|
|
|
82
88
|
hashed: options.hashed,
|
|
83
89
|
tsconfig,
|
|
84
90
|
resolver: options.resolver,
|
|
91
|
+
mode,
|
|
92
|
+
manifestPath,
|
|
85
93
|
};
|
|
86
94
|
return generateDeclarations(internalOptions);
|
|
87
95
|
}
|
|
@@ -100,79 +108,176 @@ async function generateDeclarations(options) {
|
|
|
100
108
|
const selectorModulesManifestPath = path.join(options.cacheDir, 'selector-modules.json');
|
|
101
109
|
const previousSelectorManifest = await readManifest(selectorModulesManifestPath);
|
|
102
110
|
const nextSelectorManifest = {};
|
|
111
|
+
const sidecarManifest = {};
|
|
103
112
|
const selectorCache = new Map();
|
|
104
113
|
const processedSelectors = new Set();
|
|
105
114
|
const proxyInfoCache = new Map();
|
|
106
115
|
const warnings = [];
|
|
107
116
|
let selectorModuleWrites = 0;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const selectorSource = extractSelectorSourceSpecifier(resource);
|
|
115
|
-
if (!selectorSource) {
|
|
117
|
+
if (options.mode === 'declaration') {
|
|
118
|
+
warnings.push(DECLARATION_MODE_WARNING);
|
|
119
|
+
}
|
|
120
|
+
if (options.mode === 'declaration') {
|
|
121
|
+
for (const filePath of files) {
|
|
122
|
+
if (!isScriptResource(filePath)) {
|
|
116
123
|
continue;
|
|
117
124
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
if (!isWithinRoot(filePath, options.rootDir)) {
|
|
126
|
+
warnings.push(`Skipping declaration output for ${relativeToRoot(filePath, options.rootDir)} because it is outside the project root.`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const manifestKey = buildSelectorModuleManifestKey(filePath);
|
|
130
|
+
if (processedSelectors.has(manifestKey)) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const hasStyles = await hasStyleImports(filePath, {
|
|
134
|
+
rootDir: options.rootDir,
|
|
135
|
+
tsconfig: options.tsconfig,
|
|
136
|
+
resolver: options.resolver,
|
|
137
|
+
resolverFactory,
|
|
138
|
+
});
|
|
139
|
+
if (!hasStyles) {
|
|
140
|
+
processedSelectors.add(manifestKey);
|
|
122
141
|
continue;
|
|
123
142
|
}
|
|
124
|
-
const
|
|
143
|
+
const resolvedNamespace = resolveStableNamespace(options.stableNamespace);
|
|
144
|
+
const cacheKey = `${filePath}::${resolvedNamespace}::declaration`;
|
|
125
145
|
let selectorMap = selectorCache.get(cacheKey);
|
|
126
146
|
if (!selectorMap) {
|
|
127
147
|
try {
|
|
128
|
-
|
|
129
|
-
const { css } = await activeCssWithMeta(resolvedPath, {
|
|
148
|
+
let cssResult = await activeCssWithMeta(filePath, {
|
|
130
149
|
cwd: options.rootDir,
|
|
131
150
|
peerResolver,
|
|
132
151
|
autoStable: options.autoStable ? { namespace: resolvedNamespace } : undefined,
|
|
133
|
-
lightningcss: options.autoStable && shouldUseCssModules
|
|
134
|
-
? { cssModules: true }
|
|
135
|
-
: undefined,
|
|
136
152
|
resolver: options.resolver,
|
|
137
153
|
});
|
|
154
|
+
if (cssResult.files.length === 0 || cssResult.css.trim().length === 0) {
|
|
155
|
+
processedSelectors.add(manifestKey);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (options.autoStable &&
|
|
159
|
+
cssResult.files.some(file => isCssModuleResource(file))) {
|
|
160
|
+
cssResult = await activeCssWithMeta(filePath, {
|
|
161
|
+
cwd: options.rootDir,
|
|
162
|
+
peerResolver,
|
|
163
|
+
autoStable: options.autoStable
|
|
164
|
+
? { namespace: resolvedNamespace }
|
|
165
|
+
: undefined,
|
|
166
|
+
lightningcss: { cssModules: true },
|
|
167
|
+
resolver: options.resolver,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
138
170
|
selectorMap = options.hashed
|
|
139
|
-
? collectSelectorTokensFromCss(css)
|
|
171
|
+
? collectSelectorTokensFromCss(cssResult.css)
|
|
140
172
|
: buildStableSelectorsLiteral({
|
|
141
|
-
css,
|
|
173
|
+
css: cssResult.css,
|
|
142
174
|
namespace: resolvedNamespace,
|
|
143
|
-
resourcePath:
|
|
175
|
+
resourcePath: filePath,
|
|
144
176
|
emitWarning: message => warnings.push(message),
|
|
145
177
|
}).selectorMap;
|
|
146
178
|
}
|
|
147
179
|
catch (error) {
|
|
148
|
-
warnings.push(`Failed to extract CSS for ${relativeToRoot(
|
|
180
|
+
warnings.push(`Failed to extract CSS for ${relativeToRoot(filePath, options.rootDir)}: ${formatErrorMessage(error)}`);
|
|
181
|
+
processedSelectors.add(manifestKey);
|
|
149
182
|
continue;
|
|
150
183
|
}
|
|
151
184
|
selectorCache.set(cacheKey, selectorMap);
|
|
152
185
|
}
|
|
153
|
-
if (!
|
|
154
|
-
|
|
186
|
+
if (!selectorMap || selectorMap.size === 0) {
|
|
187
|
+
processedSelectors.add(manifestKey);
|
|
155
188
|
continue;
|
|
156
189
|
}
|
|
157
|
-
const
|
|
158
|
-
if (
|
|
190
|
+
const proxyInfo = await resolveDeclarationProxyInfo(manifestKey, filePath, proxyInfoCache);
|
|
191
|
+
if (!proxyInfo) {
|
|
192
|
+
processedSelectors.add(manifestKey);
|
|
159
193
|
continue;
|
|
160
194
|
}
|
|
161
|
-
const
|
|
162
|
-
|
|
195
|
+
const moduleWrite = await ensureDeclarationModule(filePath, selectorMap, previousSelectorManifest, nextSelectorManifest, proxyInfo, options.hashed ?? false);
|
|
196
|
+
if (options.manifestPath) {
|
|
197
|
+
sidecarManifest[manifestKey] = { file: buildDeclarationPath(filePath) };
|
|
198
|
+
}
|
|
163
199
|
if (moduleWrite) {
|
|
164
200
|
selectorModuleWrites += 1;
|
|
165
201
|
}
|
|
166
202
|
processedSelectors.add(manifestKey);
|
|
167
203
|
}
|
|
168
204
|
}
|
|
205
|
+
else {
|
|
206
|
+
for (const filePath of files) {
|
|
207
|
+
const matches = await findSpecifierImports(filePath);
|
|
208
|
+
for (const match of matches) {
|
|
209
|
+
const cleaned = match.specifier.trim();
|
|
210
|
+
const inlineFree = stripInlineLoader(cleaned);
|
|
211
|
+
const { resource } = splitResourceAndQuery(inlineFree);
|
|
212
|
+
const selectorSource = extractSelectorSourceSpecifier(resource);
|
|
213
|
+
if (!selectorSource) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const resolvedNamespace = resolveStableNamespace(options.stableNamespace);
|
|
217
|
+
const resolvedPath = await resolveImportPath(selectorSource, match.importer, options.rootDir, options.tsconfig, options.resolver, resolverFactory, RESOLUTION_EXTENSIONS);
|
|
218
|
+
if (!resolvedPath) {
|
|
219
|
+
warnings.push(`Unable to resolve ${selectorSource} referenced by ${relativeToRoot(match.importer, options.rootDir)}.`);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const cacheKey = `${resolvedPath}::${resolvedNamespace}`;
|
|
223
|
+
let selectorMap = selectorCache.get(cacheKey);
|
|
224
|
+
if (!selectorMap) {
|
|
225
|
+
try {
|
|
226
|
+
const shouldUseCssModules = resolvedPath.endsWith('.module.css');
|
|
227
|
+
const { css } = await activeCssWithMeta(resolvedPath, {
|
|
228
|
+
cwd: options.rootDir,
|
|
229
|
+
peerResolver,
|
|
230
|
+
autoStable: options.autoStable
|
|
231
|
+
? { namespace: resolvedNamespace }
|
|
232
|
+
: undefined,
|
|
233
|
+
lightningcss: options.autoStable && shouldUseCssModules
|
|
234
|
+
? { cssModules: true }
|
|
235
|
+
: undefined,
|
|
236
|
+
resolver: options.resolver,
|
|
237
|
+
});
|
|
238
|
+
selectorMap = options.hashed
|
|
239
|
+
? collectSelectorTokensFromCss(css)
|
|
240
|
+
: buildStableSelectorsLiteral({
|
|
241
|
+
css,
|
|
242
|
+
namespace: resolvedNamespace,
|
|
243
|
+
resourcePath: resolvedPath,
|
|
244
|
+
emitWarning: message => warnings.push(message),
|
|
245
|
+
}).selectorMap;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
warnings.push(`Failed to extract CSS for ${relativeToRoot(resolvedPath, options.rootDir)}: ${formatErrorMessage(error)}`);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
selectorCache.set(cacheKey, selectorMap);
|
|
252
|
+
}
|
|
253
|
+
if (!isWithinRoot(resolvedPath, options.rootDir)) {
|
|
254
|
+
warnings.push(`Skipping selector module for ${relativeToRoot(resolvedPath, options.rootDir)} because it is outside the project root.`);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const manifestKey = buildSelectorModuleManifestKey(resolvedPath);
|
|
258
|
+
if (processedSelectors.has(manifestKey)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const proxyInfo = await resolveProxyInfo(manifestKey, selectorSource, resolvedPath, proxyInfoCache);
|
|
262
|
+
const moduleWrite = await ensureSelectorModule(resolvedPath, selectorMap, previousSelectorManifest, nextSelectorManifest, selectorSource, proxyInfo ?? undefined, options.hashed ?? false);
|
|
263
|
+
if (moduleWrite) {
|
|
264
|
+
selectorModuleWrites += 1;
|
|
265
|
+
}
|
|
266
|
+
processedSelectors.add(manifestKey);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
169
270
|
const selectorModulesRemoved = await removeStaleSelectorModules(previousSelectorManifest, nextSelectorManifest);
|
|
170
271
|
await writeManifest(selectorModulesManifestPath, nextSelectorManifest);
|
|
272
|
+
if (options.manifestPath && options.mode === 'declaration') {
|
|
273
|
+
await writeSidecarManifest(options.manifestPath, sidecarManifest);
|
|
274
|
+
}
|
|
171
275
|
return {
|
|
172
276
|
selectorModulesWritten: selectorModuleWrites,
|
|
173
277
|
selectorModulesRemoved,
|
|
174
278
|
warnings,
|
|
175
279
|
manifestPath: selectorModulesManifestPath,
|
|
280
|
+
sidecarManifestPath: options.mode === 'declaration' ? options.manifestPath : undefined,
|
|
176
281
|
};
|
|
177
282
|
}
|
|
178
283
|
function normalizeIncludeOptions(include, rootDir) {
|
|
@@ -351,6 +456,50 @@ function buildSelectorModulePath(resolvedPath) {
|
|
|
351
456
|
const base = ext ? resolvedPath.slice(0, -ext.length) : resolvedPath;
|
|
352
457
|
return `${base}${SELECTOR_MODULE_SUFFIX}`;
|
|
353
458
|
}
|
|
459
|
+
function buildDeclarationModuleSpecifier(resolvedPath) {
|
|
460
|
+
const ext = path.extname(resolvedPath).toLowerCase();
|
|
461
|
+
const baseName = path.basename(resolvedPath, ext);
|
|
462
|
+
const mappedExt = ext === '.mjs' || ext === '.mts'
|
|
463
|
+
? '.mjs'
|
|
464
|
+
: ext === '.cjs' || ext === '.cts'
|
|
465
|
+
? '.cjs'
|
|
466
|
+
: '.js';
|
|
467
|
+
return `./${baseName}${mappedExt}`;
|
|
468
|
+
}
|
|
469
|
+
function buildDeclarationPath(resolvedPath) {
|
|
470
|
+
if (resolvedPath.endsWith(DECLARATION_SUFFIX)) {
|
|
471
|
+
return resolvedPath;
|
|
472
|
+
}
|
|
473
|
+
return `${resolvedPath}${DECLARATION_SUFFIX}`;
|
|
474
|
+
}
|
|
475
|
+
function formatSelectorTypeLiteral(selectors) {
|
|
476
|
+
const entries = Array.from(selectors.keys()).sort((a, b) => a.localeCompare(b));
|
|
477
|
+
const typeLines = entries.map(token => ` readonly ${JSON.stringify(token)}: string`);
|
|
478
|
+
return typeLines.length > 0
|
|
479
|
+
? `{
|
|
480
|
+
${typeLines.join('\n')}
|
|
481
|
+
}`
|
|
482
|
+
: 'Record<string, string>';
|
|
483
|
+
}
|
|
484
|
+
function formatDeclarationSource(selectors, proxyInfo, options = {}) {
|
|
485
|
+
const header = '// Generated by @knighted/css/generate-types\n// Do not edit.';
|
|
486
|
+
const isHashed = options.hashed === true;
|
|
487
|
+
const marker = isHashed ? '// @knighted-css:hashed' : '// @knighted-css';
|
|
488
|
+
const exportName = isHashed ? 'selectors' : 'stableSelectors';
|
|
489
|
+
const typeLiteral = formatSelectorTypeLiteral(selectors);
|
|
490
|
+
const shouldEmit = (name) => !proxyInfo.exportedNames?.has(name);
|
|
491
|
+
const lines = [
|
|
492
|
+
header,
|
|
493
|
+
marker,
|
|
494
|
+
'',
|
|
495
|
+
`declare module '${proxyInfo.moduleSpecifier}' {`,
|
|
496
|
+
shouldEmit('knightedCss') ? ' export const knightedCss: string' : '',
|
|
497
|
+
shouldEmit(exportName) ? ` export const ${exportName}: ${typeLiteral}` : '',
|
|
498
|
+
'}',
|
|
499
|
+
'export {}',
|
|
500
|
+
].filter(Boolean);
|
|
501
|
+
return `${lines.join('\n')}\n`;
|
|
502
|
+
}
|
|
354
503
|
function formatSelectorModuleSource(selectors, proxyInfo, options = {}) {
|
|
355
504
|
const header = '// Generated by @knighted/css/generate-types\n// Do not edit.';
|
|
356
505
|
const entries = Array.from(selectors.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
@@ -428,6 +577,10 @@ async function readManifest(manifestPath) {
|
|
|
428
577
|
async function writeManifest(manifestPath, manifest) {
|
|
429
578
|
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
430
579
|
}
|
|
580
|
+
async function writeSidecarManifest(manifestPath, manifest) {
|
|
581
|
+
await fs.mkdir(path.dirname(manifestPath), { recursive: true });
|
|
582
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
583
|
+
}
|
|
431
584
|
async function removeStaleSelectorModules(previous, next) {
|
|
432
585
|
const stale = Object.entries(previous).filter(([key]) => !next[key]);
|
|
433
586
|
let removed = 0;
|
|
@@ -472,6 +625,19 @@ async function ensureSelectorModule(resolvedPath, selectors, previousManifest, n
|
|
|
472
625
|
nextManifest[manifestKey] = { file: targetPath, hash };
|
|
473
626
|
return needsWrite;
|
|
474
627
|
}
|
|
628
|
+
async function ensureDeclarationModule(resolvedPath, selectors, previousManifest, nextManifest, proxyInfo, hashed) {
|
|
629
|
+
const manifestKey = buildSelectorModuleManifestKey(resolvedPath);
|
|
630
|
+
const targetPath = buildDeclarationPath(resolvedPath);
|
|
631
|
+
const source = formatDeclarationSource(selectors, proxyInfo, { hashed });
|
|
632
|
+
const hash = hashContent(source);
|
|
633
|
+
const previousEntry = previousManifest[manifestKey];
|
|
634
|
+
const needsWrite = previousEntry?.hash !== hash || !(await fileExists(targetPath));
|
|
635
|
+
if (needsWrite) {
|
|
636
|
+
await fs.writeFile(targetPath, source, 'utf8');
|
|
637
|
+
}
|
|
638
|
+
nextManifest[manifestKey] = { file: targetPath, hash };
|
|
639
|
+
return needsWrite;
|
|
640
|
+
}
|
|
475
641
|
async function fileExists(target) {
|
|
476
642
|
try {
|
|
477
643
|
await fs.access(target);
|
|
@@ -613,6 +779,60 @@ function isStyleResource(filePath) {
|
|
|
613
779
|
const normalized = filePath.toLowerCase();
|
|
614
780
|
return STYLE_EXTENSIONS.some(ext => normalized.endsWith(ext));
|
|
615
781
|
}
|
|
782
|
+
function isCssModuleResource(filePath) {
|
|
783
|
+
return /\.module\.(css|scss|sass|less)$/i.test(filePath);
|
|
784
|
+
}
|
|
785
|
+
function isScriptResource(filePath) {
|
|
786
|
+
const normalized = filePath.toLowerCase();
|
|
787
|
+
if (normalized.endsWith('.d.ts')) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
return SCRIPT_EXTENSIONS.some(ext => normalized.endsWith(ext));
|
|
791
|
+
}
|
|
792
|
+
async function hasStyleImports(filePath, options) {
|
|
793
|
+
let source;
|
|
794
|
+
try {
|
|
795
|
+
source = await fs.readFile(filePath, 'utf8');
|
|
796
|
+
}
|
|
797
|
+
catch {
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
const candidates = new Set();
|
|
801
|
+
try {
|
|
802
|
+
const analysis = await analyzeModule(source, filePath);
|
|
803
|
+
for (const specifier of analysis.imports) {
|
|
804
|
+
if (specifier) {
|
|
805
|
+
candidates.add(specifier);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
catch {
|
|
810
|
+
// fall back to regex scanning below
|
|
811
|
+
}
|
|
812
|
+
const importRegex = /(import|require)\s*(?:\(|[^'"`]*)(['"])([^'"`]+)\2/g;
|
|
813
|
+
let match;
|
|
814
|
+
while ((match = importRegex.exec(source)) !== null) {
|
|
815
|
+
const specifier = match[3];
|
|
816
|
+
if (specifier) {
|
|
817
|
+
candidates.add(specifier);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
for (const specifier of candidates) {
|
|
821
|
+
const cleaned = stripInlineLoader(specifier.trim());
|
|
822
|
+
const { resource } = splitResourceAndQuery(cleaned);
|
|
823
|
+
if (!resource) {
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
if (isStyleResource(resource)) {
|
|
827
|
+
return true;
|
|
828
|
+
}
|
|
829
|
+
const resolved = await resolveImportPath(resource, filePath, options.rootDir, options.tsconfig, options.resolver, options.resolverFactory, RESOLUTION_EXTENSIONS);
|
|
830
|
+
if (resolved && isStyleResource(resolved)) {
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
616
836
|
function collectSelectorTokensFromCss(css) {
|
|
617
837
|
const tokens = new Set();
|
|
618
838
|
const pattern = /\.([A-Za-z_-][A-Za-z0-9_-]*)\b/g;
|
|
@@ -645,6 +865,21 @@ async function resolveProxyInfo(manifestKey, selectorSource, resolvedPath, cache
|
|
|
645
865
|
cache.set(manifestKey, proxyInfo);
|
|
646
866
|
return proxyInfo;
|
|
647
867
|
}
|
|
868
|
+
async function resolveDeclarationProxyInfo(manifestKey, resolvedPath, cache) {
|
|
869
|
+
const cached = cache.get(manifestKey);
|
|
870
|
+
if (cached !== undefined) {
|
|
871
|
+
return cached;
|
|
872
|
+
}
|
|
873
|
+
const defaultSignal = await getDefaultExportSignal(resolvedPath);
|
|
874
|
+
const exportedNames = await getNamedExports(resolvedPath);
|
|
875
|
+
const proxyInfo = {
|
|
876
|
+
moduleSpecifier: buildDeclarationModuleSpecifier(resolvedPath),
|
|
877
|
+
includeDefault: defaultSignal === 'has-default',
|
|
878
|
+
exportedNames,
|
|
879
|
+
};
|
|
880
|
+
cache.set(manifestKey, proxyInfo);
|
|
881
|
+
return proxyInfo;
|
|
882
|
+
}
|
|
648
883
|
function buildProxyModuleSpecifier(resolvedPath, selectorSource) {
|
|
649
884
|
const resolvedExt = path.extname(resolvedPath);
|
|
650
885
|
const baseName = path.basename(resolvedPath, resolvedExt);
|
|
@@ -662,6 +897,16 @@ async function getDefaultExportSignal(filePath) {
|
|
|
662
897
|
return 'unknown';
|
|
663
898
|
}
|
|
664
899
|
}
|
|
900
|
+
async function getNamedExports(filePath) {
|
|
901
|
+
try {
|
|
902
|
+
const source = await fs.readFile(filePath, 'utf8');
|
|
903
|
+
const analysis = await analyzeModule(source, filePath);
|
|
904
|
+
return new Set(analysis.exports ?? []);
|
|
905
|
+
}
|
|
906
|
+
catch {
|
|
907
|
+
return new Set();
|
|
908
|
+
}
|
|
909
|
+
}
|
|
665
910
|
function createProjectPeerResolver(rootDir) {
|
|
666
911
|
const resolver = getProjectRequire(rootDir);
|
|
667
912
|
return async (name) => {
|
|
@@ -734,6 +979,8 @@ export async function runGenerateTypesCli(argv = process.argv.slice(2)) {
|
|
|
734
979
|
autoStable: parsed.autoStable,
|
|
735
980
|
hashed: parsed.hashed,
|
|
736
981
|
resolver,
|
|
982
|
+
mode: parsed.mode,
|
|
983
|
+
manifestPath: parsed.manifestPath,
|
|
737
984
|
});
|
|
738
985
|
reportCliResult(result);
|
|
739
986
|
}
|
|
@@ -751,10 +998,20 @@ function parseCliArgs(argv) {
|
|
|
751
998
|
let autoStable = false;
|
|
752
999
|
let hashed = false;
|
|
753
1000
|
let resolver;
|
|
1001
|
+
let mode = 'module';
|
|
1002
|
+
let manifestPath;
|
|
754
1003
|
for (let i = 0; i < argv.length; i += 1) {
|
|
755
1004
|
const arg = argv[i];
|
|
756
1005
|
if (arg === '--help' || arg === '-h') {
|
|
757
|
-
return {
|
|
1006
|
+
return {
|
|
1007
|
+
rootDir,
|
|
1008
|
+
include,
|
|
1009
|
+
outDir,
|
|
1010
|
+
stableNamespace,
|
|
1011
|
+
autoStable,
|
|
1012
|
+
mode,
|
|
1013
|
+
help: true,
|
|
1014
|
+
};
|
|
758
1015
|
}
|
|
759
1016
|
if (arg === '--auto-stable') {
|
|
760
1017
|
autoStable = true;
|
|
@@ -788,6 +1045,14 @@ function parseCliArgs(argv) {
|
|
|
788
1045
|
outDir = value;
|
|
789
1046
|
continue;
|
|
790
1047
|
}
|
|
1048
|
+
if (arg === '--manifest') {
|
|
1049
|
+
const value = argv[++i];
|
|
1050
|
+
if (!value) {
|
|
1051
|
+
throw new Error('Missing value for --manifest');
|
|
1052
|
+
}
|
|
1053
|
+
manifestPath = value;
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
791
1056
|
if (arg === '--stable-namespace') {
|
|
792
1057
|
const value = argv[++i];
|
|
793
1058
|
if (!value) {
|
|
@@ -804,6 +1069,17 @@ function parseCliArgs(argv) {
|
|
|
804
1069
|
resolver = value;
|
|
805
1070
|
continue;
|
|
806
1071
|
}
|
|
1072
|
+
if (arg === '--mode') {
|
|
1073
|
+
const value = argv[++i];
|
|
1074
|
+
if (!value) {
|
|
1075
|
+
throw new Error('Missing value for --mode');
|
|
1076
|
+
}
|
|
1077
|
+
if (value !== 'module' && value !== 'declaration') {
|
|
1078
|
+
throw new Error(`Unknown mode: ${value}`);
|
|
1079
|
+
}
|
|
1080
|
+
mode = value;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
807
1083
|
if (arg.startsWith('-')) {
|
|
808
1084
|
throw new Error(`Unknown flag: ${arg}`);
|
|
809
1085
|
}
|
|
@@ -812,20 +1088,35 @@ function parseCliArgs(argv) {
|
|
|
812
1088
|
if (autoStable && hashed) {
|
|
813
1089
|
throw new Error('Cannot combine --auto-stable with --hashed');
|
|
814
1090
|
}
|
|
815
|
-
|
|
1091
|
+
if (manifestPath && mode !== 'declaration') {
|
|
1092
|
+
throw new Error('Cannot use --manifest unless --mode is declaration');
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
rootDir,
|
|
1096
|
+
include,
|
|
1097
|
+
outDir,
|
|
1098
|
+
stableNamespace,
|
|
1099
|
+
autoStable,
|
|
1100
|
+
hashed,
|
|
1101
|
+
resolver,
|
|
1102
|
+
mode,
|
|
1103
|
+
manifestPath,
|
|
1104
|
+
};
|
|
816
1105
|
}
|
|
817
1106
|
function printHelp() {
|
|
818
1107
|
console.log(`Usage: knighted-css-generate-types [options]
|
|
819
1108
|
|
|
820
1109
|
Options:
|
|
821
|
-
-r, --root <path>
|
|
822
|
-
-i, --include <path>
|
|
823
|
-
--out-dir <path>
|
|
824
|
-
--stable-namespace <name>
|
|
825
|
-
--auto-stable
|
|
826
|
-
--hashed
|
|
827
|
-
--resolver <path>
|
|
828
|
-
|
|
1110
|
+
-r, --root <path> Project root directory (default: cwd)
|
|
1111
|
+
-i, --include <path> Additional directories/files to scan (repeatable)
|
|
1112
|
+
--out-dir <path> Directory to store selector module manifest cache
|
|
1113
|
+
--stable-namespace <name> Stable namespace prefix for generated selector maps
|
|
1114
|
+
--auto-stable Enable autoStable when extracting CSS for selectors
|
|
1115
|
+
--hashed Emit selectors backed by loader-bridge hashed modules
|
|
1116
|
+
--resolver <path> Path or package name exporting a CssResolver
|
|
1117
|
+
--mode <module|declaration> Emit selector modules (module) or declaration files (declaration)
|
|
1118
|
+
--manifest <path> Write a sidecar manifest (declaration mode only)
|
|
1119
|
+
-h, --help Show this help message
|
|
829
1120
|
`);
|
|
830
1121
|
}
|
|
831
1122
|
function reportCliResult(result) {
|
|
@@ -836,6 +1127,9 @@ function reportCliResult(result) {
|
|
|
836
1127
|
console.log(`[knighted-css] Selector modules updated: wrote ${result.selectorModulesWritten}, removed ${result.selectorModulesRemoved}.`);
|
|
837
1128
|
}
|
|
838
1129
|
console.log(`[knighted-css] Manifest: ${result.manifestPath}`);
|
|
1130
|
+
if (result.sidecarManifestPath) {
|
|
1131
|
+
console.log(`[knighted-css] Sidecar manifest: ${result.sidecarManifestPath}`);
|
|
1132
|
+
}
|
|
839
1133
|
for (const warning of result.warnings) {
|
|
840
1134
|
console.warn(`[knighted-css] ${warning}`);
|
|
841
1135
|
}
|
|
@@ -865,23 +1159,31 @@ export const __generateTypesInternals = {
|
|
|
865
1159
|
setImportMetaUrlProvider,
|
|
866
1160
|
isNonRelativeSpecifier,
|
|
867
1161
|
isStyleResource,
|
|
1162
|
+
isCssModuleResource,
|
|
868
1163
|
resolveProxyInfo,
|
|
1164
|
+
resolveDeclarationProxyInfo,
|
|
869
1165
|
resolveWithExtensionFallback,
|
|
870
1166
|
resolveIndexFallback,
|
|
871
1167
|
createProjectPeerResolver,
|
|
872
1168
|
getProjectRequire,
|
|
873
1169
|
loadTsconfigResolutionContext,
|
|
874
1170
|
resolveWithTsconfigPaths,
|
|
1171
|
+
hasStyleImports,
|
|
875
1172
|
loadResolverModule,
|
|
876
1173
|
parseCliArgs,
|
|
877
1174
|
printHelp,
|
|
878
1175
|
reportCliResult,
|
|
879
1176
|
buildSelectorModuleManifestKey,
|
|
880
1177
|
buildSelectorModulePath,
|
|
1178
|
+
buildDeclarationModuleSpecifier,
|
|
881
1179
|
formatSelectorModuleSource,
|
|
1180
|
+
buildDeclarationPath,
|
|
1181
|
+
formatDeclarationSource,
|
|
1182
|
+
ensureDeclarationModule,
|
|
882
1183
|
ensureSelectorModule,
|
|
883
1184
|
removeStaleSelectorModules,
|
|
884
1185
|
readManifest,
|
|
885
1186
|
writeManifest,
|
|
1187
|
+
writeSidecarManifest,
|
|
886
1188
|
};
|
|
887
1189
|
//# sourceMappingURL=generateTypes.js.map
|