@plumeria/utils 19.2.14 → 19.2.16

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/parser.d.ts CHANGED
@@ -43,6 +43,7 @@ export declare function traverse(node: Module | JSXExpression, visitor: {
43
43
  }) => void;
44
44
  }): void;
45
45
  export declare function objectExpressionToObject(node: ObjectExpression, staticTable: StaticTable, keyframesHashTable: KeyframesHashTable, viewTransitionHashTable: ViewTransitionHashTable, createThemeHashTable: CreateThemeHashTable, createThemeObjectTable: CreateThemeObjectTable, createHashTable: CreateHashTable, createStaticHashTable: CreateStaticHashTable, createStaticObjectTable: CreateStaticObjectTable, resolveVariable?: (name: string) => any): CSSObject;
46
+ export declare function collectLocalConstNodes(ast: Module): Map<string, any>;
46
47
  export declare function collectLocalConsts(ast: Module): Record<string, any>;
47
48
  export declare function resolveThemeSelector(node: Expression, staticTable: StaticTable, createStaticHashTable: CreateStaticHashTable, createStaticObjectTable: CreateStaticObjectTable): string;
48
49
  export declare function resolveFileError(actualPath: string, importedName: string): {
package/dist/parser.js CHANGED
@@ -39,6 +39,7 @@ exports.resolveOriginError = resolveOriginError;
39
39
  exports.resolveComponentKey = resolveComponentKey;
40
40
  exports.traverse = traverse;
41
41
  exports.objectExpressionToObject = objectExpressionToObject;
42
+ exports.collectLocalConstNodes = collectLocalConstNodes;
42
43
  exports.collectLocalConsts = collectLocalConsts;
43
44
  exports.resolveThemeSelector = resolveThemeSelector;
44
45
  exports.resolveFileError = resolveFileError;
@@ -101,6 +102,35 @@ const getRootIdentifier = (node) => {
101
102
  return null;
102
103
  };
103
104
  exports.getRootIdentifier = getRootIdentifier;
105
+ const EXPRESSION_KINDS = {
106
+ NullLiteral: 'null',
107
+ ObjectExpression: 'an object literal',
108
+ ArrayExpression: 'an array literal',
109
+ CallExpression: 'a function call',
110
+ NewExpression: 'a new expression',
111
+ ConditionalExpression: 'a conditional expression',
112
+ ArrowFunctionExpression: 'a function',
113
+ FunctionExpression: 'a function',
114
+ TaggedTemplateExpression: 'a tagged template',
115
+ AwaitExpression: 'an await expression',
116
+ };
117
+ const expressionLabel = (node) => {
118
+ node = unwrapExpression(node);
119
+ if (exports.t.isIdentifier(node))
120
+ return node.value;
121
+ if (exports.t.isStringLiteral(node))
122
+ return `'${node.value}'`;
123
+ if (exports.t.isNumericLiteral(node))
124
+ return String(node.value);
125
+ if (exports.t.isMemberExpression(node)) {
126
+ const property = node.property;
127
+ if (property.type === 'Identifier')
128
+ return `${expressionLabel(node.object)}.${property.value}`;
129
+ if (property.type === 'Computed')
130
+ return `${expressionLabel(node.object)}[${expressionLabel(property.expression)}]`;
131
+ }
132
+ return EXPRESSION_KINDS[node.type] ?? 'an expression';
133
+ };
104
134
  const getNamespaceMember = (node, rootName) => {
105
135
  node = unwrapExpression(node);
106
136
  if (exports.t.isCallExpression(node)) {
@@ -277,7 +307,7 @@ function objectExpressionToObject(node, staticTable, keyframesHashTable, viewTra
277
307
  [root]: resolved,
278
308
  }));
279
309
  if (member === undefined)
280
- throw new Error(`[plumeria] Unknown style member on ${root}.`);
310
+ throw new Error(`[plumeria] Unknown style member: ${expressionLabel(val)} does not exist.`);
281
311
  obj[key] = member;
282
312
  return;
283
313
  }
@@ -343,8 +373,7 @@ function objectExpressionToObject(node, staticTable, keyframesHashTable, viewTra
343
373
  });
344
374
  return obj;
345
375
  }
