@csszyx/compiler 0.4.0 → 0.6.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/dist/index.cjs +107 -9
- package/dist/index.d.cts +151 -131
- package/dist/index.d.ts +151 -131
- package/dist/index.js +109 -11
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -329,6 +329,39 @@ function stripInvalidColorStrings(sz) {
|
|
|
329
329
|
var babel = __toESM(require("@babel/core"), 1);
|
|
330
330
|
var t = __toESM(require("@babel/types"), 1);
|
|
331
331
|
|
|
332
|
+
// src/ast-budget.ts
|
|
333
|
+
var AST_BUDGET = 5e4;
|
|
334
|
+
var ASTBudgetExceededError = class extends Error {
|
|
335
|
+
/**
|
|
336
|
+
*
|
|
337
|
+
* @param filename Source filename if known, otherwise `undefined`.
|
|
338
|
+
* @param nodeCount Node count at the point traversal was aborted.
|
|
339
|
+
* @param budget Effective budget that was exceeded. Defaults to
|
|
340
|
+
* {@link AST_BUDGET} for backwards compatibility with callers that
|
|
341
|
+
* don't pass an override.
|
|
342
|
+
*/
|
|
343
|
+
constructor(filename, nodeCount, budget = AST_BUDGET) {
|
|
344
|
+
const where = filename ?? "<anonymous>";
|
|
345
|
+
super(
|
|
346
|
+
`[csszyx] AST budget exceeded: ${where} has more than ${budget} nodes (traversal aborted at ${nodeCount}). Files this large are almost always machine-generated and should be excluded from sz transformation. Either exclude the file from the plugin (Vite: \`csszyx({ exclude: [/large-data\\.ts$/] })\`), or raise the limit globally with \`csszyx({ build: { astBudgetLimit: 100_000 } })\`.`
|
|
347
|
+
);
|
|
348
|
+
this.name = "ASTBudgetExceededError";
|
|
349
|
+
this.filename = filename;
|
|
350
|
+
this.nodeCount = nodeCount;
|
|
351
|
+
this.budget = budget;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// src/recovery-tokens.ts
|
|
356
|
+
var import_node_crypto = require("crypto");
|
|
357
|
+
function generateInlineRecoveryToken(filename, line, column, elementType) {
|
|
358
|
+
const input = `${filename}:${line}:${column}:${elementType}`;
|
|
359
|
+
return (0, import_node_crypto.createHash)("sha256").update(input).digest("hex").substring(0, 12);
|
|
360
|
+
}
|
|
361
|
+
function isValidInlineRecoveryMode(value) {
|
|
362
|
+
return value === "csr" || value === "dev-only";
|
|
363
|
+
}
|
|
364
|
+
|
|
332
365
|
// src/transform-core.ts
|
|
333
366
|
var PROPERTY_MAP = {
|
|
334
367
|
// Background
|
|
@@ -2321,7 +2354,8 @@ function normalizeClassName(className) {
|
|
|
2321
2354
|
}
|
|
2322
2355
|
|
|
2323
2356
|
// src/transform.ts
|
|
2324
|
-
function transformSourceCode(source) {
|
|
2357
|
+
function transformSourceCode(source, filename, options) {
|
|
2358
|
+
const astBudget = options?.astBudget ?? AST_BUDGET;
|
|
2325
2359
|
let usesRuntime = false;
|
|
2326
2360
|
let usesMerge = false;
|
|
2327
2361
|
let usesColorVar = false;
|
|
@@ -2329,12 +2363,13 @@ function transformSourceCode(source) {
|
|
|
2329
2363
|
const collectedClasses = /* @__PURE__ */ new Set();
|
|
2330
2364
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2331
2365
|
const diagnostics = [];
|
|
2366
|
+
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
2332
2367
|
if (!source.includes("sz")) {
|
|
2333
|
-
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics };
|
|
2368
|
+
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
|
|
2334
2369
|
}
|
|
2335
2370
|
try {
|
|
2336
2371
|
const result = babel.transformSync(source, {
|
|
2337
|
-
filename: "file.tsx",
|
|
2372
|
+
filename: filename ?? "file.tsx",
|
|
2338
2373
|
// Enable TS/JSX parsing
|
|
2339
2374
|
ast: true,
|
|
2340
2375
|
code: true,
|
|
@@ -2346,6 +2381,21 @@ function transformSourceCode(source) {
|
|
|
2346
2381
|
plugins: [
|
|
2347
2382
|
function() {
|
|
2348
2383
|
return {
|
|
2384
|
+
// Budget guard runs in `pre` (before the visitor pass)
|
|
2385
|
+
// so it short-circuits pathologically large files
|
|
2386
|
+
// before any sz transform work begins, and doesn't
|
|
2387
|
+
// interfere with the JSXAttribute handler below.
|
|
2388
|
+
pre(file) {
|
|
2389
|
+
let nodeCount = 0;
|
|
2390
|
+
babel.traverse(file.ast, {
|
|
2391
|
+
enter() {
|
|
2392
|
+
nodeCount++;
|
|
2393
|
+
if (nodeCount > astBudget) {
|
|
2394
|
+
throw new ASTBudgetExceededError(filename, nodeCount, astBudget);
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
});
|
|
2398
|
+
},
|
|
2349
2399
|
visitor: {
|
|
2350
2400
|
JSXAttribute(path) {
|
|
2351
2401
|
const attrName = t.isJSXIdentifier(path.node.name) ? path.node.name.name : "";
|
|
@@ -2360,6 +2410,50 @@ function transformSourceCode(source) {
|
|
|
2360
2410
|
}
|
|
2361
2411
|
return;
|
|
2362
2412
|
}
|
|
2413
|
+
if (attrName === "szRecover") {
|
|
2414
|
+
const recoverValue = path.node.value;
|
|
2415
|
+
if (!t.isStringLiteral(recoverValue)) {
|
|
2416
|
+
diagnostics.push(
|
|
2417
|
+
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: only string-literal values ("csr" | "dev-only") are supported. Dynamic values disable token emission for this element.`
|
|
2418
|
+
);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
if (!isValidInlineRecoveryMode(recoverValue.value)) {
|
|
2422
|
+
diagnostics.push(
|
|
2423
|
+
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: unknown mode "${recoverValue.value}" \u2014 expected "csr" or "dev-only". Token emission skipped.`
|
|
2424
|
+
);
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
const opening = path.parentPath;
|
|
2428
|
+
if (!opening?.isJSXOpeningElement()) {
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
const alreadyTagged = opening.node.attributes.some(
|
|
2432
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === "data-sz-recovery-token"
|
|
2433
|
+
);
|
|
2434
|
+
if (alreadyTagged) {
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
const loc = path.node.loc;
|
|
2438
|
+
const elementType = t.isJSXIdentifier(opening.node.name) ? opening.node.name.name : t.isJSXMemberExpression(opening.node.name) ? "<member>" : "<unknown>";
|
|
2439
|
+
const line = loc?.start.line ?? 0;
|
|
2440
|
+
const column = loc?.start.column ?? 0;
|
|
2441
|
+
const file = filename ?? "file.tsx";
|
|
2442
|
+
const token = generateInlineRecoveryToken(file, line, column, elementType);
|
|
2443
|
+
opening.node.attributes.push(
|
|
2444
|
+
t.jsxAttribute(
|
|
2445
|
+
t.jsxIdentifier("data-sz-recovery-token"),
|
|
2446
|
+
t.stringLiteral(token)
|
|
2447
|
+
)
|
|
2448
|
+
);
|
|
2449
|
+
recoveryTokens.set(token, {
|
|
2450
|
+
mode: recoverValue.value,
|
|
2451
|
+
component: elementType,
|
|
2452
|
+
path: `${file}:${line}:${column}`
|
|
2453
|
+
});
|
|
2454
|
+
transformed = true;
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2363
2457
|
if (attrName !== "sz") {
|
|
2364
2458
|
return;
|
|
2365
2459
|
}
|
|
@@ -2862,11 +2956,15 @@ function transformSourceCode(source) {
|
|
|
2862
2956
|
usesColorVar,
|
|
2863
2957
|
classes: collectedClasses,
|
|
2864
2958
|
rawClassNames,
|
|
2865
|
-
diagnostics
|
|
2959
|
+
diagnostics,
|
|
2960
|
+
recoveryTokens
|
|
2866
2961
|
};
|
|
2867
2962
|
} catch (e) {
|
|
2963
|
+
if (e instanceof ASTBudgetExceededError) {
|
|
2964
|
+
throw e;
|
|
2965
|
+
}
|
|
2868
2966
|
console.warn("[csszyx] AST transform failed, falling back to original code:", e);
|
|
2869
|
-
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics };
|
|
2967
|
+
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
|
|
2870
2968
|
}
|
|
2871
2969
|
}
|
|
2872
2970
|
function parseStyleStringToObjectExpr(styleStr) {
|
|
@@ -3716,7 +3814,7 @@ function hoistCSSVariables(usages, parentMap) {
|
|
|
3716
3814
|
}
|
|
3717
3815
|
function buildParentMap(ast) {
|
|
3718
3816
|
const map = /* @__PURE__ */ new Map();
|
|
3719
|
-
function
|
|
3817
|
+
function traverse2(node, parent) {
|
|
3720
3818
|
if (parent) {
|
|
3721
3819
|
map.set(node, parent);
|
|
3722
3820
|
}
|
|
@@ -3726,16 +3824,16 @@ function buildParentMap(ast) {
|
|
|
3726
3824
|
if (Array.isArray(value)) {
|
|
3727
3825
|
for (const item of value) {
|
|
3728
3826
|
if (item && typeof item === "object" && "type" in item) {
|
|
3729
|
-
|
|
3827
|
+
traverse2(item, node);
|
|
3730
3828
|
}
|
|
3731
3829
|
}
|
|
3732
3830
|
} else if ("type" in value) {
|
|
3733
|
-
|
|
3831
|
+
traverse2(value, node);
|
|
3734
3832
|
}
|
|
3735
3833
|
}
|
|
3736
3834
|
}
|
|
3737
3835
|
}
|
|
3738
|
-
|
|
3836
|
+
traverse2(ast);
|
|
3739
3837
|
return map;
|
|
3740
3838
|
}
|
|
3741
3839
|
|
package/dist/index.d.cts
CHANGED
|
@@ -1,137 +1,6 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import * as CSS from 'csstype';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* JSX Transform - Converts sz prop to className string.
|
|
6
|
-
*
|
|
7
|
-
* This module handles the transformation of csszyx object syntax into
|
|
8
|
-
* Tailwind CSS class strings. It processes nested objects for variants
|
|
9
|
-
* like hover, focus, etc.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Represents a value in the sz object.
|
|
13
|
-
* Can be a string, number, boolean, or nested object for variants.
|
|
14
|
-
*/
|
|
15
|
-
type SzValue = string | number | boolean | SzObject;
|
|
16
|
-
/**
|
|
17
|
-
* Represents the sz object structure.
|
|
18
|
-
* Keys are CSS property abbreviations, values can be primitives or nested objects.
|
|
19
|
-
*/
|
|
20
|
-
interface SzObject {
|
|
21
|
-
[key: string]: SzValue;
|
|
22
|
-
}
|
|
23
|
-
declare const PROPERTY_MAP: Record<string, string>;
|
|
24
|
-
declare const SUGGESTION_MAP: Record<string, string>;
|
|
25
|
-
declare const KNOWN_VARIANTS: Set<string>;
|
|
26
|
-
declare const BOOLEAN_SHORTHANDS: Set<string>;
|
|
27
|
-
/**
|
|
28
|
-
* Represents the result of a transformation.
|
|
29
|
-
*/
|
|
30
|
-
interface TransformResult {
|
|
31
|
-
className: string;
|
|
32
|
-
attributes: Record<string, string>;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Transforms a csszyx sz object into a Tailwind CSS className string and extracted attributes.
|
|
36
|
-
*
|
|
37
|
-
* @param {SzObject} szProp - The sz object from JSX
|
|
38
|
-
* @param {string} prefix - Variant prefix for nested properties
|
|
39
|
-
* @param {Record<string, string>} [mangleMap] - Optional map for property name mangling
|
|
40
|
-
* @returns {TransformResult} The transformation result
|
|
41
|
-
*/
|
|
42
|
-
declare function transform(szProp: SzObject, prefix?: string, mangleMap?: Record<string, string>): TransformResult;
|
|
43
|
-
/**
|
|
44
|
-
* Validates that an sz prop object is valid.
|
|
45
|
-
*
|
|
46
|
-
* @param {unknown} szProp - The value to validate
|
|
47
|
-
* @returns {boolean} True if valid, false otherwise
|
|
48
|
-
*/
|
|
49
|
-
declare function isValidSzProp(szProp: unknown): szProp is SzObject;
|
|
50
|
-
/**
|
|
51
|
-
* Normalizes a className string by removing extra whitespace.
|
|
52
|
-
*
|
|
53
|
-
* @param {string} className - The className string to normalize
|
|
54
|
-
* @returns {string} The normalized className string
|
|
55
|
-
*/
|
|
56
|
-
declare function normalizeClassName(className: string): string;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Transforms all sz props in a source code string into Tailwind classNames.
|
|
60
|
-
*
|
|
61
|
-
* @param {string} source - The source code to transform
|
|
62
|
-
* @returns {object} Transformation result with code and metadata
|
|
63
|
-
*/
|
|
64
|
-
declare function transformSourceCode(source: string): {
|
|
65
|
-
code: string;
|
|
66
|
-
transformed: boolean;
|
|
67
|
-
usesRuntime: boolean;
|
|
68
|
-
usesMerge: boolean;
|
|
69
|
-
usesColorVar: boolean;
|
|
70
|
-
classes: Set<string>;
|
|
71
|
-
rawClassNames: Set<string>;
|
|
72
|
-
diagnostics: string[];
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Core Compiler class for csszyx.
|
|
77
|
-
*
|
|
78
|
-
* This class manages the WASM lifecycle and provides high-performance
|
|
79
|
-
* transformation methods. It falls back to JavaScript if WASM is not available.
|
|
80
|
-
*/
|
|
81
|
-
declare class CsszyxCompiler {
|
|
82
|
-
private static instance;
|
|
83
|
-
private wasmLoaded;
|
|
84
|
-
/**
|
|
85
|
-
* Private constructor to enforce singleton pattern.
|
|
86
|
-
*/
|
|
87
|
-
private constructor();
|
|
88
|
-
/**
|
|
89
|
-
* Gets the singleton instance of the compiler.
|
|
90
|
-
*
|
|
91
|
-
* @returns {CsszyxCompiler} The compiler instance.
|
|
92
|
-
*/
|
|
93
|
-
static getInstance(): CsszyxCompiler;
|
|
94
|
-
/**
|
|
95
|
-
* Initializes the WASM core.
|
|
96
|
-
*
|
|
97
|
-
* @returns {Promise<void>} Resolves when WASM is ready.
|
|
98
|
-
*/
|
|
99
|
-
init(): Promise<void>;
|
|
100
|
-
/**
|
|
101
|
-
* Transforms an sz object into Tailwind classes.
|
|
102
|
-
*
|
|
103
|
-
* @param {SzObject} sz - The object to transform.
|
|
104
|
-
* @returns {string} The transformed class string.
|
|
105
|
-
*/
|
|
106
|
-
transform(sz: SzObject): string;
|
|
107
|
-
/**
|
|
108
|
-
* Checks if the WASM core is currently active.
|
|
109
|
-
*
|
|
110
|
-
* @returns {boolean} True if WASM is loaded.
|
|
111
|
-
*/
|
|
112
|
-
isWasmActive(): boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Generates a recovery token using WASM or JS fallback.
|
|
115
|
-
*
|
|
116
|
-
* @param {object} metadata - Token metadata
|
|
117
|
-
* @param metadata.component - Component name
|
|
118
|
-
* @param metadata.filePath - File path source
|
|
119
|
-
* @param metadata.line - Line number
|
|
120
|
-
* @param metadata.column - Column number
|
|
121
|
-
* @param metadata.mode - Build mode (dev/prod)
|
|
122
|
-
* @param metadata.buildId - Unique build identifier
|
|
123
|
-
* @returns {string} The generated token
|
|
124
|
-
*/
|
|
125
|
-
generateRecoveryToken(metadata: {
|
|
126
|
-
component: string;
|
|
127
|
-
filePath: string;
|
|
128
|
-
line: number;
|
|
129
|
-
column: number;
|
|
130
|
-
mode: 'csr' | 'dev-only';
|
|
131
|
-
buildId: string;
|
|
132
|
-
}): string;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
4
|
/**
|
|
136
5
|
* Valid recovery modes for szRecover attribute.
|
|
137
6
|
*/
|
|
@@ -426,6 +295,157 @@ declare function validateManifest(manifest: unknown): {
|
|
|
426
295
|
error?: string;
|
|
427
296
|
};
|
|
428
297
|
|
|
298
|
+
/**
|
|
299
|
+
* JSX Transform - Converts sz prop to className string.
|
|
300
|
+
*
|
|
301
|
+
* This module handles the transformation of csszyx object syntax into
|
|
302
|
+
* Tailwind CSS class strings. It processes nested objects for variants
|
|
303
|
+
* like hover, focus, etc.
|
|
304
|
+
*/
|
|
305
|
+
/**
|
|
306
|
+
* Represents a value in the sz object.
|
|
307
|
+
* Can be a string, number, boolean, or nested object for variants.
|
|
308
|
+
*/
|
|
309
|
+
type SzValue = string | number | boolean | SzObject;
|
|
310
|
+
/**
|
|
311
|
+
* Represents the sz object structure.
|
|
312
|
+
* Keys are CSS property abbreviations, values can be primitives or nested objects.
|
|
313
|
+
*/
|
|
314
|
+
interface SzObject {
|
|
315
|
+
[key: string]: SzValue;
|
|
316
|
+
}
|
|
317
|
+
declare const PROPERTY_MAP: Record<string, string>;
|
|
318
|
+
declare const SUGGESTION_MAP: Record<string, string>;
|
|
319
|
+
declare const KNOWN_VARIANTS: Set<string>;
|
|
320
|
+
declare const BOOLEAN_SHORTHANDS: Set<string>;
|
|
321
|
+
/**
|
|
322
|
+
* Represents the result of a transformation.
|
|
323
|
+
*/
|
|
324
|
+
interface TransformResult {
|
|
325
|
+
className: string;
|
|
326
|
+
attributes: Record<string, string>;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Transforms a csszyx sz object into a Tailwind CSS className string and extracted attributes.
|
|
330
|
+
*
|
|
331
|
+
* @param {SzObject} szProp - The sz object from JSX
|
|
332
|
+
* @param {string} prefix - Variant prefix for nested properties
|
|
333
|
+
* @param {Record<string, string>} [mangleMap] - Optional map for property name mangling
|
|
334
|
+
* @returns {TransformResult} The transformation result
|
|
335
|
+
*/
|
|
336
|
+
declare function transform(szProp: SzObject, prefix?: string, mangleMap?: Record<string, string>): TransformResult;
|
|
337
|
+
/**
|
|
338
|
+
* Validates that an sz prop object is valid.
|
|
339
|
+
*
|
|
340
|
+
* @param {unknown} szProp - The value to validate
|
|
341
|
+
* @returns {boolean} True if valid, false otherwise
|
|
342
|
+
*/
|
|
343
|
+
declare function isValidSzProp(szProp: unknown): szProp is SzObject;
|
|
344
|
+
/**
|
|
345
|
+
* Normalizes a className string by removing extra whitespace.
|
|
346
|
+
*
|
|
347
|
+
* @param {string} className - The className string to normalize
|
|
348
|
+
* @returns {string} The normalized className string
|
|
349
|
+
*/
|
|
350
|
+
declare function normalizeClassName(className: string): string;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Options for {@link transformSourceCode}.
|
|
354
|
+
*/
|
|
355
|
+
interface TransformSourceCodeOptions {
|
|
356
|
+
/**
|
|
357
|
+
* Override the AST node budget. Files larger than this throw
|
|
358
|
+
* {@link ASTBudgetExceededError}. Defaults to {@link AST_BUDGET} (50 000).
|
|
359
|
+
* Useful for repos with legitimately large generated files (json-as-ts
|
|
360
|
+
* fixtures, GraphQL schema snapshots) that exceed the default cap but
|
|
361
|
+
* are still safe to transform.
|
|
362
|
+
*/
|
|
363
|
+
astBudget?: number;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Transforms all sz props in a source code string into Tailwind classNames.
|
|
367
|
+
*
|
|
368
|
+
* @param {string} source - The source code to transform
|
|
369
|
+
* @param {string} [filename] - Source filename, used in error messages and
|
|
370
|
+
* passed to Babel as the parser filename. Defaults to a placeholder.
|
|
371
|
+
* @param {TransformSourceCodeOptions} [options] - Optional overrides
|
|
372
|
+
* (currently: `astBudget` to raise/lower the per-file node cap).
|
|
373
|
+
* @returns {object} Transformation result with code and metadata
|
|
374
|
+
* @throws {ASTBudgetExceededError} when the file's AST exceeds the
|
|
375
|
+
* effective budget (`options.astBudget` or {@link AST_BUDGET}).
|
|
376
|
+
*/
|
|
377
|
+
declare function transformSourceCode(source: string, filename?: string, options?: TransformSourceCodeOptions): {
|
|
378
|
+
code: string;
|
|
379
|
+
transformed: boolean;
|
|
380
|
+
usesRuntime: boolean;
|
|
381
|
+
usesMerge: boolean;
|
|
382
|
+
usesColorVar: boolean;
|
|
383
|
+
classes: Set<string>;
|
|
384
|
+
rawClassNames: Set<string>;
|
|
385
|
+
diagnostics: string[];
|
|
386
|
+
recoveryTokens: Map<string, TokenData>;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Core Compiler class for csszyx.
|
|
391
|
+
*
|
|
392
|
+
* This class manages the WASM lifecycle and provides high-performance
|
|
393
|
+
* transformation methods. It falls back to JavaScript if WASM is not available.
|
|
394
|
+
*/
|
|
395
|
+
declare class CsszyxCompiler {
|
|
396
|
+
private static instance;
|
|
397
|
+
private wasmLoaded;
|
|
398
|
+
/**
|
|
399
|
+
* Private constructor to enforce singleton pattern.
|
|
400
|
+
*/
|
|
401
|
+
private constructor();
|
|
402
|
+
/**
|
|
403
|
+
* Gets the singleton instance of the compiler.
|
|
404
|
+
*
|
|
405
|
+
* @returns {CsszyxCompiler} The compiler instance.
|
|
406
|
+
*/
|
|
407
|
+
static getInstance(): CsszyxCompiler;
|
|
408
|
+
/**
|
|
409
|
+
* Initializes the WASM core.
|
|
410
|
+
*
|
|
411
|
+
* @returns {Promise<void>} Resolves when WASM is ready.
|
|
412
|
+
*/
|
|
413
|
+
init(): Promise<void>;
|
|
414
|
+
/**
|
|
415
|
+
* Transforms an sz object into Tailwind classes.
|
|
416
|
+
*
|
|
417
|
+
* @param {SzObject} sz - The object to transform.
|
|
418
|
+
* @returns {string} The transformed class string.
|
|
419
|
+
*/
|
|
420
|
+
transform(sz: SzObject): string;
|
|
421
|
+
/**
|
|
422
|
+
* Checks if the WASM core is currently active.
|
|
423
|
+
*
|
|
424
|
+
* @returns {boolean} True if WASM is loaded.
|
|
425
|
+
*/
|
|
426
|
+
isWasmActive(): boolean;
|
|
427
|
+
/**
|
|
428
|
+
* Generates a recovery token using WASM or JS fallback.
|
|
429
|
+
*
|
|
430
|
+
* @param {object} metadata - Token metadata
|
|
431
|
+
* @param metadata.component - Component name
|
|
432
|
+
* @param metadata.filePath - File path source
|
|
433
|
+
* @param metadata.line - Line number
|
|
434
|
+
* @param metadata.column - Column number
|
|
435
|
+
* @param metadata.mode - Build mode (dev/prod)
|
|
436
|
+
* @param metadata.buildId - Unique build identifier
|
|
437
|
+
* @returns {string} The generated token
|
|
438
|
+
*/
|
|
439
|
+
generateRecoveryToken(metadata: {
|
|
440
|
+
component: string;
|
|
441
|
+
filePath: string;
|
|
442
|
+
line: number;
|
|
443
|
+
column: number;
|
|
444
|
+
mode: 'csr' | 'dev-only';
|
|
445
|
+
buildId: string;
|
|
446
|
+
}): string;
|
|
447
|
+
}
|
|
448
|
+
|
|
429
449
|
/**
|
|
430
450
|
* Property Type System for CSS Variable Auto-Compile.
|
|
431
451
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,137 +1,6 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import * as CSS from 'csstype';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* JSX Transform - Converts sz prop to className string.
|
|
6
|
-
*
|
|
7
|
-
* This module handles the transformation of csszyx object syntax into
|
|
8
|
-
* Tailwind CSS class strings. It processes nested objects for variants
|
|
9
|
-
* like hover, focus, etc.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Represents a value in the sz object.
|
|
13
|
-
* Can be a string, number, boolean, or nested object for variants.
|
|
14
|
-
*/
|
|
15
|
-
type SzValue = string | number | boolean | SzObject;
|
|
16
|
-
/**
|
|
17
|
-
* Represents the sz object structure.
|
|
18
|
-
* Keys are CSS property abbreviations, values can be primitives or nested objects.
|
|
19
|
-
*/
|
|
20
|
-
interface SzObject {
|
|
21
|
-
[key: string]: SzValue;
|
|
22
|
-
}
|
|
23
|
-
declare const PROPERTY_MAP: Record<string, string>;
|
|
24
|
-
declare const SUGGESTION_MAP: Record<string, string>;
|
|
25
|
-
declare const KNOWN_VARIANTS: Set<string>;
|
|
26
|
-
declare const BOOLEAN_SHORTHANDS: Set<string>;
|
|
27
|
-
/**
|
|
28
|
-
* Represents the result of a transformation.
|
|
29
|
-
*/
|
|
30
|
-
interface TransformResult {
|
|
31
|
-
className: string;
|
|
32
|
-
attributes: Record<string, string>;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Transforms a csszyx sz object into a Tailwind CSS className string and extracted attributes.
|
|
36
|
-
*
|
|
37
|
-
* @param {SzObject} szProp - The sz object from JSX
|
|
38
|
-
* @param {string} prefix - Variant prefix for nested properties
|
|
39
|
-
* @param {Record<string, string>} [mangleMap] - Optional map for property name mangling
|
|
40
|
-
* @returns {TransformResult} The transformation result
|
|
41
|
-
*/
|
|
42
|
-
declare function transform(szProp: SzObject, prefix?: string, mangleMap?: Record<string, string>): TransformResult;
|
|
43
|
-
/**
|
|
44
|
-
* Validates that an sz prop object is valid.
|
|
45
|
-
*
|
|
46
|
-
* @param {unknown} szProp - The value to validate
|
|
47
|
-
* @returns {boolean} True if valid, false otherwise
|
|
48
|
-
*/
|
|
49
|
-
declare function isValidSzProp(szProp: unknown): szProp is SzObject;
|
|
50
|
-
/**
|
|
51
|
-
* Normalizes a className string by removing extra whitespace.
|
|
52
|
-
*
|
|
53
|
-
* @param {string} className - The className string to normalize
|
|
54
|
-
* @returns {string} The normalized className string
|
|
55
|
-
*/
|
|
56
|
-
declare function normalizeClassName(className: string): string;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Transforms all sz props in a source code string into Tailwind classNames.
|
|
60
|
-
*
|
|
61
|
-
* @param {string} source - The source code to transform
|
|
62
|
-
* @returns {object} Transformation result with code and metadata
|
|
63
|
-
*/
|
|
64
|
-
declare function transformSourceCode(source: string): {
|
|
65
|
-
code: string;
|
|
66
|
-
transformed: boolean;
|
|
67
|
-
usesRuntime: boolean;
|
|
68
|
-
usesMerge: boolean;
|
|
69
|
-
usesColorVar: boolean;
|
|
70
|
-
classes: Set<string>;
|
|
71
|
-
rawClassNames: Set<string>;
|
|
72
|
-
diagnostics: string[];
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Core Compiler class for csszyx.
|
|
77
|
-
*
|
|
78
|
-
* This class manages the WASM lifecycle and provides high-performance
|
|
79
|
-
* transformation methods. It falls back to JavaScript if WASM is not available.
|
|
80
|
-
*/
|
|
81
|
-
declare class CsszyxCompiler {
|
|
82
|
-
private static instance;
|
|
83
|
-
private wasmLoaded;
|
|
84
|
-
/**
|
|
85
|
-
* Private constructor to enforce singleton pattern.
|
|
86
|
-
*/
|
|
87
|
-
private constructor();
|
|
88
|
-
/**
|
|
89
|
-
* Gets the singleton instance of the compiler.
|
|
90
|
-
*
|
|
91
|
-
* @returns {CsszyxCompiler} The compiler instance.
|
|
92
|
-
*/
|
|
93
|
-
static getInstance(): CsszyxCompiler;
|
|
94
|
-
/**
|
|
95
|
-
* Initializes the WASM core.
|
|
96
|
-
*
|
|
97
|
-
* @returns {Promise<void>} Resolves when WASM is ready.
|
|
98
|
-
*/
|
|
99
|
-
init(): Promise<void>;
|
|
100
|
-
/**
|
|
101
|
-
* Transforms an sz object into Tailwind classes.
|
|
102
|
-
*
|
|
103
|
-
* @param {SzObject} sz - The object to transform.
|
|
104
|
-
* @returns {string} The transformed class string.
|
|
105
|
-
*/
|
|
106
|
-
transform(sz: SzObject): string;
|
|
107
|
-
/**
|
|
108
|
-
* Checks if the WASM core is currently active.
|
|
109
|
-
*
|
|
110
|
-
* @returns {boolean} True if WASM is loaded.
|
|
111
|
-
*/
|
|
112
|
-
isWasmActive(): boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Generates a recovery token using WASM or JS fallback.
|
|
115
|
-
*
|
|
116
|
-
* @param {object} metadata - Token metadata
|
|
117
|
-
* @param metadata.component - Component name
|
|
118
|
-
* @param metadata.filePath - File path source
|
|
119
|
-
* @param metadata.line - Line number
|
|
120
|
-
* @param metadata.column - Column number
|
|
121
|
-
* @param metadata.mode - Build mode (dev/prod)
|
|
122
|
-
* @param metadata.buildId - Unique build identifier
|
|
123
|
-
* @returns {string} The generated token
|
|
124
|
-
*/
|
|
125
|
-
generateRecoveryToken(metadata: {
|
|
126
|
-
component: string;
|
|
127
|
-
filePath: string;
|
|
128
|
-
line: number;
|
|
129
|
-
column: number;
|
|
130
|
-
mode: 'csr' | 'dev-only';
|
|
131
|
-
buildId: string;
|
|
132
|
-
}): string;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
4
|
/**
|
|
136
5
|
* Valid recovery modes for szRecover attribute.
|
|
137
6
|
*/
|
|
@@ -426,6 +295,157 @@ declare function validateManifest(manifest: unknown): {
|
|
|
426
295
|
error?: string;
|
|
427
296
|
};
|
|
428
297
|
|
|
298
|
+
/**
|
|
299
|
+
* JSX Transform - Converts sz prop to className string.
|
|
300
|
+
*
|
|
301
|
+
* This module handles the transformation of csszyx object syntax into
|
|
302
|
+
* Tailwind CSS class strings. It processes nested objects for variants
|
|
303
|
+
* like hover, focus, etc.
|
|
304
|
+
*/
|
|
305
|
+
/**
|
|
306
|
+
* Represents a value in the sz object.
|
|
307
|
+
* Can be a string, number, boolean, or nested object for variants.
|
|
308
|
+
*/
|
|
309
|
+
type SzValue = string | number | boolean | SzObject;
|
|
310
|
+
/**
|
|
311
|
+
* Represents the sz object structure.
|
|
312
|
+
* Keys are CSS property abbreviations, values can be primitives or nested objects.
|
|
313
|
+
*/
|
|
314
|
+
interface SzObject {
|
|
315
|
+
[key: string]: SzValue;
|
|
316
|
+
}
|
|
317
|
+
declare const PROPERTY_MAP: Record<string, string>;
|
|
318
|
+
declare const SUGGESTION_MAP: Record<string, string>;
|
|
319
|
+
declare const KNOWN_VARIANTS: Set<string>;
|
|
320
|
+
declare const BOOLEAN_SHORTHANDS: Set<string>;
|
|
321
|
+
/**
|
|
322
|
+
* Represents the result of a transformation.
|
|
323
|
+
*/
|
|
324
|
+
interface TransformResult {
|
|
325
|
+
className: string;
|
|
326
|
+
attributes: Record<string, string>;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Transforms a csszyx sz object into a Tailwind CSS className string and extracted attributes.
|
|
330
|
+
*
|
|
331
|
+
* @param {SzObject} szProp - The sz object from JSX
|
|
332
|
+
* @param {string} prefix - Variant prefix for nested properties
|
|
333
|
+
* @param {Record<string, string>} [mangleMap] - Optional map for property name mangling
|
|
334
|
+
* @returns {TransformResult} The transformation result
|
|
335
|
+
*/
|
|
336
|
+
declare function transform(szProp: SzObject, prefix?: string, mangleMap?: Record<string, string>): TransformResult;
|
|
337
|
+
/**
|
|
338
|
+
* Validates that an sz prop object is valid.
|
|
339
|
+
*
|
|
340
|
+
* @param {unknown} szProp - The value to validate
|
|
341
|
+
* @returns {boolean} True if valid, false otherwise
|
|
342
|
+
*/
|
|
343
|
+
declare function isValidSzProp(szProp: unknown): szProp is SzObject;
|
|
344
|
+
/**
|
|
345
|
+
* Normalizes a className string by removing extra whitespace.
|
|
346
|
+
*
|
|
347
|
+
* @param {string} className - The className string to normalize
|
|
348
|
+
* @returns {string} The normalized className string
|
|
349
|
+
*/
|
|
350
|
+
declare function normalizeClassName(className: string): string;
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Options for {@link transformSourceCode}.
|
|
354
|
+
*/
|
|
355
|
+
interface TransformSourceCodeOptions {
|
|
356
|
+
/**
|
|
357
|
+
* Override the AST node budget. Files larger than this throw
|
|
358
|
+
* {@link ASTBudgetExceededError}. Defaults to {@link AST_BUDGET} (50 000).
|
|
359
|
+
* Useful for repos with legitimately large generated files (json-as-ts
|
|
360
|
+
* fixtures, GraphQL schema snapshots) that exceed the default cap but
|
|
361
|
+
* are still safe to transform.
|
|
362
|
+
*/
|
|
363
|
+
astBudget?: number;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Transforms all sz props in a source code string into Tailwind classNames.
|
|
367
|
+
*
|
|
368
|
+
* @param {string} source - The source code to transform
|
|
369
|
+
* @param {string} [filename] - Source filename, used in error messages and
|
|
370
|
+
* passed to Babel as the parser filename. Defaults to a placeholder.
|
|
371
|
+
* @param {TransformSourceCodeOptions} [options] - Optional overrides
|
|
372
|
+
* (currently: `astBudget` to raise/lower the per-file node cap).
|
|
373
|
+
* @returns {object} Transformation result with code and metadata
|
|
374
|
+
* @throws {ASTBudgetExceededError} when the file's AST exceeds the
|
|
375
|
+
* effective budget (`options.astBudget` or {@link AST_BUDGET}).
|
|
376
|
+
*/
|
|
377
|
+
declare function transformSourceCode(source: string, filename?: string, options?: TransformSourceCodeOptions): {
|
|
378
|
+
code: string;
|
|
379
|
+
transformed: boolean;
|
|
380
|
+
usesRuntime: boolean;
|
|
381
|
+
usesMerge: boolean;
|
|
382
|
+
usesColorVar: boolean;
|
|
383
|
+
classes: Set<string>;
|
|
384
|
+
rawClassNames: Set<string>;
|
|
385
|
+
diagnostics: string[];
|
|
386
|
+
recoveryTokens: Map<string, TokenData>;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Core Compiler class for csszyx.
|
|
391
|
+
*
|
|
392
|
+
* This class manages the WASM lifecycle and provides high-performance
|
|
393
|
+
* transformation methods. It falls back to JavaScript if WASM is not available.
|
|
394
|
+
*/
|
|
395
|
+
declare class CsszyxCompiler {
|
|
396
|
+
private static instance;
|
|
397
|
+
private wasmLoaded;
|
|
398
|
+
/**
|
|
399
|
+
* Private constructor to enforce singleton pattern.
|
|
400
|
+
*/
|
|
401
|
+
private constructor();
|
|
402
|
+
/**
|
|
403
|
+
* Gets the singleton instance of the compiler.
|
|
404
|
+
*
|
|
405
|
+
* @returns {CsszyxCompiler} The compiler instance.
|
|
406
|
+
*/
|
|
407
|
+
static getInstance(): CsszyxCompiler;
|
|
408
|
+
/**
|
|
409
|
+
* Initializes the WASM core.
|
|
410
|
+
*
|
|
411
|
+
* @returns {Promise<void>} Resolves when WASM is ready.
|
|
412
|
+
*/
|
|
413
|
+
init(): Promise<void>;
|
|
414
|
+
/**
|
|
415
|
+
* Transforms an sz object into Tailwind classes.
|
|
416
|
+
*
|
|
417
|
+
* @param {SzObject} sz - The object to transform.
|
|
418
|
+
* @returns {string} The transformed class string.
|
|
419
|
+
*/
|
|
420
|
+
transform(sz: SzObject): string;
|
|
421
|
+
/**
|
|
422
|
+
* Checks if the WASM core is currently active.
|
|
423
|
+
*
|
|
424
|
+
* @returns {boolean} True if WASM is loaded.
|
|
425
|
+
*/
|
|
426
|
+
isWasmActive(): boolean;
|
|
427
|
+
/**
|
|
428
|
+
* Generates a recovery token using WASM or JS fallback.
|
|
429
|
+
*
|
|
430
|
+
* @param {object} metadata - Token metadata
|
|
431
|
+
* @param metadata.component - Component name
|
|
432
|
+
* @param metadata.filePath - File path source
|
|
433
|
+
* @param metadata.line - Line number
|
|
434
|
+
* @param metadata.column - Column number
|
|
435
|
+
* @param metadata.mode - Build mode (dev/prod)
|
|
436
|
+
* @param metadata.buildId - Unique build identifier
|
|
437
|
+
* @returns {string} The generated token
|
|
438
|
+
*/
|
|
439
|
+
generateRecoveryToken(metadata: {
|
|
440
|
+
component: string;
|
|
441
|
+
filePath: string;
|
|
442
|
+
line: number;
|
|
443
|
+
column: number;
|
|
444
|
+
mode: 'csr' | 'dev-only';
|
|
445
|
+
buildId: string;
|
|
446
|
+
}): string;
|
|
447
|
+
}
|
|
448
|
+
|
|
429
449
|
/**
|
|
430
450
|
* Property Type System for CSS Variable Auto-Compile.
|
|
431
451
|
*
|
package/dist/index.js
CHANGED
|
@@ -270,6 +270,39 @@ function stripInvalidColorStrings(sz) {
|
|
|
270
270
|
import * as babel from "@babel/core";
|
|
271
271
|
import * as t from "@babel/types";
|
|
272
272
|
|
|
273
|
+
// src/ast-budget.ts
|
|
274
|
+
var AST_BUDGET = 5e4;
|
|
275
|
+
var ASTBudgetExceededError = class extends Error {
|
|
276
|
+
/**
|
|
277
|
+
*
|
|
278
|
+
* @param filename Source filename if known, otherwise `undefined`.
|
|
279
|
+
* @param nodeCount Node count at the point traversal was aborted.
|
|
280
|
+
* @param budget Effective budget that was exceeded. Defaults to
|
|
281
|
+
* {@link AST_BUDGET} for backwards compatibility with callers that
|
|
282
|
+
* don't pass an override.
|
|
283
|
+
*/
|
|
284
|
+
constructor(filename, nodeCount, budget = AST_BUDGET) {
|
|
285
|
+
const where = filename ?? "<anonymous>";
|
|
286
|
+
super(
|
|
287
|
+
`[csszyx] AST budget exceeded: ${where} has more than ${budget} nodes (traversal aborted at ${nodeCount}). Files this large are almost always machine-generated and should be excluded from sz transformation. Either exclude the file from the plugin (Vite: \`csszyx({ exclude: [/large-data\\.ts$/] })\`), or raise the limit globally with \`csszyx({ build: { astBudgetLimit: 100_000 } })\`.`
|
|
288
|
+
);
|
|
289
|
+
this.name = "ASTBudgetExceededError";
|
|
290
|
+
this.filename = filename;
|
|
291
|
+
this.nodeCount = nodeCount;
|
|
292
|
+
this.budget = budget;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// src/recovery-tokens.ts
|
|
297
|
+
import { createHash } from "crypto";
|
|
298
|
+
function generateInlineRecoveryToken(filename, line, column, elementType) {
|
|
299
|
+
const input = `${filename}:${line}:${column}:${elementType}`;
|
|
300
|
+
return createHash("sha256").update(input).digest("hex").substring(0, 12);
|
|
301
|
+
}
|
|
302
|
+
function isValidInlineRecoveryMode(value) {
|
|
303
|
+
return value === "csr" || value === "dev-only";
|
|
304
|
+
}
|
|
305
|
+
|
|
273
306
|
// src/transform-core.ts
|
|
274
307
|
var PROPERTY_MAP = {
|
|
275
308
|
// Background
|
|
@@ -2262,7 +2295,8 @@ function normalizeClassName(className) {
|
|
|
2262
2295
|
}
|
|
2263
2296
|
|
|
2264
2297
|
// src/transform.ts
|
|
2265
|
-
function transformSourceCode(source) {
|
|
2298
|
+
function transformSourceCode(source, filename, options) {
|
|
2299
|
+
const astBudget = options?.astBudget ?? AST_BUDGET;
|
|
2266
2300
|
let usesRuntime = false;
|
|
2267
2301
|
let usesMerge = false;
|
|
2268
2302
|
let usesColorVar = false;
|
|
@@ -2270,12 +2304,13 @@ function transformSourceCode(source) {
|
|
|
2270
2304
|
const collectedClasses = /* @__PURE__ */ new Set();
|
|
2271
2305
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2272
2306
|
const diagnostics = [];
|
|
2307
|
+
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
2273
2308
|
if (!source.includes("sz")) {
|
|
2274
|
-
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics };
|
|
2309
|
+
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
|
|
2275
2310
|
}
|
|
2276
2311
|
try {
|
|
2277
2312
|
const result = babel.transformSync(source, {
|
|
2278
|
-
filename: "file.tsx",
|
|
2313
|
+
filename: filename ?? "file.tsx",
|
|
2279
2314
|
// Enable TS/JSX parsing
|
|
2280
2315
|
ast: true,
|
|
2281
2316
|
code: true,
|
|
@@ -2287,6 +2322,21 @@ function transformSourceCode(source) {
|
|
|
2287
2322
|
plugins: [
|
|
2288
2323
|
function() {
|
|
2289
2324
|
return {
|
|
2325
|
+
// Budget guard runs in `pre` (before the visitor pass)
|
|
2326
|
+
// so it short-circuits pathologically large files
|
|
2327
|
+
// before any sz transform work begins, and doesn't
|
|
2328
|
+
// interfere with the JSXAttribute handler below.
|
|
2329
|
+
pre(file) {
|
|
2330
|
+
let nodeCount = 0;
|
|
2331
|
+
babel.traverse(file.ast, {
|
|
2332
|
+
enter() {
|
|
2333
|
+
nodeCount++;
|
|
2334
|
+
if (nodeCount > astBudget) {
|
|
2335
|
+
throw new ASTBudgetExceededError(filename, nodeCount, astBudget);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
});
|
|
2339
|
+
},
|
|
2290
2340
|
visitor: {
|
|
2291
2341
|
JSXAttribute(path) {
|
|
2292
2342
|
const attrName = t.isJSXIdentifier(path.node.name) ? path.node.name.name : "";
|
|
@@ -2301,6 +2351,50 @@ function transformSourceCode(source) {
|
|
|
2301
2351
|
}
|
|
2302
2352
|
return;
|
|
2303
2353
|
}
|
|
2354
|
+
if (attrName === "szRecover") {
|
|
2355
|
+
const recoverValue = path.node.value;
|
|
2356
|
+
if (!t.isStringLiteral(recoverValue)) {
|
|
2357
|
+
diagnostics.push(
|
|
2358
|
+
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: only string-literal values ("csr" | "dev-only") are supported. Dynamic values disable token emission for this element.`
|
|
2359
|
+
);
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
if (!isValidInlineRecoveryMode(recoverValue.value)) {
|
|
2363
|
+
diagnostics.push(
|
|
2364
|
+
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: unknown mode "${recoverValue.value}" \u2014 expected "csr" or "dev-only". Token emission skipped.`
|
|
2365
|
+
);
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
const opening = path.parentPath;
|
|
2369
|
+
if (!opening?.isJSXOpeningElement()) {
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
const alreadyTagged = opening.node.attributes.some(
|
|
2373
|
+
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === "data-sz-recovery-token"
|
|
2374
|
+
);
|
|
2375
|
+
if (alreadyTagged) {
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
const loc = path.node.loc;
|
|
2379
|
+
const elementType = t.isJSXIdentifier(opening.node.name) ? opening.node.name.name : t.isJSXMemberExpression(opening.node.name) ? "<member>" : "<unknown>";
|
|
2380
|
+
const line = loc?.start.line ?? 0;
|
|
2381
|
+
const column = loc?.start.column ?? 0;
|
|
2382
|
+
const file = filename ?? "file.tsx";
|
|
2383
|
+
const token = generateInlineRecoveryToken(file, line, column, elementType);
|
|
2384
|
+
opening.node.attributes.push(
|
|
2385
|
+
t.jsxAttribute(
|
|
2386
|
+
t.jsxIdentifier("data-sz-recovery-token"),
|
|
2387
|
+
t.stringLiteral(token)
|
|
2388
|
+
)
|
|
2389
|
+
);
|
|
2390
|
+
recoveryTokens.set(token, {
|
|
2391
|
+
mode: recoverValue.value,
|
|
2392
|
+
component: elementType,
|
|
2393
|
+
path: `${file}:${line}:${column}`
|
|
2394
|
+
});
|
|
2395
|
+
transformed = true;
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2304
2398
|
if (attrName !== "sz") {
|
|
2305
2399
|
return;
|
|
2306
2400
|
}
|
|
@@ -2803,11 +2897,15 @@ function transformSourceCode(source) {
|
|
|
2803
2897
|
usesColorVar,
|
|
2804
2898
|
classes: collectedClasses,
|
|
2805
2899
|
rawClassNames,
|
|
2806
|
-
diagnostics
|
|
2900
|
+
diagnostics,
|
|
2901
|
+
recoveryTokens
|
|
2807
2902
|
};
|
|
2808
2903
|
} catch (e) {
|
|
2904
|
+
if (e instanceof ASTBudgetExceededError) {
|
|
2905
|
+
throw e;
|
|
2906
|
+
}
|
|
2809
2907
|
console.warn("[csszyx] AST transform failed, falling back to original code:", e);
|
|
2810
|
-
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics };
|
|
2908
|
+
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
|
|
2811
2909
|
}
|
|
2812
2910
|
}
|
|
2813
2911
|
function parseStyleStringToObjectExpr(styleStr) {
|
|
@@ -3374,7 +3472,7 @@ function injectRecoveryToken(attributes, token) {
|
|
|
3374
3472
|
}
|
|
3375
3473
|
|
|
3376
3474
|
// src/manifest.ts
|
|
3377
|
-
import { createHash } from "crypto";
|
|
3475
|
+
import { createHash as createHash2 } from "crypto";
|
|
3378
3476
|
var ManifestBuilder = class {
|
|
3379
3477
|
/**
|
|
3380
3478
|
* Creates a new manifest builder.
|
|
@@ -3447,7 +3545,7 @@ var ManifestBuilder = class {
|
|
|
3447
3545
|
sortedTokens[key] = tokens[key];
|
|
3448
3546
|
}
|
|
3449
3547
|
const content = JSON.stringify(sortedTokens);
|
|
3450
|
-
return
|
|
3548
|
+
return createHash2("sha256").update(content).digest("hex");
|
|
3451
3549
|
}
|
|
3452
3550
|
/**
|
|
3453
3551
|
* Builds the final recovery manifest.
|
|
@@ -3657,7 +3755,7 @@ function hoistCSSVariables(usages, parentMap) {
|
|
|
3657
3755
|
}
|
|
3658
3756
|
function buildParentMap(ast) {
|
|
3659
3757
|
const map = /* @__PURE__ */ new Map();
|
|
3660
|
-
function
|
|
3758
|
+
function traverse2(node, parent) {
|
|
3661
3759
|
if (parent) {
|
|
3662
3760
|
map.set(node, parent);
|
|
3663
3761
|
}
|
|
@@ -3667,16 +3765,16 @@ function buildParentMap(ast) {
|
|
|
3667
3765
|
if (Array.isArray(value)) {
|
|
3668
3766
|
for (const item of value) {
|
|
3669
3767
|
if (item && typeof item === "object" && "type" in item) {
|
|
3670
|
-
|
|
3768
|
+
traverse2(item, node);
|
|
3671
3769
|
}
|
|
3672
3770
|
}
|
|
3673
3771
|
} else if ("type" in value) {
|
|
3674
|
-
|
|
3772
|
+
traverse2(value, node);
|
|
3675
3773
|
}
|
|
3676
3774
|
}
|
|
3677
3775
|
}
|
|
3678
3776
|
}
|
|
3679
|
-
|
|
3777
|
+
traverse2(ast);
|
|
3680
3778
|
return map;
|
|
3681
3779
|
}
|
|
3682
3780
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csszyx/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Core compiler and transformation logic for csszyx",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"csszyx",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@babel/core": "^7.23.7",
|
|
48
48
|
"@babel/types": "^7.23.6",
|
|
49
49
|
"@babel/traverse": "^7.23.7",
|
|
50
|
-
"@csszyx/core": "0.
|
|
50
|
+
"@csszyx/core": "0.6.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/babel__core": "^7.20.5",
|