@knighted/css 1.0.9 → 1.0.10
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 +2 -2
- package/dist/cjs/moduleGraph.cjs +134 -7
- package/dist/cjs/moduleGraph.cjs.map +1 -1
- package/dist/moduleGraph.js +134 -7
- package/dist/moduleGraph.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://codecov.io/gh/knightedcodemonkey/css)
|
|
5
5
|
[](https://www.npmjs.com/package/@knighted/css)
|
|
6
6
|
|
|
7
|
-
`@knighted/css` walks your
|
|
7
|
+
`@knighted/css` walks your module graph, compiles every CSS-like dependency (plain CSS, Sass/SCSS, Less, vanilla-extract), and ships both the concatenated stylesheet string and optional `.knighted-css.*` imports that keep selectors typed. Use it with or without a bundler: run the `css()` API in scripts/SSR pipelines, or lean on the `?knighted-css` loader query so bundlers import compiled CSS alongside modules. Either path yields fully materialized styles for Shadow DOM surfaces, server-rendered routes, static site builds, or any entry point that should inline CSS.
|
|
8
8
|
|
|
9
9
|
## Why
|
|
10
10
|
|
|
@@ -23,7 +23,7 @@ I needed a single source of truth for UI components that could drop into both li
|
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
26
|
-
- Traverses module graphs with a built-in walker to find transitive style imports (
|
|
26
|
+
- Traverses module graphs with a built-in walker to find transitive style imports (bundler optional—works standalone or through bundler loaders), including static import attributes (`with { type: "css" }`) for extensionless or aliased specifiers.
|
|
27
27
|
- Resolution parity via [`oxc-resolver`](https://github.com/oxc-project/oxc-resolver): tsconfig `paths`, package `exports` + `imports`, and extension aliasing (e.g., `.css.js` → `.css.ts`) are honored without wiring up a bundler.
|
|
28
28
|
- Compiles `*.css`, `*.scss`, `*.sass`, `*.less`, and `*.css.ts` (vanilla-extract) files out of the box.
|
|
29
29
|
- Optional post-processing via [`lightningcss`](https://github.com/parcel-bundler/lightningcss) for minification, prefixing, media query optimizations, or specificity boosts.
|
package/dist/cjs/moduleGraph.cjs
CHANGED
|
@@ -47,7 +47,7 @@ async function collectStyleImports(entryPath, options) {
|
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
const specifiers = extractModuleSpecifiers(source, absolutePath);
|
|
50
|
-
for (const specifier of specifiers) {
|
|
50
|
+
for (const { specifier, assertedType } of specifiers) {
|
|
51
51
|
if (!specifier || isBuiltinSpecifier(specifier)) {
|
|
52
52
|
continue;
|
|
53
53
|
}
|
|
@@ -59,6 +59,13 @@ async function collectStyleImports(entryPath, options) {
|
|
|
59
59
|
if (!filter(normalized)) {
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
62
|
+
if (assertedType === 'css') {
|
|
63
|
+
if (!seenStyles.has(normalized)) {
|
|
64
|
+
seenStyles.add(normalized);
|
|
65
|
+
styleOrder.push(normalized);
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
62
69
|
if (isStyleExtension(normalized, normalizedStyles)) {
|
|
63
70
|
if (!seenStyles.has(normalized)) {
|
|
64
71
|
seenStyles.add(normalized);
|
|
@@ -144,26 +151,26 @@ function extractModuleSpecifiers(sourceText, filePath) {
|
|
|
144
151
|
return [];
|
|
145
152
|
}
|
|
146
153
|
const specifiers = [];
|
|
147
|
-
const addSpecifier = (raw) => {
|
|
154
|
+
const addSpecifier = (raw, assertedType) => {
|
|
148
155
|
if (!raw) {
|
|
149
156
|
return;
|
|
150
157
|
}
|
|
151
158
|
const normalized = normalizeSpecifier(raw);
|
|
152
159
|
if (normalized) {
|
|
153
|
-
specifiers.push(normalized);
|
|
160
|
+
specifiers.push({ specifier: normalized, assertedType });
|
|
154
161
|
}
|
|
155
162
|
};
|
|
156
163
|
const visitor = new oxc_parser_1.Visitor({
|
|
157
164
|
ImportDeclaration(node) {
|
|
158
|
-
addSpecifier(node.source?.value);
|
|
165
|
+
addSpecifier(node.source?.value, getImportAssertedType(node));
|
|
159
166
|
},
|
|
160
167
|
ExportNamedDeclaration(node) {
|
|
161
168
|
if (node.source) {
|
|
162
|
-
addSpecifier(node.source.value);
|
|
169
|
+
addSpecifier(node.source.value, getImportAssertedType(node));
|
|
163
170
|
}
|
|
164
171
|
},
|
|
165
172
|
ExportAllDeclaration(node) {
|
|
166
|
-
addSpecifier(node.source?.value);
|
|
173
|
+
addSpecifier(node.source?.value, getImportAssertedType(node));
|
|
167
174
|
},
|
|
168
175
|
TSImportEqualsDeclaration(node) {
|
|
169
176
|
const specifier = extractImportEqualsSpecifier(node);
|
|
@@ -174,7 +181,7 @@ function extractModuleSpecifiers(sourceText, filePath) {
|
|
|
174
181
|
ImportExpression(node) {
|
|
175
182
|
const specifier = getStringFromExpression(node.source);
|
|
176
183
|
if (specifier) {
|
|
177
|
-
addSpecifier(specifier);
|
|
184
|
+
addSpecifier(specifier, getImportExpressionAssertedType(node));
|
|
178
185
|
}
|
|
179
186
|
},
|
|
180
187
|
CallExpression(node) {
|
|
@@ -210,6 +217,126 @@ function normalizeSpecifier(raw) {
|
|
|
210
217
|
}
|
|
211
218
|
return withoutQuery;
|
|
212
219
|
}
|
|
220
|
+
function getImportAssertedType(node) {
|
|
221
|
+
const attributes = getImportAttributes(node);
|
|
222
|
+
for (const attribute of attributes) {
|
|
223
|
+
const key = getAttributeKey(attribute);
|
|
224
|
+
const value = getAttributeValue(attribute);
|
|
225
|
+
if (key === 'type' && value === 'css') {
|
|
226
|
+
return 'css';
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
function getImportAttributes(node) {
|
|
232
|
+
const attributes = [];
|
|
233
|
+
const candidate = node;
|
|
234
|
+
const withClause = candidate?.withClause;
|
|
235
|
+
if (withClause && Array.isArray(withClause.attributes)) {
|
|
236
|
+
attributes.push(...withClause.attributes);
|
|
237
|
+
}
|
|
238
|
+
const directAttributes = candidate?.attributes;
|
|
239
|
+
if (Array.isArray(directAttributes)) {
|
|
240
|
+
attributes.push(...directAttributes);
|
|
241
|
+
}
|
|
242
|
+
const assertions = candidate?.assertions;
|
|
243
|
+
if (Array.isArray(assertions)) {
|
|
244
|
+
attributes.push(...assertions);
|
|
245
|
+
}
|
|
246
|
+
return attributes;
|
|
247
|
+
}
|
|
248
|
+
function getAttributeKey(attribute) {
|
|
249
|
+
const attr = attribute;
|
|
250
|
+
const key = attr?.key;
|
|
251
|
+
if (!key) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
if (typeof key.name === 'string') {
|
|
255
|
+
return key.name;
|
|
256
|
+
}
|
|
257
|
+
const value = key.value;
|
|
258
|
+
if (typeof value === 'string') {
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
function getAttributeValue(attribute) {
|
|
264
|
+
const attr = attribute;
|
|
265
|
+
const value = attr?.value;
|
|
266
|
+
if (typeof value === 'string') {
|
|
267
|
+
return value;
|
|
268
|
+
}
|
|
269
|
+
if (value && typeof value.value === 'string') {
|
|
270
|
+
return value.value;
|
|
271
|
+
}
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
function getImportExpressionAssertedType(node) {
|
|
275
|
+
// Stage-3 import attributes proposal shape: import(spec, { with: { type: "css" } })
|
|
276
|
+
const options = node.options;
|
|
277
|
+
if (!options) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
const withObject = getStaticObjectProperty(options, 'with');
|
|
281
|
+
if (withObject && isObjectExpression(withObject)) {
|
|
282
|
+
const typeValue = getStaticObjectString(withObject, 'type');
|
|
283
|
+
if (typeValue === 'css') {
|
|
284
|
+
return 'css';
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const assertObject = getStaticObjectProperty(options, 'assert');
|
|
288
|
+
if (assertObject && isObjectExpression(assertObject)) {
|
|
289
|
+
const typeValue = getStaticObjectString(assertObject, 'type');
|
|
290
|
+
if (typeValue === 'css') {
|
|
291
|
+
return 'css';
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
function isObjectExpression(expression) {
|
|
297
|
+
return expression && expression.type === 'ObjectExpression'
|
|
298
|
+
? expression
|
|
299
|
+
: undefined;
|
|
300
|
+
}
|
|
301
|
+
function getStaticObjectProperty(expression, name) {
|
|
302
|
+
const objectExpression = isObjectExpression(expression);
|
|
303
|
+
if (!objectExpression) {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
for (const prop of objectExpression.properties) {
|
|
307
|
+
const maybeProp = prop;
|
|
308
|
+
if (maybeProp.type && maybeProp.type !== 'Property') {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const keyName = getPropertyKeyName(maybeProp.key);
|
|
312
|
+
if (keyName === name) {
|
|
313
|
+
const value = maybeProp.value;
|
|
314
|
+
if (value) {
|
|
315
|
+
return value;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
function getPropertyKeyName(key) {
|
|
322
|
+
if (!key)
|
|
323
|
+
return undefined;
|
|
324
|
+
const asAny = key;
|
|
325
|
+
if (typeof asAny.name === 'string') {
|
|
326
|
+
return asAny.name;
|
|
327
|
+
}
|
|
328
|
+
if (typeof asAny.value === 'string') {
|
|
329
|
+
return asAny.value;
|
|
330
|
+
}
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
333
|
+
function getStaticObjectString(expression, name) {
|
|
334
|
+
const valueExpression = getStaticObjectProperty(expression, name);
|
|
335
|
+
if (!valueExpression) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
return getStringFromExpression(valueExpression);
|
|
339
|
+
}
|
|
213
340
|
function extractImportEqualsSpecifier(node) {
|
|
214
341
|
if (node.moduleReference.type === 'TSExternalModuleReference') {
|
|
215
342
|
return node.moduleReference.expression.value;
|