@plumeria/utils 19.6.1 → 19.7.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/compile.js CHANGED
@@ -41,6 +41,7 @@ const path = __importStar(require("path"));
41
41
  const rs = __importStar(require("@rust-gear/glob"));
42
42
  const index_1 = require("./index");
43
43
  const index_2 = require("./index");
44
+ const dynamicKey_1 = require("./dynamicKey");
44
45
  const unwrapExport = (node) => {
45
46
  if (node?.type === 'ExportDeclaration')
46
47
  return node.declaration;
@@ -626,6 +627,7 @@ function compileCSS(options) {
626
627
  const tempStaticTable = { ...ctx.mergedStaticTable };
627
628
  const providedParams = new Set();
628
629
  const runtime = [];
630
+ const definite = new Set();
629
631
  const resolveObjectArg = (argExpr) => (0, index_1.objectExpressionToObject)({
630
632
  ...argExpr,
631
633
  properties: argExpr.properties.filter((prop) => prop.type === 'Identifier' ||
@@ -662,8 +664,11 @@ function compileCSS(options) {
662
664
  tempStaticTable[local] = argObj[key];
663
665
  providedParams.add(local);
664
666
  }
665
- else
667
+ else {
666
668
  runtime.push(local);
669
+ if ((0, dynamicKey_1.isDefinedArgument)(source))
670
+ definite.add(local);
671
+ }
667
672
  });
668
673
  }
669
674
  else if (callArgs.length === 1 &&
@@ -677,14 +682,16 @@ function compileCSS(options) {
677
682
  });
678
683
  }
679
684
  else {
680
- callArgs.forEach((_callArg, i) => {
685
+ callArgs.forEach((callArg, i) => {
681
686
  const p = func.params[i];
682
687
  if (!p)
683
688
  return;
684
689
  runtime.push(p);
690
+ if ((0, dynamicKey_1.isDefinedArgument)(callArg.expression))
691
+ definite.add(p);
685
692
  });
686
693
  }
687
- const resolved = (0, index_1.resolveDynamicStyle)(func, runtime, tempStaticTable, dynamicTablesOf(ctx), providedParams);
694
+ const resolved = (0, index_1.resolveDynamicStyle)(func, runtime, tempStaticTable, dynamicTablesOf(ctx), providedParams, definite);
688
695
  const { style } = resolved;
689
696
  return style;
690
697
  };
@@ -35,6 +35,14 @@ export type DynamicStyleTables = {
35
35
  createStaticHashTable: CreateStaticHashTable;
36
36
  createStaticObjectTable: CreateStaticObjectTable;
37
37
  };
38
+ export type DerivedPiece = string | {
39
+ param: string;
40
+ fallback?: string;
41
+ };
42
+ export type DerivedVar = {
43
+ name: string;
44
+ pieces: DerivedPiece[];
45
+ };
38
46
  export type DynamicStyleResult = {
39
47
  style: CSSObject;
40
48
  varGroups: Map<string, Array<{
@@ -43,6 +51,8 @@ export type DynamicStyleResult = {
43
51
  unit: string;
44
52
  written: boolean;
45
53
  }>>;
54
+ derived: DerivedVar[];
46
55
  };
47
- export declare const resolveDynamicStyle: (func: StyleFunction, runtimeParams: string[], staticTable: StaticTable, tables: DynamicStyleTables, providedParams?: ReadonlySet<string>) => DynamicStyleResult;
56
+ export declare const isDefinedArgument: (expression: Expression) => boolean;
57
+ export declare const resolveDynamicStyle: (func: StyleFunction, runtimeParams: string[], staticTable: StaticTable, tables: DynamicStyleTables, providedParams?: ReadonlySet<string>, definiteParams?: ReadonlySet<string>) => DynamicStyleResult;
48
58
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveDynamicStyle = exports.applyVarFallback = exports.splitVarByUnit = exports.isUnitlessProp = exports.styleFunctionsOf = void 0;
3
+ exports.resolveDynamicStyle = exports.isDefinedArgument = exports.applyVarFallback = exports.splitVarByUnit = exports.isUnitlessProp = exports.styleFunctionsOf = void 0;
4
4
  const zss_engine_1 = require("zss-engine");
5
5
  const zss_engine_2 = require("zss-engine");
6
6
  const parser_1 = require("./parser");
@@ -229,55 +229,222 @@ const applyVarFallback = (style, cssVar, literal, unit) => {
229
229
  }
230
230
  };
231
231
  exports.applyVarFallback = applyVarFallback;
232
- const resolveDynamicStyle = (func, runtimeParams, staticTable, tables, providedParams) => {
232
+ const ARITHMETIC = new Set(['+', '-', '*', '/', '%', '**']);
233
+ const isSign = (node) => parser_1.t.isUnaryExpression(node) && (node.operator === '-' || node.operator === '+');
234
+ const isDefinedArgument = (expression) => {
235
+ const node = (0, parser_1.unwrapExpression)(expression);
236
+ if (parser_1.t.isStringLiteral(node) ||
237
+ parser_1.t.isNumericLiteral(node) ||
238
+ parser_1.t.isBooleanLiteral(node) ||
239
+ parser_1.t.isNullLiteral(node) ||
240
+ parser_1.t.isTemplateLiteral(node))
241
+ return true;
242
+ return isSign(node) && parser_1.t.isNumericLiteral((0, parser_1.unwrapExpression)(node.argument));
243
+ };
244
+ exports.isDefinedArgument = isDefinedArgument;
245
+ const defaultError = (param, node, literal) => {
246
+ const kind = literal === null || parser_1.t.isNullLiteral(node)
247
+ ? 'null'
248
+ : typeof literal === 'boolean'
249
+ ? 'a boolean'
250
+ : literal !== undefined
251
+ ? 'an object'
252
+ : undefined;
253
+ return new Error(kind
254
+ ? `[plumeria] The default of "${param}" is ${kind}, which a dynamic style function cannot fall back on. Use a string or a number, or pass the value from the call.`
255
+ : `[plumeria] Cannot resolve the default of "${param}" at build time (${(0, parser_1.expressionLabel)(node)}). A dynamic style function falls back on it when the argument is undefined, so it has to be a string or a number plumeria can read. Pass the value from the call instead.`);
256
+ };
257
+ const replaceNodes = (node, replacements) => {
258
+ if (!node || typeof node !== 'object')
259
+ return node;
260
+ const replacement = replacements.get(node);
261
+ if (replacement)
262
+ return replacement;
263
+ if (Array.isArray(node))
264
+ return node.map((item) => replaceNodes(item, replacements));
265
+ const copy = {};
266
+ for (const key of Object.keys(node))
267
+ copy[key] =
268
+ key === 'span' ? node[key] : replaceNodes(node[key], replacements);
269
+ return copy;
270
+ };
271
+ const literalSource = (value) => {
272
+ if (typeof value === 'string')
273
+ return JSON.stringify(value);
274
+ const text = String(value);
275
+ return text.startsWith('-') ? `(${text})` : text;
276
+ };
277
+ const deriveArithmetic = (body, runtimeParams, varParams, defaults, evaluate) => {
278
+ const derived = [];
279
+ const names = new Map();
280
+ const replacements = new Map();
281
+ const render = (expression) => {
282
+ const node = (0, parser_1.unwrapExpression)(expression);
283
+ if (parser_1.t.isIdentifier(node) && runtimeParams.has(node.value)) {
284
+ const fallback = defaults.get(node.value);
285
+ return [
286
+ fallback === undefined
287
+ ? { param: node.value }
288
+ : { param: node.value, fallback: literalSource(fallback) },
289
+ ];
290
+ }
291
+ if (parser_1.t.isBinaryExpression(node) && ARITHMETIC.has(node.operator)) {
292
+ const left = render(node.left);
293
+ const right = render(node.right);
294
+ if (!left || !right)
295
+ return null;
296
+ return ['(', ...left, ` ${node.operator} `, ...right, ')'];
297
+ }
298
+ if (isSign(node)) {
299
+ const argument = render(node.argument);
300
+ return argument && ['(', node.operator, '(', ...argument, ')', ')'];
301
+ }
302
+ if ((0, parser_1.readsParams)(node, runtimeParams))
303
+ return null;
304
+ const value = evaluate(node);
305
+ return typeof value === 'number' ? [literalSource(value)] : null;
306
+ };
307
+ const register = (node, pieces) => {
308
+ const first = pieces.find((piece) => typeof piece !== 'string');
309
+ if (!first) {
310
+ replacements.set(node, {
311
+ type: 'NumericLiteral',
312
+ span: node.span,
313
+ value: evaluate(node),
314
+ });
315
+ return;
316
+ }
317
+ const key = JSON.stringify(pieces);
318
+ let name = names.get(key);
319
+ if (!name) {
320
+ name = `${first.param}-${derived.length + 1}`;
321
+ names.set(key, name);
322
+ derived.push({ name, pieces });
323
+ }
324
+ replacements.set(node, {
325
+ type: 'Identifier',
326
+ span: node.span,
327
+ value: name,
328
+ optional: false,
329
+ });
330
+ };
331
+ const visit = (expression) => {
332
+ const node = (0, parser_1.unwrapExpression)(expression);
333
+ if (parser_1.t.isObjectExpression(node)) {
334
+ node.properties.forEach((prop) => {
335
+ if (prop.type === 'KeyValueProperty')
336
+ visit(prop.value);
337
+ });
338
+ return;
339
+ }
340
+ if (parser_1.t.isTemplateLiteral(node)) {
341
+ node.expressions.forEach(visit);
342
+ return;
343
+ }
344
+ const arithmetic = parser_1.t.isBinaryExpression(node) && ARITHMETIC.has(node.operator);
345
+ if (!arithmetic && !isSign(node))
346
+ return;
347
+ if (!(0, parser_1.readsParams)(node, varParams))
348
+ return;
349
+ const pieces = render(node);
350
+ if (pieces) {
351
+ register(node, pieces.slice(1, -1));
352
+ return;
353
+ }
354
+ if (arithmetic && node.operator === '+') {
355
+ visit(node.left);
356
+ visit(node.right);
357
+ }
358
+ };
359
+ visit(body);
360
+ return {
361
+ body: replacements.size > 0 ? replaceNodes(body, replacements) : body,
362
+ derived,
363
+ };
364
+ };
365
+ const resolveDynamicStyle = (func, runtimeParams, staticTable, tables, providedParams, definiteParams) => {
233
366
  if (func.unsupportedParams)
234
367
  throw new Error('[plumeria] Dynamic styles require named parameters or object destructuring; array and rest parameters are not supported.');
235
368
  const tempStaticTable = Object.create(staticTable);
236
- const resolveBody = () => (0, parser_1.objectExpressionToObject)(func.body, tempStaticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.createThemeHashTable, tables.createThemeObjectTable, tables.createHashTable, tables.createStaticHashTable, tables.createStaticObjectTable);
369
+ const evaluate = (expr, table) => (0, parser_1.objectExpressionToObject)({
370
+ type: 'ObjectExpression',
371
+ span: func.body.span,
372
+ properties: [
373
+ {
374
+ type: 'KeyValueProperty',
375
+ key: {
376
+ type: 'Identifier',
377
+ span: func.body.span,
378
+ value: 'value',
379
+ optional: false,
380
+ },
381
+ value: expr,
382
+ },
383
+ ],
384
+ }, table, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.createThemeHashTable, tables.createThemeObjectTable, tables.createHashTable, tables.createStaticHashTable, tables.createStaticObjectTable).value;
237
385
  const withDefault = Object.entries(func.defaults ?? {}).filter(([param]) => providedParams
238
386
  ? !providedParams.has(param)
239
387
  : tempStaticTable[param] === undefined);
388
+ const defaultLiterals = new Map();
389
+ withDefault.forEach(([param, expr]) => {
390
+ const node = (0, parser_1.unwrapExpression)(expr);
391
+ if (parser_1.t.isIdentifier(node) && node.value === 'undefined')
392
+ return;
393
+ const definite = definiteParams?.has(param) || !(0, parser_1.readsParams)(func.body, new Set([param]));
394
+ let literal;
395
+ try {
396
+ literal = evaluate(expr, staticTable);
397
+ }
398
+ catch (error) {
399
+ if (definite)
400
+ return;
401
+ throw error;
402
+ }
403
+ if (typeof literal === 'string' || typeof literal === 'number') {
404
+ defaultLiterals.set(param, literal);
405
+ return;
406
+ }
407
+ if (!definite)
408
+ throw defaultError(param, node, literal);
409
+ });
410
+ const holeDefaults = new Map([...defaultLiterals].filter(([param]) => !definiteParams?.has(param)));
240
411
  const cssVars = {};
241
412
  const varParams = Array.from(new Set([...runtimeParams, ...withDefault.map(([param]) => param)]));
242
- if (varParams.length > 0) {
243
- varParams.forEach((param) => (tempStaticTable[param] = param));
413
+ const runtimeSet = new Set(runtimeParams);
414
+ const constantTable = Object.create(staticTable);
415
+ defaultLiterals.forEach((literal, param) => {
416
+ if (!runtimeSet.has(param))
417
+ constantTable[param] = literal;
418
+ });
419
+ const { body, derived } = deriveArithmetic(func.body, runtimeSet, new Set(varParams), holeDefaults, (node) => {
420
+ try {
421
+ return evaluate(node, constantTable);
422
+ }
423
+ catch {
424
+ return undefined;
425
+ }
426
+ });
427
+ const resolveBody = () => (0, parser_1.objectExpressionToObject)(body, tempStaticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.createThemeHashTable, tables.createThemeObjectTable, tables.createHashTable, tables.createStaticHashTable, tables.createStaticObjectTable);
428
+ const varNames = [...varParams, ...derived.map(({ name }) => name)];
429
+ if (varNames.length > 0) {
430
+ varNames.forEach((name) => (tempStaticTable[name] = name));
244
431
  const hash = (0, zss_engine_2.genBase36Hash)(resolveBody(), 1, 8);
245
- varParams.forEach((param) => {
246
- const cssVar = `--${hash}-${param}`;
247
- tempStaticTable[param] = `var(${cssVar})`;
248
- cssVars[param] = cssVar;
432
+ varNames.forEach((name) => {
433
+ const cssVar = `--${hash}-${name}`;
434
+ tempStaticTable[name] = `var(${cssVar})`;
435
+ cssVars[name] = cssVar;
249
436
  });
250
437
  }
251
438
  const style = resolveBody();
252
439
  const varGroups = new Map();
253
- varParams.forEach((param) => {
254
- const cssVar = cssVars[param];
255
- varGroups.set(param, (0, exports.splitVarByUnit)(style, cssVar));
440
+ varNames.forEach((name) => {
441
+ varGroups.set(name, (0, exports.splitVarByUnit)(style, cssVars[name]));
256
442
  });
257
- withDefault.forEach(([param, expr]) => {
258
- const resolved = (0, parser_1.objectExpressionToObject)({
259
- type: 'ObjectExpression',
260
- span: func.body.span,
261
- properties: [
262
- {
263
- type: 'KeyValueProperty',
264
- key: {
265
- type: 'Identifier',
266
- span: func.body.span,
267
- value: 'value',
268
- optional: false,
269
- },
270
- value: expr,
271
- },
272
- ],
273
- }, staticTable, tables.keyframesHashTable, tables.viewTransitionHashTable, tables.createThemeHashTable, tables.createThemeObjectTable, tables.createHashTable, tables.createStaticHashTable, tables.createStaticObjectTable);
274
- const literal = resolved.value;
275
- if (typeof literal !== 'string' && typeof literal !== 'number')
276
- return;
443
+ defaultLiterals.forEach((literal, param) => {
277
444
  varGroups
278
445
  .get(param)
279
446
  .forEach(({ cssVar, unit, written }) => (0, exports.applyVarFallback)(style, cssVar, literal, { unit, written }));
280
447
  });
281
- return { style, varGroups };
448
+ return { style, varGroups, derived };
282
449
  };
283
450
  exports.resolveDynamicStyle = resolveDynamicStyle;
package/dist/parser.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { CSSObject, Tables, StaticTable, KeyframesHashTable, ViewTransition
2
2
  import type { Module, Expression, CallExpression, Identifier, KeyValueProperty, StringLiteral, NumericLiteral, BooleanLiteral, ObjectExpression, MemberExpression, TemplateLiteral, BinaryExpression, UnaryExpression, ParenthesisExpression, VariableDeclaration, VariableDeclarator, ExportDeclaration, ConditionalExpression, JSXExpression, ArrowFunctionExpression, FunctionExpression } from '@swc/core';
3
3
  export declare function unwrapExpression(node: any): any;
4
4
  export declare const getRootIdentifier: (node: Expression) => string | null;
5
+ export declare const expressionLabel: (node: Expression) => string;
5
6
  export declare function resolveOriginError(node: Expression, rootName: string | null, localImports: Record<string, {
6
7
  actualPath: string;
7
8
  importedName: string;
@@ -45,6 +46,7 @@ export declare function traverse(node: Module | JSXExpression, visitor: {
45
46
  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
47
  export declare function collectLocalConstNodes(ast: Module): Map<string, any>;
47
48
  export declare function collectLocalConsts(ast: Module): Record<string, any>;
49
+ export declare function readsParams(node: any, params: Set<string>): boolean;
48
50
  export declare function resolveThemeSelector(node: Expression, staticTable: StaticTable, createStaticHashTable: CreateStaticHashTable, createStaticObjectTable: CreateStaticObjectTable): string;
49
51
  export declare function resolveFileError(actualPath: string, importedName: string): {
50
52
  filePath: string;
package/dist/parser.js CHANGED
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.appendSheet = exports.t = exports.getRootIdentifier = void 0;
36
+ exports.appendSheet = exports.t = exports.expressionLabel = exports.getRootIdentifier = void 0;
37
37
  exports.unwrapExpression = unwrapExpression;
38
38
  exports.resolveOriginError = resolveOriginError;
39
39
  exports.resolveComponentKey = resolveComponentKey;
@@ -41,6 +41,7 @@ exports.traverse = traverse;
41
41
  exports.objectExpressionToObject = objectExpressionToObject;
42
42
  exports.collectLocalConstNodes = collectLocalConstNodes;
43
43
  exports.collectLocalConsts = collectLocalConsts;
44
+ exports.readsParams = readsParams;
44
45
  exports.resolveThemeSelector = resolveThemeSelector;
45
46
  exports.resolveFileError = resolveFileError;
46
47
  exports.fileTableKeys = fileTableKeys;
@@ -127,12 +128,13 @@ const expressionLabel = (node) => {
127
128
  if (exports.t.isMemberExpression(node)) {
128
129
  const property = node.property;
129
130
  if (property.type === 'Identifier')
130
- return `${expressionLabel(node.object)}.${property.value}`;
131
+ return `${(0, exports.expressionLabel)(node.object)}.${property.value}`;
131
132
  if (property.type === 'Computed')
132
- return `${expressionLabel(node.object)}[${expressionLabel(property.expression)}]`;
133
+ return `${(0, exports.expressionLabel)(node.object)}[${(0, exports.expressionLabel)(property.expression)}]`;
133
134
  }
134
135
  return EXPRESSION_KINDS[node.type] ?? 'an expression';
135
136
  };
137
+ exports.expressionLabel = expressionLabel;
136
138
  const getNamespaceMember = (node, rootName) => {
137
139
  node = unwrapExpression(node);
138
140
  if (exports.t.isCallExpression(node)) {
@@ -299,6 +301,12 @@ function objectExpressionToObject(node, staticTable, keyframesHashTable, viewTra
299
301
  const key = getPropertyKey(prop.key, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
300
302
  if (!key)
301
303
  return;
304
+ if (typeof key === 'string' &&
305
+ (key.startsWith(':') || key.startsWith('['))) {
306
+ const name = (0, zss_engine_1.findSameNameNesting)(key);
307
+ if (name)
308
+ throw new Error(`[plumeria] "${name}()" cannot be nested inside another "${name}()": "${key}". Rewrite the selector without nesting.`);
309
+ }
302
310
  const val = unwrapExpression(prop.value);
303
311
  if (exports.t.isIdentifier(val) || exports.t.isMemberExpression(val)) {
304
312
  if (resolveVariable && exports.t.isMemberExpression(val)) {
@@ -309,7 +317,7 @@ function objectExpressionToObject(node, staticTable, keyframesHashTable, viewTra
309
317
  [root]: resolved,
310
318
  }));
311
319
  if (member === undefined)
312
- throw new Error(`[plumeria] Unknown style member: ${expressionLabel(val)} does not exist.`);
320
+ throw new Error(`[plumeria] Unknown style member: ${(0, exports.expressionLabel)(val)} does not exist.`);
313
321
  obj[key] = member;
314
322
  return;
315
323
  }
@@ -715,7 +723,7 @@ function evaluateTemplateLiteral(node, staticTable, keyframesHashTable, viewTran
715
723
  const expr = node.expressions[i];
716
724
  const evaluatedExpr = evaluateExpression(expr, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
717
725
  if (evaluatedExpr === null || typeof evaluatedExpr === 'object')
718
- 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.`);
726
+ throw new Error(`[plumeria] Template value cannot be resolved to a primitive: ${(0, exports.expressionLabel)(expr)} inside \${} must resolve to a string or number at build time.`);
719
727
  result += String(evaluatedExpr);
720
728
  }
721
729
  }
@@ -872,7 +880,7 @@ function evaluateExpression(node, staticTable, keyframesHashTable, viewTransitio
872
880
  if (resolvedStatic !== undefined) {
873
881
  return resolvedStatic;
874
882
  }
875
- 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.`);
883
+ throw new Error(`[plumeria] Cannot resolve static member expression: ${(0, exports.expressionLabel)(node)}. Its object must be a const or a value created by css.createStatic or css.createTheme.`);
876
884
  }
877
885
  if (exports.t.isBinaryExpression(node)) {
878
886
  return evaluateBinaryExpression(node, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
@@ -892,12 +900,12 @@ function evaluateExpression(node, staticTable, keyframesHashTable, viewTransitio
892
900
  if (node.operator === '~')
893
901
  return ~value;
894
902
  }
895
- throw new Error(`[plumeria] Unsupported unary operand for ${node.operator}: ${expressionLabel(node.argument)} must resolve to a number at build time.`);
903
+ throw new Error(`[plumeria] Unsupported unary operand for ${node.operator}: ${(0, exports.expressionLabel)(node.argument)} must resolve to a number at build time.`);
896
904
  }
897
905
  if (exports.t.isParenthesisExpression(node)) {
898
906
  return evaluateExpression(node.expression, staticTable, keyframesHashTable, viewTransitionHashTable, createThemeHashTable, createThemeObjectTable, createStaticHashTable, createStaticObjectTable);
899
907
  }
900
- throw new Error(`[plumeria] Unsupported expression type: ${expressionLabel(node)}. Style values must be literals, consts, or arithmetic and template expressions of them.`);
908
+ throw new Error(`[plumeria] Unsupported expression type: ${(0, exports.expressionLabel)(node)}. Style values must be literals, consts, or arithmetic and template expressions of them.`);
901
909
  }
902
910
  function resolveKeyframesTableMemberExpression(node, keyframesHashTable) {
903
911
  if (exports.t.isIdentifier(node)) {
@@ -1858,22 +1866,27 @@ function runScan(scanCwd, styleProp) {
1858
1866
  if (callArgs.some((a) => a.spread))
1859
1867
  return null;
1860
1868
  const runtime = [];
1869
+ const definite = new Set();
1861
1870
  if (func.named) {
1862
1871
  const argExpr = callArgs[0]?.expression;
1863
1872
  if (callArgs.length > 1 ||
1864
1873
  (argExpr && argExpr.type !== 'ObjectExpression'))
1865
1874
  return null;
1866
- const given = new Set();
1875
+ const given = new Map();
1867
1876
  (argExpr?.properties ?? []).forEach((prop) => {
1868
1877
  if (prop.type === 'Identifier')
1869
- given.add(prop.value);
1878
+ given.set(prop.value, prop);
1870
1879
  else if (prop.type === 'KeyValueProperty' &&
1871
1880
  (exports.t.isIdentifier(prop.key) || exports.t.isStringLiteral(prop.key)))
1872
- given.add(String(prop.key.value));
1881
+ given.set(String(prop.key.value), prop.value);
1873
1882
  });
1874
1883
  for (const { key, local } of func.named) {
1875
- if (given.has(key))
1884
+ const source = given.get(key);
1885
+ if (source) {
1876
1886
  runtime.push(local);
1887
+ if ((0, dynamicKey_1.isDefinedArgument)(source))
1888
+ definite.add(local);
1889
+ }
1877
1890
  else if (!func.defaults?.[local])
1878
1891
  return null;
1879
1892
  }
@@ -1883,14 +1896,20 @@ function runScan(scanCwd, styleProp) {
1883
1896
  return null;
1884
1897
  }
1885
1898
  else {
1886
- callArgs.forEach((_, i) => {
1899
+ callArgs.forEach((callArg, i) => {
1887
1900
  const param = func.params[i];
1888
- if (param)
1889
- runtime.push(param);
1901
+ if (!param)
1902
+ return;
1903
+ runtime.push(param);
1904
+ if ((0, dynamicKey_1.isDefinedArgument)(callArg.expression))
1905
+ definite.add(param);
1890
1906
  });
1891
1907
  }
1892
- const resolved = (0, dynamicKey_1.resolveDynamicStyle)(func, runtime, dynamicStaticTable, dynamicStyleTables, new Set());
1893
- const hasVars = runtime.some((param) => (resolved.varGroups.get(param) ?? []).length > 0);
1908
+ const resolved = (0, dynamicKey_1.resolveDynamicStyle)(func, runtime, dynamicStaticTable, dynamicStyleTables, new Set(), definite);
1909
+ const hasVars = [
1910
+ ...runtime,
1911
+ ...resolved.derived.map(({ name }) => name),
1912
+ ].some((param) => (resolved.varGroups.get(param) ?? []).length > 0);
1894
1913
  return { style: resolved.style, hasVars };
1895
1914
  };
1896
1915
  const resolveCallStylePropInScan = (expr) => {
@@ -5,7 +5,7 @@ const CORE = '@plumeria/core';
5
5
  const isIdentifierStart = (c) => (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c === 36;
6
6
  const isNameChar = (c) => isIdentifierStart(c) || (c >= 48 && c <= 57) || c === 46 || c === 45;
7
7
  const isSpace = (c) => c === 32 || (c >= 9 && c <= 13);
8
- const EXPRESSION_BEFORE = new Set(Array.from('(,=:[!&|?{};+-*%<>~^', (c) => c.charCodeAt(0)));
8
+ const EXPRESSION_BEFORE = new Set(Array.from('(,=:[!&|?{};+-*%<>~^/', (c) => c.charCodeAt(0)));
9
9
  const EXPRESSION_WORDS = new Set([
10
10
  'return',
11
11
  'yield',
@@ -202,7 +202,7 @@ const writesAttribute = (source, name) => {
202
202
  if (end === -1)
203
203
  return true;
204
204
  i = end;
205
- previous = 96;
205
+ previous = source.charCodeAt(i) === 123 ? 123 : 96;
206
206
  continue;
207
207
  }
208
208
  if (c === 123) {
@@ -217,7 +217,7 @@ const writesAttribute = (source, name) => {
217
217
  if (end === -1)
218
218
  return true;
219
219
  i = end;
220
- previous = 96;
220
+ previous = source.charCodeAt(i) === 123 ? 123 : 96;
221
221
  continue;
222
222
  }
223
223
  if (kind === 'attribute') {
@@ -237,6 +237,7 @@ const writesAttribute = (source, name) => {
237
237
  source.charCodeAt(previousEnd - 2) === previous;
238
238
  const expressionStart = previous === 0 ||
239
239
  (EXPRESSION_BEFORE.has(previous) && !afterUpdate) ||
240
+ (previous === 46 && source.startsWith('...', previousEnd - 3)) ||
240
241
  (isNameChar(previous) &&
241
242
  EXPRESSION_WORDS.has(wordBefore(source, previousEnd)));
242
243
  if (c === 47 && expressionStart) {
package/dist/transform.js CHANGED
@@ -1200,18 +1200,40 @@ const transformSource = async (env) => {
1200
1200
  runtime.push({ param: p, source: callArg.expression });
1201
1201
  });
1202
1202
  }
1203
- const resolved = (0, dynamicKey_1.resolveDynamicStyle)(func, runtime.map(({ param }) => param), tempStaticTable, dynamicStyleTables, providedParams);
1204
- const { style, varGroups } = resolved;
1205
- const vars = [];
1203
+ const resolved = (0, dynamicKey_1.resolveDynamicStyle)(func, runtime.map(({ param }) => param), tempStaticTable, dynamicStyleTables, providedParams, new Set(runtime
1204
+ .filter(({ source }) => (0, dynamicKey_1.isDefinedArgument)(source))
1205
+ .map(({ param }) => param)));
1206
+ const { style, varGroups, derived } = resolved;
1207
+ const argSources = new Map();
1206
1208
  runtime.forEach(({ param, source }) => {
1207
- const groups = varGroups.get(param);
1208
- if (!groups?.length)
1209
- return;
1210
1209
  const argStart = source.span.start - baseByteOffset;
1211
1210
  const argEnd = source.span.end - baseByteOffset;
1212
- const argSource = sourceBuffer
1213
- .subarray(argStart, argEnd)
1214
- .toString('utf-8');
1211
+ argSources.set(param, sourceBuffer.subarray(argStart, argEnd).toString('utf-8'));
1212
+ });
1213
+ const runtimeSources = runtime.map(({ param }) => ({
1214
+ name: param,
1215
+ argSource: argSources.get(param),
1216
+ }));
1217
+ derived.forEach(({ name, pieces }) => {
1218
+ runtimeSources.push({
1219
+ name,
1220
+ argSource: pieces
1221
+ .map((piece) => {
1222
+ if (typeof piece === 'string')
1223
+ return piece;
1224
+ const argument = `(${argSources.get(piece.param)})`;
1225
+ return piece.fallback === undefined
1226
+ ? argument
1227
+ : `(${argument} === undefined ? ${piece.fallback} : ${argument})`;
1228
+ })
1229
+ .join(''),
1230
+ });
1231
+ });
1232
+ const vars = [];
1233
+ runtimeSources.forEach(({ name, argSource }) => {
1234
+ const groups = varGroups.get(name);
1235
+ if (!groups?.length)
1236
+ return;
1215
1237
  const maybeNumber = Number(argSource);
1216
1238
  groups.forEach(({ cssVar, prop, unit, written }) => {
1217
1239
  let valueExpr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/utils",
3
- "version": "19.6.1",
3
+ "version": "19.7.0",
4
4
  "description": "Plumeria Utils",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  "@swc/core": "1.15.47",
26
26
  "lightningcss": "^1.32.0",
27
27
  "postcss": "8.5.26",
28
- "zss-engine": "2.8.0"
28
+ "zss-engine": "2.8.2"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public",