346
- function collectLocalConsts(ast) {
347
- const localConsts = {};
376
+ function collectLocalConstNodes(ast) {
348
377
  const decls = new Map();
349
378
  for (const node of ast.body) {
350
379
  let declarations = [];
@@ -363,6 +392,11 @@ function collectLocalConsts(ast) {
363
392
  }
364
393
  }
365
394
  }
395
+ return decls;
396
+ }
397
+ function collectLocalConsts(ast) {
398
+ const localConsts = {};
399
+ const decls = collectLocalConstNodes(ast);
366
400
  const visiting = new Set();
367
401
  function resolveValue(name) {
368
402
  if (localConsts[name] !== undefined)
@@ -679,7 +713,7 @@ function evaluateTemplateLiteral(node, staticTable, keyframesHashTable, viewTran
679
713
  const expr = node.expressions[i];
680
714
  const evaluatedExpr = evaluateExpression(expr, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
681
715
  if (evaluatedExpr === null || typeof evaluatedExpr === 'object')
682
- throw new Error('[plumeria] Template value cannot be resolved to a primitive.');
716
+ throw new Error(`[plumeria] Template value cannot be resolved to a primitive: ${expressionLabel(expr)} inside \${} must resolve to a string or number at build time.`);
683
717
  result += String(evaluatedExpr);
684
718
  }
685
719
  }
@@ -747,7 +781,7 @@ function evaluateBinaryExpression(node, staticTable, keyframesHashTable, viewTra
747
781
  const rightType = right === null ? 'null' : typeof right;
748
782
  throw new Error(`[plumeria] Binary operator ${node.operator} requires ${expected} operands; received ${leftType} and ${rightType}.`);
749
783
  }
750
- throw new Error(`[plumeria] Unsupported binary operator: ${node.operator}`);
784
+ throw new Error(`[plumeria] Unsupported binary operator: ${node.operator}. Use arithmetic, bitwise, &&, ||, or ?? operators, which can be resolved at build time.`);
751
785
  }
752
786
  function evaluateCallExpression(node, staticTable) {
753
787
  const callee = node.callee;
@@ -821,7 +855,7 @@ function evaluateExpression(node, staticTable, keyframesHashTable, viewTransitio
821
855
  return createStaticObjectTable[hash];
822
856
  }
823
857
  }
824
- throw new Error(`[plumeria] Cannot resolve static value: ${node.value}`);
858
+ throw new Error(`[plumeria] Cannot resolve static value: ${node.value}. It must be a const holding a string or number, declared in this file or imported from a module plumeria can read.`);
825
859
  }
