@fuzdev/fuz_code 0.44.0 → 0.44.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"svelte_preprocess_fuz_code.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_fuz_code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,iBAAiB,EAAW,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"svelte_preprocess_fuz_code.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_fuz_code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,iBAAiB,EAAW,MAAM,iBAAiB,CAAC;AAgBxE,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACxC,gCAAgC;IAChC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAEjC,0DAA0D;IAC1D,aAAa,CAAC,EAAE,YAAY,CAAC;IAE7B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,0BAA0B,GACtC,UAAS,wBAA6B,KACpC,iBA6DF,CAAC"}
|
|
@@ -3,7 +3,7 @@ import MagicString from 'magic-string';
|
|
|
3
3
|
import { walk } from 'zimmerframe';
|
|
4
4
|
import { should_exclude_path } from '@fuzdev/fuz_util/path.js';
|
|
5
5
|
import { escape_js_string } from '@fuzdev/fuz_util/string.js';
|
|
6
|
-
import { find_attribute,
|
|
6
|
+
import { find_attribute, extract_static_string, try_extract_conditional_chain, build_static_bindings, resolve_component_names, handle_preprocess_error, } from '@fuzdev/fuz_util/svelte_preprocess_helpers.js';
|
|
7
7
|
import { syntax_styler_global } from './syntax_styler_global.js';
|
|
8
8
|
export const svelte_preprocess_fuz_code = (options = {}) => {
|
|
9
9
|
const { exclude = [], syntax_styler = syntax_styler_global, cache = true, component_imports = ['@fuzdev/fuz_code/Code.svelte'], on_error = process.env.CI === 'true' ? 'throw' : 'log', } = options;
|
|
@@ -63,7 +63,7 @@ const try_highlight = (text, lang, syntax_styler, options) => {
|
|
|
63
63
|
options.cache?.set(cache_key, html);
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
|
-
|
|
66
|
+
handle_preprocess_error(error, '[fuz-code]', options.filename, options.on_error);
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -117,53 +117,43 @@ const find_code_usages = (ast, syntax_styler, code_names, options) => {
|
|
|
117
117
|
});
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
|
-
// Try conditional
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
// Try conditional chain (handles both simple and nested ternaries)
|
|
121
|
+
const chain = try_extract_conditional_chain(content_attr.value, options.source, options.bindings);
|
|
122
|
+
if (chain) {
|
|
123
|
+
// Highlight all branches
|
|
124
|
+
const highlighted = [];
|
|
125
|
+
let any_changed = false;
|
|
126
|
+
for (const branch of chain) {
|
|
127
|
+
const html = try_highlight(branch.value, lang_value, syntax_styler, options);
|
|
128
|
+
if (html === null)
|
|
129
|
+
return;
|
|
130
|
+
if (html !== branch.value)
|
|
131
|
+
any_changed = true;
|
|
132
|
+
highlighted.push({ html, original: branch.value });
|
|
133
|
+
}
|
|
134
|
+
if (!any_changed)
|
|
128
135
|
return;
|
|
136
|
+
// Build nested ternary expression for dangerous_raw_html
|
|
137
|
+
// chain: [{test_source: 'a', value: ...}, {test_source: 'b', value: ...}, {test_source: null, value: ...}]
|
|
138
|
+
// → a ? 'html_a' : b ? 'html_b' : 'html_c'
|
|
139
|
+
let expr = '';
|
|
140
|
+
for (let i = 0; i < chain.length; i++) {
|
|
141
|
+
const branch = chain[i];
|
|
142
|
+
const html = highlighted[i].html;
|
|
143
|
+
if (branch.test_source !== null) {
|
|
144
|
+
expr += `${branch.test_source} ? '${escape_js_string(html)}' : `;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
expr += `'${escape_js_string(html)}'`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
129
150
|
transformations.push({
|
|
130
151
|
start: content_attr.start,
|
|
131
152
|
end: content_attr.end,
|
|
132
|
-
replacement: `dangerous_raw_html={${
|
|
153
|
+
replacement: `dangerous_raw_html={${expr}}`,
|
|
133
154
|
});
|
|
134
155
|
}
|
|
135
156
|
},
|
|
136
157
|
});
|
|
137
158
|
return transformations;
|
|
138
159
|
};
|
|
139
|
-
/**
|
|
140
|
-
* Try to extract a conditional expression where both branches are static strings.
|
|
141
|
-
* Returns the condition source text and both branch values, or `null` if not applicable.
|
|
142
|
-
*/
|
|
143
|
-
const try_extract_conditional = (value, source, bindings) => {
|
|
144
|
-
if (value === true || Array.isArray(value))
|
|
145
|
-
return null;
|
|
146
|
-
const expr = value.expression;
|
|
147
|
-
if (expr.type !== 'ConditionalExpression')
|
|
148
|
-
return null;
|
|
149
|
-
const consequent = evaluate_static_expr(expr.consequent, bindings);
|
|
150
|
-
if (consequent === null)
|
|
151
|
-
return null;
|
|
152
|
-
const alternate = evaluate_static_expr(expr.alternate, bindings);
|
|
153
|
-
if (alternate === null)
|
|
154
|
-
return null;
|
|
155
|
-
const test = expr.test;
|
|
156
|
-
const test_source = source.slice(test.start, test.end);
|
|
157
|
-
return { test_source, consequent, alternate };
|
|
158
|
-
};
|
|
159
|
-
/**
|
|
160
|
-
* Handle errors during highlighting.
|
|
161
|
-
*/
|
|
162
|
-
const handle_error = (error, options) => {
|
|
163
|
-
const message = `[fuz-code] Highlighting failed${options.filename ? ` in ${options.filename}` : ''}: ${error instanceof Error ? error.message : String(error)}`;
|
|
164
|
-
if (options.on_error === 'throw') {
|
|
165
|
-
throw new Error(message);
|
|
166
|
-
}
|
|
167
|
-
// eslint-disable-next-line no-console
|
|
168
|
-
console.error(message);
|
|
169
|
-
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzdev/fuz_code",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.1",
|
|
4
4
|
"description": "syntax styling utilities and components for TypeScript, Svelte, and Markdown",
|
|
5
5
|
"glyph": "🎨",
|
|
6
6
|
"logo": "logo.svg",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@changesets/changelog-git": "^0.2.1",
|
|
61
61
|
"@fuzdev/fuz_css": "^0.47.0",
|
|
62
62
|
"@fuzdev/fuz_ui": "^0.181.1",
|
|
63
|
-
"@fuzdev/fuz_util": "^0.
|
|
63
|
+
"@fuzdev/fuz_util": "^0.50.0",
|
|
64
64
|
"@ryanatkn/eslint-config": "^0.9.0",
|
|
65
65
|
"@ryanatkn/gro": "^0.191.0",
|
|
66
66
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
@@ -5,10 +5,11 @@ import {should_exclude_path} from '@fuzdev/fuz_util/path.js';
|
|
|
5
5
|
import {escape_js_string} from '@fuzdev/fuz_util/string.js';
|
|
6
6
|
import {
|
|
7
7
|
find_attribute,
|
|
8
|
-
evaluate_static_expr,
|
|
9
8
|
extract_static_string,
|
|
9
|
+
try_extract_conditional_chain,
|
|
10
10
|
build_static_bindings,
|
|
11
11
|
resolve_component_names,
|
|
12
|
+
handle_preprocess_error,
|
|
12
13
|
type ResolvedComponentImport,
|
|
13
14
|
} from '@fuzdev/fuz_util/svelte_preprocess_helpers.js';
|
|
14
15
|
|
|
@@ -136,7 +137,7 @@ const try_highlight = (
|
|
|
136
137
|
html = syntax_styler.stylize(text, lang);
|
|
137
138
|
options.cache?.set(cache_key, html);
|
|
138
139
|
} catch (error) {
|
|
139
|
-
|
|
140
|
+
handle_preprocess_error(error, '[fuz-code]', options.filename, options.on_error);
|
|
140
141
|
return null;
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -165,7 +166,7 @@ const find_code_usages = (
|
|
|
165
166
|
if (!code_names.has(node.name)) return;
|
|
166
167
|
|
|
167
168
|
// Skip if spread attributes present — can't determine content statically
|
|
168
|
-
if (node.attributes.some((attr
|
|
169
|
+
if (node.attributes.some((attr) => attr.type === 'SpreadAttribute')) return;
|
|
169
170
|
|
|
170
171
|
const content_attr = find_attribute(node, 'content');
|
|
171
172
|
if (!content_attr) return;
|
|
@@ -200,21 +201,42 @@ const find_code_usages = (
|
|
|
200
201
|
return;
|
|
201
202
|
}
|
|
202
203
|
|
|
203
|
-
// Try conditional
|
|
204
|
-
const
|
|
204
|
+
// Try conditional chain (handles both simple and nested ternaries)
|
|
205
|
+
const chain = try_extract_conditional_chain(
|
|
205
206
|
content_attr.value,
|
|
206
207
|
options.source,
|
|
207
208
|
options.bindings,
|
|
208
209
|
);
|
|
209
|
-
if (
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
if (chain) {
|
|
211
|
+
// Highlight all branches
|
|
212
|
+
const highlighted: Array<{html: string; original: string}> = [];
|
|
213
|
+
let any_changed = false;
|
|
214
|
+
for (const branch of chain) {
|
|
215
|
+
const html = try_highlight(branch.value, lang_value, syntax_styler, options);
|
|
216
|
+
if (html === null) return;
|
|
217
|
+
if (html !== branch.value) any_changed = true;
|
|
218
|
+
highlighted.push({html, original: branch.value});
|
|
219
|
+
}
|
|
220
|
+
if (!any_changed) return;
|
|
221
|
+
|
|
222
|
+
// Build nested ternary expression for dangerous_raw_html
|
|
223
|
+
// chain: [{test_source: 'a', value: ...}, {test_source: 'b', value: ...}, {test_source: null, value: ...}]
|
|
224
|
+
// → a ? 'html_a' : b ? 'html_b' : 'html_c'
|
|
225
|
+
let expr = '';
|
|
226
|
+
for (let i = 0; i < chain.length; i++) {
|
|
227
|
+
const branch = chain[i]!;
|
|
228
|
+
const html = highlighted[i]!.html;
|
|
229
|
+
if (branch.test_source !== null) {
|
|
230
|
+
expr += `${branch.test_source} ? '${escape_js_string(html)}' : `;
|
|
231
|
+
} else {
|
|
232
|
+
expr += `'${escape_js_string(html)}'`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
214
236
|
transformations.push({
|
|
215
237
|
start: content_attr.start,
|
|
216
238
|
end: content_attr.end,
|
|
217
|
-
replacement: `dangerous_raw_html={${
|
|
239
|
+
replacement: `dangerous_raw_html={${expr}}`,
|
|
218
240
|
});
|
|
219
241
|
}
|
|
220
242
|
},
|
|
@@ -222,47 +244,3 @@ const find_code_usages = (
|
|
|
222
244
|
|
|
223
245
|
return transformations;
|
|
224
246
|
};
|
|
225
|
-
|
|
226
|
-
type AttributeValue = AST.Attribute['value'];
|
|
227
|
-
|
|
228
|
-
interface ConditionalStaticStrings {
|
|
229
|
-
test_source: string;
|
|
230
|
-
consequent: string;
|
|
231
|
-
alternate: string;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Try to extract a conditional expression where both branches are static strings.
|
|
236
|
-
* Returns the condition source text and both branch values, or `null` if not applicable.
|
|
237
|
-
*/
|
|
238
|
-
const try_extract_conditional = (
|
|
239
|
-
value: AttributeValue,
|
|
240
|
-
source: string,
|
|
241
|
-
bindings: ReadonlyMap<string, string>,
|
|
242
|
-
): ConditionalStaticStrings | null => {
|
|
243
|
-
if (value === true || Array.isArray(value)) return null;
|
|
244
|
-
const expr = value.expression;
|
|
245
|
-
if (expr.type !== 'ConditionalExpression') return null;
|
|
246
|
-
|
|
247
|
-
const consequent = evaluate_static_expr(expr.consequent, bindings);
|
|
248
|
-
if (consequent === null) return null;
|
|
249
|
-
const alternate = evaluate_static_expr(expr.alternate, bindings);
|
|
250
|
-
if (alternate === null) return null;
|
|
251
|
-
|
|
252
|
-
const test = expr.test as any;
|
|
253
|
-
const test_source = source.slice(test.start, test.end);
|
|
254
|
-
return {test_source, consequent, alternate};
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Handle errors during highlighting.
|
|
259
|
-
*/
|
|
260
|
-
const handle_error = (error: unknown, options: FindCodeUsagesOptions): void => {
|
|
261
|
-
const message = `[fuz-code] Highlighting failed${options.filename ? ` in ${options.filename}` : ''}: ${error instanceof Error ? error.message : String(error)}`;
|
|
262
|
-
|
|
263
|
-
if (options.on_error === 'throw') {
|
|
264
|
-
throw new Error(message);
|
|
265
|
-
}
|
|
266
|
-
// eslint-disable-next-line no-console
|
|
267
|
-
console.error(message);
|
|
268
|
-
};
|