@fuzdev/fuz_util 0.49.0 → 0.49.1

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.
@@ -41,14 +41,16 @@ export declare const find_attribute: (node: AST.Component, name: string) => AST.
41
41
  /**
42
42
  * Recursively evaluates an expression AST node to a static string value.
43
43
  *
44
- * Handles string `Literal`, `TemplateLiteral` without interpolation, and
45
- * `BinaryExpression` with the `+` operator (string concatenation).
44
+ * Handles string `Literal`, `TemplateLiteral` (including interpolations when all
45
+ * expressions resolve), `BinaryExpression` with `+`, and `Identifier` lookup
46
+ * via an optional bindings map built by `build_static_bindings`.
46
47
  * Returns `null` for dynamic expressions, non-string literals, or unsupported node types.
47
48
  *
48
49
  * @param expr An ESTree expression AST node.
50
+ * @param bindings Optional map of variable names to their resolved static string values.
49
51
  * @returns The resolved static string, or `null` if the expression is dynamic.
50
52
  */
51
- export declare const evaluate_static_expr: (expr: Expression) => string | null;
53
+ export declare const evaluate_static_expr: (expr: Expression, bindings?: ReadonlyMap<string, string>) => string | null;
52
54
  /**
53
55
  * Extracts a static string value from a Svelte attribute value AST node.
54
56
  *
@@ -61,9 +63,25 @@ export declare const evaluate_static_expr: (expr: Expression) => string | null;
61
63
  * Returns `null` for null literals, mixed arrays, dynamic expressions, and non-string values.
62
64
  *
63
65
  * @param value The attribute value from `AST.Attribute['value']`.
66
+ * @param bindings Optional map of variable names to their resolved static string values.
64
67
  * @returns The resolved static string, or `null` if the value is dynamic.
65
68
  */
66
- export declare const extract_static_string: (value: AST.Attribute["value"]) => string | null;
69
+ export declare const extract_static_string: (value: AST.Attribute["value"], bindings?: ReadonlyMap<string, string>) => string | null;
70
+ /**
71
+ * Builds a map of statically resolvable `const` bindings from a Svelte AST.
72
+ *
73
+ * Scans top-level `const` variable declarations in both instance and module scripts.
74
+ * For each declarator with a plain `Identifier` pattern and a statically evaluable
75
+ * initializer, adds the binding to the map. Processes declarations in source order
76
+ * so that chained references resolve: `const a = 'x'; const b = a;` maps `b` to `'x'`.
77
+ *
78
+ * Skips destructuring patterns, `let`/`var` declarations, and declarations
79
+ * whose initializers reference dynamic values.
80
+ *
81
+ * @param ast The parsed Svelte AST root node.
82
+ * @returns Map of variable names to their resolved static string values.
83
+ */
84
+ export declare const build_static_bindings: (ast: AST.Root) => Map<string, string>;
67
85
  /**
68
86
  * Resolves local names that import from specified source paths.
69
87
  *
@@ -1 +1 @@
1
- {"version":3,"file":"svelte_preprocess_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,eAAe,EAAC,MAAM,QAAQ,CAAC;AACnG,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAC;AAEzC,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACpC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;CAC1B;AAED,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACvC,gEAAgE;IAChE,WAAW,EAAE,iBAAiB,CAAC;IAC/B,mDAAmD;IACnD,SAAS,EAAE,eAAe,GAAG,sBAAsB,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,GAAG,CAAC,SAAS,EAAE,MAAM,MAAM,KAAG,GAAG,CAAC,SAAS,GAAG,SAOlF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,UAAU,KAAG,MAAM,GAAG,IAchE,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,KAAG,MAAM,GAAG,IAkB9E,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,GACnC,KAAK,GAAG,CAAC,IAAI,EACb,mBAAmB,KAAK,CAAC,MAAM,CAAC,KAC9B,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAcrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,MAYhE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC1C,SAAQ,MAAa,KACnB,MAyBF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,MAAM,MAAM,EACZ,OAAO,GAAG,CAAC,OAAO,CAAC,KACjB,OAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAc/C,CAAC"}
1
+ {"version":3,"file":"svelte_preprocess_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,eAAe,EAAC,MAAM,QAAQ,CAAC;AACnG,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAC;AAEzC,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACpC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;CAC1B;AAED,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACvC,gEAAgE;IAChE,WAAW,EAAE,iBAAiB,CAAC;IAC/B,mDAAmD;IACnD,SAAS,EAAE,eAAe,GAAG,sBAAsB,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,GAAG,CAAC,SAAS,EAAE,MAAM,MAAM,KAAG,GAAG,CAAC,SAAS,GAAG,SAOlF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,UAAU,EAChB,WAAW,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KACpC,MAAM,GAAG,IA+BX,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,GACjC,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAC7B,WAAW,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KACpC,MAAM,GAAG,IAkBX,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,GAAG,CAAC,IAAI,KAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAiBvE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,GACnC,KAAK,GAAG,CAAC,IAAI,EACb,mBAAmB,KAAK,CAAC,MAAM,CAAC,KAC9B,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAcrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,MAYhE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,SAAS,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAC1C,SAAQ,MAAa,KACnB,MAyBF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,MAAM,MAAM,EACZ,OAAO,GAAG,CAAC,OAAO,CAAC,KACjB,OAYF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAc/C,CAAC"}
@@ -32,30 +32,50 @@ export const find_attribute = (node, name) => {
32
32
  /**
33
33
  * Recursively evaluates an expression AST node to a static string value.
34
34
  *
35
- * Handles string `Literal`, `TemplateLiteral` without interpolation, and
36
- * `BinaryExpression` with the `+` operator (string concatenation).
35
+ * Handles string `Literal`, `TemplateLiteral` (including interpolations when all
36
+ * expressions resolve), `BinaryExpression` with `+`, and `Identifier` lookup
37
+ * via an optional bindings map built by `build_static_bindings`.
37
38
  * Returns `null` for dynamic expressions, non-string literals, or unsupported node types.
38
39
  *
39
40
  * @param expr An ESTree expression AST node.
41
+ * @param bindings Optional map of variable names to their resolved static string values.
40
42
  * @returns The resolved static string, or `null` if the expression is dynamic.
41
43
  */