826
860
  if (exports.t.isMemberExpression(node)) {
827
861
  const resolved = resolveStaticTableMemberExpression(node, staticTable);
@@ -836,7 +870,7 @@ function evaluateExpression(node, staticTable, keyframesHashTable, viewTransitio
836
870
  if (resolvedStatic !== undefined) {
837
871
  return resolvedStatic;
838
872
  }
839
- throw new Error('[plumeria] Cannot resolve static member expression.');
873
+ throw new Error(`[plumeria] Cannot resolve static member expression: ${expressionLabel(node)}. Its object must be a const or a value created by css.createStatic or css.createTheme.`);
840
874
  }
841
875
  if (exports.t.isBinaryExpression(node)) {
842
876
  return evaluateBinaryExpression(node, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
@@ -856,12 +890,12 @@ function evaluateExpression(node, staticTable, keyframesHashTable, viewTransitio
856
890
  if (node.operator === '~')
857
891
  return ~value;
858
892
  }
859
- throw new Error(`[plumeria] Unsupported unary operand for ${node.operator}`);
893
+ throw new Error(`[plumeria] Unsupported unary operand for ${node.operator}: ${expressionLabel(node.argument)} must resolve to a number at build time.`);
860
894
  }
861
895
  if (exports.t.isParenthesisExpression(node)) {
862
896
  return evaluateExpression(node.expression, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
863
897
  }
864
- throw new Error(`[plumeria] Unsupported expression type: ${node.type}`);
898
+ throw new Error(`[plumeria] Unsupported expression type: ${expressionLabel(node)}. Style values must be literals, consts, or arithmetic and template expressions of them.`);
865
899
  }
866
900
  function resolveKeyframesTableMemberExpression(node, keyframesHashTable) {
867
901
  if (exports.t.isIdentifier(node)) {
@@ -1681,7 +1715,7 @@ function runScan(scanCwd = process.cwd()) {
1681
1715
  else if (method === 'createTheme') {
1682
1716
  const selector = resolveThemeSelector(init.arguments[0].expression, scopedStaticTable, localCreateStaticHashTable, localCreateStaticObjectTable);
1683
1717
  if (!selector)
1684
- throw new Error('[plumeria] createTheme requires a statically resolvable non-empty selector.');
1718
+ throw new Error('[plumeria] createTheme needs a non-empty selector it can read at build time. Pass a string literal such as ".dark", or a name this file declares as one.');
1685
1719
  const hash = (0, createTheme_1.themeHashOf)(selector, obj);
1686
1720
  localTables.createThemeObjectTable[hash] = obj;
1687
1721
  localCreateThemeObjectTable[hash] = obj;
package/dist/transform.js CHANGED
@@ -38,6 +38,42 @@ const core_1 = require("@swc/core");
38
38
  const path = __importStar(require("path"));
39
39
  const zss_engine_1 = require("zss-engine");
40
40
  const parser_1 = require("./parser");
41
+ const unresolvableValue_1 = require("./unresolvableValue");
42
+ const spreadValues = (tables, constNodes, sourceOf) => {
43
+ const spread = (prop) => {
44
+ let values;
45
+ try {
46
+ values = (0, parser_1.objectExpressionToObject)({ properties: [prop] }, ...tables);
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ const argument = prop.arguments;
52
+ const declared = argument?.type === 'Identifier'
53
+ ? constNodes.get(argument.value)
54
+ : undefined;
55
+ const source = declared && parser_1.t.isObjectExpression(declared) ? declared : undefined;
56
+ return { values, source };
57
+ };
58
+ const resolvesValue = (value) => {
59
+ try {
60
+ const probe = (0, parser_1.objectExpressionToObject)({
61
+ properties: [
62
+ {
63
+ type: 'KeyValueProperty',
64
+ key: { type: 'Identifier', value: '__probe' },
65
+ value,
66
+ },
67
+ ],
68
+ }, ...tables);
69
+ return '__probe' in probe;
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ };
75
+ return { spread, resolvesValue, sourceOf };
76
+ };
41
77
  const create_1 = require("./create");
42
78
  const dynamicKey_1 = require("./dynamicKey");
43
79
  const escalation_1 = require("./escalation");
@@ -92,9 +128,9 @@ const destructuredPropAliases = (fn) => {
92
128
  }
93
129
  return aliases;
94
130
  };
95
- const propDefaultMessage = (source) => `Plumeria: A style prop default must be a defined style: "${source}". ` +
131
+ const propDefaultMessage = (source) => `[plumeria] A style prop default must be a defined style: "${source}". ` +
96
132
  `Apply a conditional or dynamic style where the element is styled.`;
97
- const spreadStyleMessage = (source) => `Plumeria: Spread elements in a style array are not supported: "...${source}". ` +
133
+ const spreadStyleMessage = (source) => `[plumeria] Spread elements in a style array are not supported: "...${source}". ` +
98
134
  `List each style explicitly.`;
99
135
  const resolveLocalStyleAlias = (aliases, expression) => {
100
136
  let current = expression;
@@ -160,6 +196,11 @@ const transformSource = async (env) => {
160
196
  const sourceBuffer = Buffer.from(source, 'utf-8');
161
197
  const leadingBytes = Buffer.byteLength(source.slice(0, leadingLen), 'utf-8');
162
198
  const baseByteOffset = ast.span.start - leadingBytes;
199
+ const getSource = (node) => {
200
+ const start = node.span.start - baseByteOffset;
201
+ const end = node.span.end - baseByteOffset;
202
+ return sourceBuffer.subarray(start, end).toString('utf-8');
203
+ };
163
204
  const throwCompilationError = (message, node) => {
164
205
  let suffix = '';
165
206
  if (node) {
@@ -196,16 +237,16 @@ const transformSource = async (env) => {
196
237
  if (!isPlumeriaStyle) {
197
238
  const failure = (0, parser_1.resolveOriginError)(node, rootId, localImports);
198
239
  if (failure) {
199
- throwCompilationError(`Plumeria: ${failure.message} (${path.basename(failure.filePath)})`);
240
+ throwCompilationError(`[plumeria] ${failure.message} (${path.basename(failure.filePath)})`);
200
241
  }
201
- throwCompilationError(`Plumeria: Dynamic or unresolvable style object "${getSource(node)}" is not supported.`, node);
242
+ throwCompilationError(`[plumeria] Dynamic or unresolvable style object "${getSource(node)}" is not supported.`, node);
202
243
  }
203
244
  }
204
245
  };
205
246
  const scannedTables = (0, parser_1.scanOverlay)();
206
247
  const ownFailure = (0, parser_1.resolveFileError)(baseId, '');
207
248
  if (ownFailure)
208
- throwCompilationError(`Plumeria: ${ownFailure.message}`);
249
+ throwCompilationError(`[plumeria] ${ownFailure.message}`);
209
250
  for (const node of ast.body) {
210
251
  if (node.type === 'ImportDeclaration') {
211
252
  const sourcePath = node.source.value;
@@ -309,6 +350,7 @@ const transformSource = async (env) => {
309
350
  return records;
310
351
  };
311
352
  const localConsts = (0, parser_1.collectLocalConsts)(ast);
353
+ const localConstNodes = (0, parser_1.collectLocalConstNodes)(ast);
312
354
  const importMap = {};
313
355
  const keyframesImportMap = {};
314
356
  const viewTransitionImportMap = {};
@@ -568,20 +610,30 @@ const transformSource = async (env) => {
568
610
  if (propName && init && parser_1.t.isCallExpression(init)) {
569
611
  if (['create', 'createTheme', 'createStatic'].includes(propName) &&
570
612
  !topLevelDeclarators.has(node)) {
571
- throwCompilationError(`Plumeria: css.${propName} must be assigned to a top-level variable so its styles can be resolved across files. Move this declaration outside the function or block.`, node);
613
+ throwCompilationError(`[plumeria] css.${propName} must be assigned to a top-level variable so its styles can be resolved across files. Move this declaration outside the function or block.`, node);
572
614
  }
573
615
  if (['create', 'createTheme', 'createStatic'].includes(propName)) {
574
616
  const argumentIndex = propName === 'createTheme' ? 1 : 0;
575
617
  const argument = init.arguments[argumentIndex];
576
618
  const object = argument && literalObjectArgument(argument.expression);
577
619
  if (!object)
578
- throwCompilationError(`Plumeria: css.${propName} needs a style object it can read at build time. Pass an object literal or a top-level constant containing one.`, init);
620
+ throwCompilationError(`[plumeria] css.${propName} needs a style object it can read at build time. Pass an object literal or a top-level constant containing one.`, init);
579
621
  argument.expression = object;
580
622
  registeredStyleCalls.add(init.span.start);
581
623
  }
582
624
  if (propName === 'create' &&
583
625
  parser_1.t.isObjectExpression(init.arguments[0].expression)) {
584
626
  const obj = (0, parser_1.objectExpressionToObject)(init.arguments[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
627
+ (0, unresolvableValue_1.assertNoDroppedValues)(init.arguments[0].expression, obj, spreadValues([
628
+ mergedStaticTable,
629
+ mergedKeyframesTable,
630
+ mergedViewTransitionTable,
631
+ mergedCreateThemeHashTable,
632
+ scannedTables.createThemeObjectTable,
633
+ mergedCreateTable,
634
+ mergedCreateStaticHashTable,
635
+ scannedTables.createStaticObjectTable,
636
+ ], localConstNodes, getSource));
585
637
  if (obj) {
586
638
  const hashMap = {};
587
639
  Object.entries(obj).forEach(([key, style]) => {
@@ -625,13 +677,23 @@ const transformSource = async (env) => {
625
677
  const selectorExpr = init.arguments[0].expression;
626
678
  const selector = (0, parser_1.resolveThemeSelector)(selectorExpr, mergedStaticTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
627
679
  if (!selector) {
628
- throwCompilationError(`Plumeria: createTheme needs a selector it can read at build time. ` +
680
+ throwCompilationError(`[plumeria] createTheme needs a selector it can read at build time. ` +
629
681
  `Pass a string literal such as ".dark", or a name this file declares as one.`, selectorExpr);
630
682
  }
631
683
  if (selector.startsWith('@') && !(0, zss_engine_1.isAtRule)(selector)) {
632
- throwCompilationError(`Plumeria: Unsupported at-rule: "${selector}". createTheme only supports nesting at-rules such as @media, @container, @supports, @layer, and @scope.`, selectorExpr);
684
+ throwCompilationError(`[plumeria] Unsupported at-rule: "${selector}". createTheme only supports nesting at-rules such as @media, @container, @supports, @layer, and @scope.`, selectorExpr);
633
685
  }
634
686
  const obj = (0, parser_1.objectExpressionToObject)(init.arguments[1].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
687
+ (0, unresolvableValue_1.assertNoDroppedValues)(init.arguments[1].expression, obj, spreadValues([
688
+ mergedStaticTable,
689
+ mergedKeyframesTable,
690
+ mergedViewTransitionTable,
691
+ mergedCreateThemeHashTable,
692
+ scannedTables.createThemeObjectTable,
693
+ mergedCreateTable,
694
+ mergedCreateStaticHashTable,
695
+ scannedTables.createStaticObjectTable,
696
+ ], localConstNodes, getSource));
635
697
  const hash = (0, createTheme_1.themeHashOf)(selector, obj);
636
698
  if (parser_1.t.isIdentifier(node.id)) {
637
699
  const uniqueKey = `${resourcePath}-${node.id.value}`;
@@ -670,6 +732,16 @@ const transformSource = async (env) => {
670
732
  idSpans.add(node.id.span.start);
671
733
  }
672
734
  const obj = (0, parser_1.objectExpressionToObject)(init.arguments[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
735
+ (0, unresolvableValue_1.assertNoDroppedValues)(init.arguments[0].expression, obj, spreadValues([
736
+ mergedStaticTable,
737
+ mergedKeyframesTable,
738
+ mergedViewTransitionTable,
739
+ mergedCreateThemeHashTable,
740
+ scannedTables.createThemeObjectTable,
741
+ mergedCreateTable,
742
+ mergedCreateStaticHashTable,
743
+ scannedTables.createStaticObjectTable,
744
+ ], localConstNodes, getSource));
673
745
  const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
674
746
  if (parser_1.t.isIdentifier(node.id)) {
675
747
  const uniqueKey = `${resourcePath}-${node.id.value}`;
@@ -775,13 +847,23 @@ const transformSource = async (env) => {
775
847
  if (propName) {
776
848
  if (['create', 'createTheme', 'createStatic'].includes(propName) &&
777
849
  !registeredStyleCalls.has(node.span.start)) {
778
- throwCompilationError(`Plumeria: css.${propName} must be assigned to a named top-level variable. Destructuring, assignment statements, and default-exported calls cannot be compiled.`, node);
850
+ throwCompilationError(`[plumeria] css.${propName} must be assigned to a named top-level variable. Destructuring, assignment statements, and default-exported calls cannot be compiled.`, node);
779
851
  }
780
852
  const args = node.arguments;
781
853
  if (propName === 'keyframes' && args.length > 0) {
782
854
  const expr = args[0].expression;
783
855
  if (parser_1.t.isObjectExpression(expr)) {
784
856
  const obj = (0, parser_1.objectExpressionToObject)(expr, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
857
+ (0, unresolvableValue_1.assertNoDroppedValues)(expr, obj, spreadValues([
858
+ mergedStaticTable,
859
+ mergedKeyframesTable,
860
+ mergedViewTransitionTable,
861
+ mergedCreateThemeHashTable,
862
+ scannedTables.createThemeObjectTable,
863
+ mergedCreateTable,
864
+ mergedCreateStaticHashTable,
865
+ scannedTables.createStaticObjectTable,
866
+ ], localConstNodes, getSource));
785
867
  const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
786
868
  scannedTables.keyframesObjectTable[hash] = obj;
787
869
  replacements.push({
@@ -795,6 +877,16 @@ const transformSource = async (env) => {
795
877
  args.length > 0 &&
796
878
  parser_1.t.isObjectExpression(args[0].expression)) {
797
879
  const obj = (0, parser_1.objectExpressionToObject)(args[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
880
+ (0, unresolvableValue_1.assertNoDroppedValues)(args[0].expression, obj, spreadValues([
881
+ mergedStaticTable,
882
+ mergedKeyframesTable,
883
+ mergedViewTransitionTable,
884
+ mergedCreateThemeHashTable,
885
+ scannedTables.createThemeObjectTable,
886
+ mergedCreateTable,
887
+ mergedCreateStaticHashTable,
888
+ scannedTables.createStaticObjectTable,
889
+ ], localConstNodes, getSource));
798
890
  const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
799
891
  scannedTables.viewTransitionObjectTable[hash] = obj;
800
892
  replacements.push({
@@ -809,13 +901,23 @@ const transformSource = async (env) => {
809
901
  const selectorExpr = args[0].expression;
810
902
  const selector = (0, parser_1.resolveThemeSelector)(selectorExpr, mergedStaticTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
811
903
  if (!selector) {
812
- throwCompilationError(`Plumeria: createTheme needs a selector it can read at build time. ` +
904
+ throwCompilationError(`[plumeria] createTheme needs a selector it can read at build time. ` +
813
905
  `Pass a string literal such as ".dark", or a name this file declares as one.`, selectorExpr);
814
906
  }
815
907
  if (selector.startsWith('@') && !(0, zss_engine_1.isAtRule)(selector)) {
816
- throwCompilationError(`Plumeria: Unsupported at-rule: "${selector}". createTheme only supports nesting at-rules such as @media, @container, @supports, @layer, and @scope.`, selectorExpr);
908
+ throwCompilationError(`[plumeria] Unsupported at-rule: "${selector}". createTheme only supports nesting at-rules such as @media, @container, @supports, @layer, and @scope.`, selectorExpr);
817
909
  }
818
910
  const obj = (0, parser_1.objectExpressionToObject)(args[1].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
911
+ (0, unresolvableValue_1.assertNoDroppedValues)(args[1].expression, obj, spreadValues([
912
+ mergedStaticTable,
913
+ mergedKeyframesTable,
914
+ mergedViewTransitionTable,
915
+ mergedCreateThemeHashTable,
916
+ scannedTables.createThemeObjectTable,
917
+ mergedCreateTable,
918
+ mergedCreateStaticHashTable,
919
+ scannedTables.createStaticObjectTable,
920
+ ], localConstNodes, getSource));
819
921
  const hash = (0, createTheme_1.themeHashOf)(selector, obj);
820
922
  scannedTables.createThemeObjectTable[hash] = obj;
821
923
  if (scannedTables.createThemeSelectorTable) {
@@ -826,6 +928,16 @@ const transformSource = async (env) => {
826
928
  args.length > 0 &&
827
929
  parser_1.t.isObjectExpression(args[0].expression)) {
828
930
  const obj = (0, parser_1.objectExpressionToObject)(args[0].expression, mergedStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable);
931
+ (0, unresolvableValue_1.assertNoDroppedValues)(args[0].expression, obj, spreadValues([
932
+ mergedStaticTable,
933
+ mergedKeyframesTable,
934
+ mergedViewTransitionTable,
935
+ mergedCreateThemeHashTable,
936
+ scannedTables.createThemeObjectTable,
937
+ mergedCreateTable,
938
+ mergedCreateStaticHashTable,
939
+ scannedTables.createStaticObjectTable,
940
+ ], localConstNodes, getSource));
829
941
  const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
830
942
  scannedTables.createStaticObjectTable[hash] = obj;
831
943
  }
@@ -901,11 +1013,6 @@ const transformSource = async (env) => {
901
1013
  }
902
1014
  Object.values(n).forEach((val) => excludeSubtreeSpans(val));
903
1015
  };
904
- const getSource = (node) => {
905
- const start = node.span.start - baseByteOffset;
906
- const end = node.span.end - baseByteOffset;
907
- return sourceBuffer.subarray(start, end).toString('utf-8');
908
- };
909
1016
  const isVisibleReference = (expr) => {
910
1017
  if (parser_1.t.isIdentifier(expr))
911
1018
  return referenceIdents.references.has(expr.span.start);
@@ -1041,7 +1148,7 @@ const transformSource = async (env) => {
1041
1148
  const argExpr = callArgs[0]?.expression;
1042
1149
  if (callArgs.length > 1 ||
1043
1150
  (argExpr && argExpr.type !== 'ObjectExpression')) {
1044
- throwCompilationError(`Plumeria: ${getSource(expr)} takes one object argument, because ${callee.property.value} destructures its parameter.`, expr);
1151
+ throwCompilationError(`[plumeria] ${getSource(expr)} takes one object argument, because ${callee.property.value} destructures its parameter.`, expr);
1045
1152
  }
1046
1153
  const given = new Map();
1047
1154
  (argExpr?.properties ?? []).forEach((prop) => {
@@ -1061,7 +1168,7 @@ const transformSource = async (env) => {
1061
1168
  if (!source) {
1062
1169
  if (func.defaults?.[local])
1063
1170
  return;
1064
- return throwCompilationError(`Plumeria: ${getSource(expr)} leaves "${key}" unset, and a dynamic style function has no value to fall back on.`, expr);
1171
+ return throwCompilationError(`[plumeria] ${getSource(expr)} leaves "${key}" unset, and a dynamic style function has no value to fall back on.`, expr);
1065
1172
  }
1066
1173
  if (!forceRuntime &&
1067
1174
  isStaticArgValue(source) &&
@@ -1280,7 +1387,7 @@ const transformSource = async (env) => {
1280
1387
  const dynamic = resolveDynamicCall(node);
1281
1388
  if (dynamic) {
1282
1389
  if (!isStyleProp) {
1283
- throwCompilationError(`Plumeria: css.use(${getSource(node)}) does not support dynamic function keys.`, node);
1390
+ throwCompilationError(`[plumeria] css.use(${getSource(node)}) does not support dynamic function keys.`, node);
1284
1391
  }
1285
1392
  branchStyle = dynamic.style;
1286
1393
  dynamic.vars.forEach((v) => dynamicVars.push({
@@ -1409,7 +1516,7 @@ const transformSource = async (env) => {
1409
1516
  }
1410
1517
  const carriesVars = possibilities.some((entry) => entry.hasVars);
1411
1518
  if (carriesVars && !isStyleProp) {
1412
- throwCompilationError(`Plumeria: "${varName}" carries a dynamic function key, and css.use() returns only a class name. ` +
1519
+ throwCompilationError(`[plumeria] "${varName}" carries a dynamic function key, and css.use() returns only a class name. ` +
1413
1520
  `Apply it to ${styleProp} on the element instead.`, expr);
1414
1521
  }
1415
1522
  const gate = gates.length ? `(${gates.join(' && ')}) && ` : '';
@@ -2169,7 +2276,7 @@ const transformSource = async (env) => {
2169
2276
  }
2170
2277
  const { classParts, isOptimizable, baseStyle, dynamicVars, propVarSpreads, } = buildClassParts(args, dynamicClassParts, existingClassExpr, true);
2171
2278
  if (!isOptimizable) {
2172
- throwCompilationError(`Plumeria: Dynamic or unresolvable style object "${getSource(expr)}" is not supported.`, expr);
2279
+ throwCompilationError(`[plumeria] Dynamic or unresolvable style object "${getSource(expr)}" is not supported.`, expr);
2173
2280
  }
2174
2281
  const styleParts = [
2175
2282
  ...existingStyleParts,
@@ -2239,7 +2346,7 @@ const transformSource = async (env) => {
2239
2346
  const propKey = callee.property.value;
2240
2347
  const styleInfo = localCreateStyles[varName];
2241
2348
  if (styleInfo?.functions?.[propKey]) {
2242
- throwCompilationError(`Plumeria: css.use(${getSource(expr)}) does not support dynamic function keys.`, expr);
2349
+ throwCompilationError(`[plumeria] css.use(${getSource(expr)}) does not support dynamic function keys.`, expr);
2243
2350
  }
2244
2351
  }
2245
2352
  const { classParts, isOptimizable } = buildClassParts(args);
@@ -2252,7 +2359,7 @@ const transformSource = async (env) => {
2252
2359
  });
2253
2360
  }
2254
2361
  else {
2255
- throwCompilationError(`Plumeria: Dynamic or unresolvable style object "${getSource(node)}" is not supported.`, node);
2362
+ throwCompilationError(`[plumeria] Dynamic or unresolvable style object "${getSource(node)}" is not supported.`, node);
2256
2363
  }
2257
2364
  },
2258
2365
  });
@@ -2262,7 +2369,7 @@ const transformSource = async (env) => {
2262
2369
  if (appliedStyleProps.has(`${name}:${propName}`)) {
2263
2370
  continue;
2264
2371
  }
2265
- throwCompilationError(`Plumeria: "${propName}" is a style received through a prop but is never applied ` +
2372
+ throwCompilationError(`[plumeria] "${propName}" is a style received through a prop but is never applied ` +
2266
2373
  `to ${styleProp} or css.use() here. Apply it on an element this component renders; ` +
2267
2374
  `a style prop cannot be passed on to another component.`, node);
2268
2375
  }
@@ -2272,7 +2379,7 @@ const transformSource = async (env) => {
2272
2379
  if (!isDev || keys.length === 0) {
2273
2380
  return JSON.stringify('');
2274
2381
  }
2275
- const head = JSON.stringify(`Plumeria: "${info.name}.`);
2382
+ const head = JSON.stringify(`[plumeria] "${info.name}.`);
2276
2383
  const tail = JSON.stringify(`" was read at runtime. The file that read it was not compiled ` +
2277
2384
  `because it does not reference "@plumeria/core" — add ` +
2278
2385
  `import '@plumeria/core'; to it (see the stack below). Defined in ` +
@@ -2303,7 +2410,7 @@ const transformSource = async (env) => {
2303
2410
  const end = call.span.end - baseByteOffset;
2304
2411
  const isResolved = replacements.some((r) => r.start <= start && r.end >= end);
2305
2412
  if (!isResolved) {
2306
- throwCompilationError(`Plumeria: ${getSource(call)} is only supported in the ${styleProp} prop. ` +
2413
+ throwCompilationError(`[plumeria] ${getSource(call)} is only supported in the ${styleProp} prop. ` +
2307
2414
  `A dynamic style function resolves to a class name and a CSS variable on the element itself, ` +
2308
2415
  `so it cannot be passed through another prop or read as a value.`, call);
2309
2416
  }
@@ -0,0 +1,15 @@
1
+ import type { ObjectExpression, SpreadElement } from '@swc/core';
2
+ type SourceObject = ObjectExpression;
3
+ type StaticValues = Record<string, unknown>;
4
+ type SpreadInfo = {
5
+ values: StaticValues;
6
+ source?: SourceObject;
7
+ };
8
+ type ResolveSpread = (prop: SpreadElement) => SpreadInfo | null;
9
+ export type StyleContext = {
10
+ spread: ResolveSpread;
11
+ resolvesValue: (value: unknown) => boolean;
12
+ sourceOf?: (node: unknown) => string;
13
+ };
14
+ export declare const assertNoDroppedValues: (node: SourceObject, resolved: StaticValues | null | undefined, context?: StyleContext, ignore?: Set<string>) => void;
15
+ export {};
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertNoDroppedValues = void 0;
4
+ const keyValue = (key) => {
5
+ if (!key || typeof key !== 'object' || !('value' in key))
6
+ return;
7
+ const value = key.value;
8
+ return typeof value === 'string' || typeof value === 'number'
9
+ ? value
10
+ : undefined;
11
+ };
12
+ const unresolvableValue = (key, node, context) => new Error(`[plumeria] Cannot resolve the value of "${key}" at build time (${context?.sourceOf?.(node) ?? node.type}). ` +
13
+ `Values in css.create must be statically known; pass a runtime value through the ` +
14
+ `function form, css.create({ name: (value) => ({ ... }) }).`);
15
+ const overwrittenLater = (properties, index, key, context) => {
16
+ for (let i = index + 1; i < properties.length; i++) {
17
+ const later = properties[i];
18
+ if (later.type === 'SpreadElement') {
19
+ const provided = context?.spread(later);
20
+ if (!provided)
21
+ return true;
22
+ if (String(key) in provided.values)
23
+ return true;
24
+ continue;
25
+ }
26
+ if (later.type === 'KeyValueProperty' && keyValue(later.key) === key)
27
+ return true;
28
+ }
29
+ return false;
30
+ };
31
+ const RUNTIME_ONLY = new Set([
32
+ 'CallExpression',
33
+ 'NewExpression',
34
+ 'AwaitExpression',
35
+ 'TaggedTemplateExpression',
36
+ 'YieldExpression',
37
+ ]);
38
+ const readsAnyOf = (node, names) => {
39
+ if (!node || typeof node !== 'object')
40
+ return false;
41
+ const value = node;
42
+ if (value.type === 'Identifier' && typeof value.value === 'string')
43
+ return names.has(value.value);
44
+ for (const key of Object.keys(value)) {
45
+ if (key === 'span')
46
+ continue;
47
+ const child = value[key];
48
+ if (Array.isArray(child)) {
49
+ for (const item of child)
50
+ if (readsAnyOf(item, names))
51
+ return true;
52
+ }
53
+ else if (readsAnyOf(child, names))
54
+ return true;
55
+ }
56
+ return false;
57
+ };
58
+ const parameterNames = (func) => {
59
+ const names = new Set();
60
+ const add = (pattern) => {
61
+ if (!pattern || typeof pattern !== 'object')
62
+ return;
63
+ if (pattern.type === 'Identifier' && typeof pattern.value === 'string')
64
+ names.add(pattern.value);
65
+ for (const key of ['pat', 'left', 'argument', 'value', 'key'])
66
+ if (pattern[key])
67
+ add(pattern[key]);
68
+ for (const key of ['properties', 'elements'])
69
+ if (Array.isArray(pattern[key]))
70
+ pattern[key].forEach(add);
71
+ };
72
+ (func.params ?? []).forEach((param) => add(param?.pat ?? param));
73
+ return names;
74
+ };
75
+ const assertStyleFunction = (func, context) => {
76
+ const params = parameterNames(func);
77
+ const body = func.body;
78
+ const returned = body?.type === 'ObjectExpression'
79
+ ? body
80
+ : body?.type === 'ParenthesisExpression' &&
81
+ body.expression?.type === 'ObjectExpression'
82
+ ? body.expression
83
+ : null;
84
+ if (!returned)
85
+ return;
86
+ const walk = (object) => {
87
+ const properties = object.properties ?? [];
88
+ for (let index = 0; index < properties.length; index++) {
89
+ const prop = properties[index];
90
+ if (prop.type !== 'KeyValueProperty')
91
+ continue;
92
+ const key = keyValue(prop.key);
93
+ if ((typeof key === 'string' || typeof key === 'number') &&
94
+ overwrittenLater(properties, index, key, context))
95
+ continue;
96
+ const value = prop.value;
97
+ if (!value)
98
+ continue;
99
+ if (value.type === 'ObjectExpression') {
100
+ walk(value);
101
+ continue;
102
+ }
103
+ if (RUNTIME_ONLY.has(value.type) && !readsAnyOf(value, params))
104
+ throw unresolvableValue(key ?? '', value, context);
105
+ if ((value.type === 'Identifier' || value.type === 'MemberExpression') &&
106
+ context &&
107
+ !readsAnyOf(value, params) &&
108
+ !context.resolvesValue(value))
109
+ throw unresolvableValue(key ?? '', value, context);
110
+ }
111
+ };
112
+ walk(returned);
113
+ };
114
+ const keysSuppliedAfter = (properties, index, context) => {
115
+ const keys = new Set();
116
+ for (let i = index + 1; i < properties.length; i++) {
117
+ const later = properties[i];
118
+ if (later.type === 'SpreadElement') {
119
+ const provided = context?.spread(later);
120
+ if (!provided)
121
+ return null;
122
+ for (const name of Object.keys(provided.values))
123
+ keys.add(name);
124
+ continue;
125
+ }
126
+ if (later.type !== 'KeyValueProperty')
127
+ continue;
128
+ const key = keyValue(later.key);
129
+ if (typeof key !== 'string' && typeof key !== 'number')
130
+ return null;
131
+ keys.add(String(key));
132
+ }
133
+ return keys;
134
+ };
135
+ const assertNoDroppedValues = (node, resolved, context, ignore) => {
136
+ if (!resolved)
137
+ return;
138
+ for (let index = 0; index < node.properties.length; index++) {
139
+ const prop = node.properties[index];
140
+ if (prop.type === 'SpreadElement') {
141
+ const provided = context?.spread(prop);
142
+ if (!provided?.source)
143
+ continue;
144
+ const replaced = keysSuppliedAfter(node.properties, index, context);
145
+ if (replaced)
146
+ (0, exports.assertNoDroppedValues)(provided.source, provided.values, context, replaced);
147
+ continue;
148
+ }
149
+ if (prop.type !== 'KeyValueProperty')
150
+ continue;
151
+ const key = keyValue(prop.key);
152
+ if (typeof key !== 'string' && typeof key !== 'number')
153
+ continue;
154
+ if (ignore?.has(String(key)))
155
+ continue;
156
+ if (overwrittenLater(node.properties, index, key, context))
157
+ continue;
158
+ const value = prop.value;
159
+ if (!value)
160
+ continue;
161
+ if (value.type === 'ArrowFunctionExpression' ||
162
+ value.type === 'FunctionExpression') {
163
+ assertStyleFunction(value, context);
164
+ continue;
165
+ }
166
+ if (value.type === 'NullLiteral')
167
+ continue;
168
+ if (!(key in resolved))
169
+ throw unresolvableValue(key, value, context);
170
+ if (value.type === 'ObjectExpression') {
171
+ const nested = resolved[key];
172
+ if (nested && typeof nested === 'object')
173
+ (0, exports.assertNoDroppedValues)(value, nested, context);
174
+ }
175
+ }
176
+ };
177
+ exports.assertNoDroppedValues = assertNoDroppedValues;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/utils",
3
- "version": "19.2.14",
3
+ "version": "19.2.16",
4
4
  "description": "Plumeria Utils",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",