42
- export const evaluate_static_expr = (expr) => {
44
+ export const evaluate_static_expr = (expr, bindings) => {
43
45
  if (expr.type === 'Literal' && typeof expr.value === 'string')
44
46
  return expr.value;
45
- if (expr.type === 'TemplateLiteral' && expr.expressions.length === 0) {
46
- return expr.quasis.map((q) => q.value.cooked ?? q.value.raw).join('');
47
+ if (expr.type === 'TemplateLiteral') {
48
+ if (expr.expressions.length === 0) {
49
+ return expr.quasis.map((q) => q.value.cooked ?? q.value.raw).join('');
50
+ }
51
+ // Try resolving interpolations through bindings
52
+ const parts = [];
53
+ for (let i = 0; i < expr.quasis.length; i++) {
54
+ const quasi = expr.quasis[i];
55
+ parts.push(quasi.value.cooked ?? quasi.value.raw);
56
+ if (i < expr.expressions.length) {
57
+ const val = evaluate_static_expr(expr.expressions[i], bindings);
58
+ if (val === null)
59
+ return null;
60
+ parts.push(val);
61
+ }
62
+ }
63
+ return parts.join('');
47
64
  }
48
65
  if (expr.type === 'BinaryExpression' && expr.operator === '+') {
49
66
  if (expr.left.type === 'PrivateIdentifier')
50
67
  return null;
51
- const left = evaluate_static_expr(expr.left);
68
+ const left = evaluate_static_expr(expr.left, bindings);
52
69
  if (left === null)
53
70
  return null;
54
- const right = evaluate_static_expr(expr.right);
71
+ const right = evaluate_static_expr(expr.right, bindings);
55
72
  if (right === null)
56
73
  return null;
57
74
  return left + right;
58
75
  }
76
+ if (expr.type === 'Identifier' && bindings?.has(expr.name)) {
77
+ return bindings.get(expr.name);
78
+ }
59
79
  return null;
60
80
  };
61
81
  /**
@@ -70,9 +90,10 @@ export const evaluate_static_expr = (expr) => {
70
90
  * Returns `null` for null literals, mixed arrays, dynamic expressions, and non-string values.
71
91
  *
72
92
  * @param value The attribute value from `AST.Attribute['value']`.
93
+ * @param bindings Optional map of variable names to their resolved static string values.
73
94
  * @returns The resolved static string, or `null` if the value is dynamic.
74
95
  */
75
- export const extract_static_string = (value) => {
96
+ export const extract_static_string = (value, bindings) => {
76
97
  // Boolean attribute (e.g., <Mdz inline />)
77
98
  if (value === true)
78
99
  return null;
@@ -89,7 +110,43 @@ export const extract_static_string = (value) => {
89
110
  // Null literal
90
111
  if (expr.type === 'Literal' && expr.value === null)
91
112
  return null;
92
- return evaluate_static_expr(expr);
113
+ return evaluate_static_expr(expr, bindings);
114
+ };
115
+ /**
116
+ * Builds a map of statically resolvable `const` bindings from a Svelte AST.
117
+ *
118
+ * Scans top-level `const` variable declarations in both instance and module scripts.
119
+ * For each declarator with a plain `Identifier` pattern and a statically evaluable
120
+ * initializer, adds the binding to the map. Processes declarations in source order
121
+ * so that chained references resolve: `const a = 'x'; const b = a;` maps `b` to `'x'`.
122
+ *
123
+ * Skips destructuring patterns, `let`/`var` declarations, and declarations
124
+ * whose initializers reference dynamic values.
125
+ *
126
+ * @param ast The parsed Svelte AST root node.
127
+ * @returns Map of variable names to their resolved static string values.
128
+ */
129
+ export const build_static_bindings = (ast) => {
130
+ const bindings = new Map();
131
+ for (const script of [ast.instance, ast.module]) {
132
+ if (!script)
133
+ continue;
134
+ for (const node of script.content.body) {
135
+ if (node.type !== 'VariableDeclaration' || node.kind !== 'const')
136
+ continue;
137
+ for (const declarator of node.declarations) {
138
+ if (declarator.id.type !== 'Identifier')
139
+ continue;
140
+ if (!declarator.init)
141
+ continue;
142
+ const value = evaluate_static_expr(declarator.init, bindings);
143
+ if (value !== null) {
144
+ bindings.set(declarator.id.name, value);
145
+ }
146
+ }
147
+ }
148
+ }
149
+ return bindings;
93
150
  };
94
151
  /**
95
152
  * Resolves local names that import from specified source paths.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_util",
3
- "version": "0.49.0",
3
+ "version": "0.49.1",
4
4
  "description": "utility belt for JS",
5
5
  "glyph": "🦕",
6
6
  "logo": "logo.svg",
@@ -53,26 +53,48 @@ export const find_attribute = (node: AST.Component, name: string): AST.Attribute
53
53
  /**
54
54
  * Recursively evaluates an expression AST node to a static string value.
55
55
  *
56
- * Handles string `Literal`, `TemplateLiteral` without interpolation, and
57
- * `BinaryExpression` with the `+` operator (string concatenation).
56
+ * Handles string `Literal`, `TemplateLiteral` (including interpolations when all
57
+ * expressions resolve), `BinaryExpression` with `+`, and `Identifier` lookup
58
+ * via an optional bindings map built by `build_static_bindings`.
58
59
  * Returns `null` for dynamic expressions, non-string literals, or unsupported node types.
59
60
  *
60
61
  * @param expr An ESTree expression AST node.
62
+ * @param bindings Optional map of variable names to their resolved static string values.
61
63
  * @returns The resolved static string, or `null` if the expression is dynamic.
62
64
  */
63
- export const evaluate_static_expr = (expr: Expression): string | null => {
65
+ export const evaluate_static_expr = (
66
+ expr: Expression,
67
+ bindings?: ReadonlyMap<string, string>,
68
+ ): string | null => {
64
69
  if (expr.type === 'Literal' && typeof expr.value === 'string') return expr.value;
65
- if (expr.type === 'TemplateLiteral' && expr.expressions.length === 0) {
66
- return expr.quasis.map((q) => q.value.cooked ?? q.value.raw).join('');
70
+ if (expr.type === 'TemplateLiteral') {
71
+ if (expr.expressions.length === 0) {
72
+ return expr.quasis.map((q) => q.value.cooked ?? q.value.raw).join('');
73
+ }
74
+ // Try resolving interpolations through bindings
75
+ const parts: Array<string> = [];
76
+ for (let i = 0; i < expr.quasis.length; i++) {
77
+ const quasi = expr.quasis[i]!;
78
+ parts.push(quasi.value.cooked ?? quasi.value.raw);
79
+ if (i < expr.expressions.length) {
80
+ const val = evaluate_static_expr(expr.expressions[i]!, bindings);
81
+ if (val === null) return null;
82
+ parts.push(val);
83
+ }
84
+ }
85
+ return parts.join('');
67
86
  }
68
87
  if (expr.type === 'BinaryExpression' && expr.operator === '+') {
69
88
  if (expr.left.type === 'PrivateIdentifier') return null;
70
- const left = evaluate_static_expr(expr.left);
89
+ const left = evaluate_static_expr(expr.left, bindings);
71
90
  if (left === null) return null;
72
- const right = evaluate_static_expr(expr.right);
91
+ const right = evaluate_static_expr(expr.right, bindings);
73
92
  if (right === null) return null;
74
93
  return left + right;
75
94
  }
95
+ if (expr.type === 'Identifier' && bindings?.has(expr.name)) {
96
+ return bindings.get(expr.name)!;
97
+ }
76
98
  return null;
77
99
  };
78
100
 
@@ -88,9 +110,13 @@ export const evaluate_static_expr = (expr: Expression): string | null => {
88
110
  * Returns `null` for null literals, mixed arrays, dynamic expressions, and non-string values.
89
111
  *
90
112
  * @param value The attribute value from `AST.Attribute['value']`.
113
+ * @param bindings Optional map of variable names to their resolved static string values.
91
114
  * @returns The resolved static string, or `null` if the value is dynamic.
92
115
  */
93
- export const extract_static_string = (value: AST.Attribute['value']): string | null => {
116
+ export const extract_static_string = (
117
+ value: AST.Attribute['value'],
118
+ bindings?: ReadonlyMap<string, string>,
119
+ ): string | null => {
94
120
  // Boolean attribute (e.g., <Mdz inline />)
95
121
  if (value === true) return null;
96
122
 
@@ -107,7 +133,40 @@ export const extract_static_string = (value: AST.Attribute['value']): string | n
107
133
  const expr = value.expression;
108
134
  // Null literal
109
135
  if (expr.type === 'Literal' && expr.value === null) return null;
110
- return evaluate_static_expr(expr);
136
+ return evaluate_static_expr(expr, bindings);
137
+ };
138
+
139
+ /**
140
+ * Builds a map of statically resolvable `const` bindings from a Svelte AST.
141
+ *
142
+ * Scans top-level `const` variable declarations in both instance and module scripts.
143
+ * For each declarator with a plain `Identifier` pattern and a statically evaluable
144
+ * initializer, adds the binding to the map. Processes declarations in source order
145
+ * so that chained references resolve: `const a = 'x'; const b = a;` maps `b` to `'x'`.
146
+ *
147
+ * Skips destructuring patterns, `let`/`var` declarations, and declarations
148
+ * whose initializers reference dynamic values.
149
+ *
150
+ * @param ast The parsed Svelte AST root node.
151
+ * @returns Map of variable names to their resolved static string values.
152
+ */
153
+ export const build_static_bindings = (ast: AST.Root): Map<string, string> => {
154
+ const bindings: Map<string, string> = new Map();
155
+ for (const script of [ast.instance, ast.module]) {
156
+ if (!script) continue;
157
+ for (const node of script.content.body) {
158
+ if (node.type !== 'VariableDeclaration' || node.kind !== 'const') continue;
159
+ for (const declarator of node.declarations) {
160
+ if (declarator.id.type !== 'Identifier') continue;
161
+ if (!declarator.init) continue;
162
+ const value = evaluate_static_expr(declarator.init, bindings);
163
+ if (value !== null) {
164
+ bindings.set(declarator.id.name, value);
165
+ }
166
+ }
167
+ }
168
+ }
169
+ return bindings;
111
170
  };
112
171
 
113
172
  /**