@jbpark/live-editor 4.5.0 → 4.6.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.
- package/README.ko.md +4 -1
- package/README.md +5 -1
- package/dist/{boundary-DnjGgsK6.js → boundary-BLB80tyw.js} +2 -2
- package/dist/boundary-BLB80tyw.js.map +1 -0
- package/dist/cache-B0-XcIxJ.js.map +1 -1
- package/dist/{compile-DDfk5P25.js → compile-Dxas-D05.js} +3 -3
- package/dist/compile-Dxas-D05.js.map +1 -0
- package/dist/{constants-h1JAgOeW.js → constants-DU17Tdwo.js} +3 -3
- package/dist/constants-DU17Tdwo.js.map +1 -0
- package/dist/{context-DsEXJl4h.js → context-B8MzP7_p.js} +3 -3
- package/dist/context-B8MzP7_p.js.map +1 -0
- package/dist/{core-CRsAGpei.js → core-Bgfek364.js} +2 -2
- package/dist/core-Bgfek364.js.map +1 -0
- package/dist/{detect-typescript-CCj9ALXc.js → detect-typescript-Dr_oLniM.js} +2 -2
- package/dist/detect-typescript-Dr_oLniM.js.map +1 -0
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/index.js +1 -1
- package/dist/{dnd-DGNp20Nk.js → dnd-V8NAxd_R.js} +435 -413
- package/dist/dnd-V8NAxd_R.js.map +1 -0
- package/dist/document-CHO215iP.js +33992 -0
- package/dist/document-CHO215iP.js.map +1 -0
- package/dist/{document-Ct4jW78J.d.ts → document-DqRSCtsx.d.ts} +496 -435
- package/dist/editor/index.js +2 -2
- package/dist/{editor-DQ8Q--qR.js → editor-CMElfHer.js} +2 -2
- package/dist/editor-CMElfHer.js.map +1 -0
- package/dist/editor-caches-ClMvdcQF.js.map +1 -1
- package/dist/error/index.d.ts +1 -1
- package/dist/error/index.js +2 -2
- package/dist/{error-DwqwjJ2C.js → error-CN_GCnXB.js} +3 -3
- package/dist/{error-DwqwjJ2C.js.map → error-CN_GCnXB.js.map} +1 -1
- package/dist/{index-vtyggWy0.d.ts → index-CRwEhJ7w.d.ts} +2 -2
- package/dist/index-C_PfR4X9.d.ts +734 -0
- package/dist/{index-P9Aifaui.d.ts → index-CiWB0zFb.d.ts} +72 -70
- package/dist/{index-WQgFy510.d.ts → index-DrWtSKXu.d.ts} +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +6 -6
- package/dist/{items-DdrwGxJw.js → items-BXXtMUNI.js} +307 -390
- package/dist/items-BXXtMUNI.js.map +1 -0
- package/dist/{messages-CzUPVnzH.js → messages-CSrMI4Rm.js} +2 -1
- package/dist/messages-CSrMI4Rm.js.map +1 -0
- package/dist/{messages-Cp3g1mn1.d.ts → messages-IBPs4TkZ.d.ts} +2 -1
- package/dist/preview/index.js +2 -2
- package/dist/{preview-BKFgq_5u.js → preview-CtyG5UbH.js} +4 -4
- package/dist/{preview-BKFgq_5u.js.map → preview-CtyG5UbH.js.map} +1 -1
- package/dist/provider/index.d.ts +2 -2
- package/dist/provider/index.js +2 -2
- package/dist/{sections-BRH3KHYc.js → sections-jYuqS4KB.js} +3 -3
- package/dist/sections-jYuqS4KB.js.map +1 -0
- package/dist/states-Ci1AvoQ9.js.map +1 -1
- package/dist/{use-dynamic-tailwind-T9r9ExbR.js → use-dynamic-tailwind-BP1toJkW.js} +59 -39
- package/dist/use-dynamic-tailwind-BP1toJkW.js.map +1 -0
- package/dist/utils/ast/index.d.ts +2 -2
- package/dist/utils/ast/index.js +84 -2
- package/dist/utils/ast/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/tailwind/index.js.map +1 -1
- package/dist/validate-iLo8IONY.js.map +1 -1
- package/package.json +5 -7
- package/dist/boundary-DnjGgsK6.js.map +0 -1
- package/dist/compile-DDfk5P25.js.map +0 -1
- package/dist/constants-h1JAgOeW.js.map +0 -1
- package/dist/context-DsEXJl4h.js.map +0 -1
- package/dist/core-CRsAGpei.js.map +0 -1
- package/dist/detect-typescript-CCj9ALXc.js.map +0 -1
- package/dist/dnd-DGNp20Nk.js.map +0 -1
- package/dist/document-DGHTfrda.js +0 -38667
- package/dist/document-DGHTfrda.js.map +0 -1
- package/dist/editor-DQ8Q--qR.js.map +0 -1
- package/dist/index-CHknA6k1.d.ts +0 -221
- package/dist/items-DdrwGxJw.js.map +0 -1
- package/dist/messages-CzUPVnzH.js.map +0 -1
- package/dist/sections-BRH3KHYc.js.map +0 -1
- package/dist/use-dynamic-tailwind-T9r9ExbR.js.map +0 -1
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { c as RESERVED_BINDING_PROPERTIES, n as CONFIG, r as DATA_ATTR, s as REGEX, t as BINDING_PROP } from "./constants-
|
|
1
|
+
import { $ as jsxClosingFragment, A as isJSXElement, B as isObjectExpression, C as booleanLiteral, D as isExpression, E as isBooleanLiteral, F as isJSXOpeningElement, G as isTSAsExpression, H as isParenthesizedExpression, I as isJSXSpreadAttribute, J as isTSTypeAssertion, K as isTSNonNullExpression, L as isJSXText, M as isJSXExpressionContainer, N as isJSXFragment, O as isIdentifier, P as isJSXIdentifier, Q as jsxClosingElement, R as isNullLiteral, S as arrayExpression, T as isArrayExpression, U as isSpreadElement, V as isObjectProperty, W as isStringLiteral, X as isUnaryExpression, Y as isTemplateLiteral, Z as jsxAttribute, _ as generateCode, _t as parse, at as jsxOpeningElement, b as getJSXTagName, ct as nullLiteral, d as traverse, dt as objectProperty, et as jsxElement, ft as stringLiteral, g as attrValue, gt as unaryExpression, ht as traverseFast, it as jsxMemberExpression, j as isJSXEmptyExpression, k as isJSXAttribute, lt as numericLiteral, mt as templateLiteral, nt as jsxFragment, ot as jsxOpeningFragment, pt as templateElement, q as isTSSatisfiesExpression, rt as jsxIdentifier, st as jsxText, tt as jsxExpressionContainer, ut as objectExpression, v as unwrap, vt as parseExpression, w as identifier, x as nanoid, y as wrap, z as isNumericLiteral } from "./document-CHO215iP.js";
|
|
2
|
+
import { c as RESERVED_BINDING_PROPERTIES, n as CONFIG, r as DATA_ATTR, s as REGEX, t as BINDING_PROP } from "./constants-DU17Tdwo.js";
|
|
3
3
|
import { n as registerEditorCache } from "./editor-caches-ClMvdcQF.js";
|
|
4
4
|
import { t as createBoundedCache } from "./cache-B0-XcIxJ.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/utils/ast/types.ts
|
|
7
|
-
var import_lib = require_lib();
|
|
8
|
-
var import_lib$1 = /* @__PURE__ */ __toESM(require_lib$1(), 1);
|
|
9
7
|
const BINDING_TYPES = [
|
|
10
8
|
"array",
|
|
11
9
|
"object",
|
|
@@ -31,44 +29,44 @@ const dedent = (str) => {
|
|
|
31
29
|
};
|
|
32
30
|
const unwrapExpression = (node) => {
|
|
33
31
|
let current = node;
|
|
34
|
-
while (
|
|
32
|
+
while (isTSAsExpression(current) || isTSSatisfiesExpression(current) || isTSNonNullExpression(current) || isTSTypeAssertion(current) || isParenthesizedExpression(current)) current = current.expression;
|
|
35
33
|
return current;
|
|
36
34
|
};
|
|
37
35
|
const isLosslesslyEvaluable = (node) => {
|
|
38
36
|
const value = unwrapExpression(node);
|
|
39
|
-
if (
|
|
40
|
-
if (
|
|
41
|
-
if (
|
|
42
|
-
if (
|
|
43
|
-
if (
|
|
37
|
+
if (isStringLiteral(value) || isNumericLiteral(value) || isBooleanLiteral(value) || isNullLiteral(value)) return true;
|
|
38
|
+
if (isUnaryExpression(value) && value.operator === "-" && isNumericLiteral(value.argument)) return true;
|
|
39
|
+
if (isTemplateLiteral(value)) return value.expressions.length === 0;
|
|
40
|
+
if (isArrayExpression(value)) return value.elements.every((element) => element !== null && isLosslesslyEvaluable(element));
|
|
41
|
+
if (isObjectExpression(value)) return value.properties.every((property) => isObjectProperty(property) && !property.computed && (isIdentifier(property.key) || isStringLiteral(property.key) || isNumericLiteral(property.key)) && isLosslesslyEvaluable(property.value));
|
|
44
42
|
return false;
|
|
45
43
|
};
|
|
46
44
|
const canLosslesslyEvaluateSource = (source) => {
|
|
47
45
|
try {
|
|
48
|
-
return isLosslesslyEvaluable(
|
|
46
|
+
return isLosslesslyEvaluable(parseExpression(source, { plugins: ["jsx", "typescript"] }));
|
|
49
47
|
} catch {
|
|
50
48
|
return false;
|
|
51
49
|
}
|
|
52
50
|
};
|
|
53
51
|
const evaluateLiteral = (rawNode) => {
|
|
54
52
|
const node = unwrapExpression(rawNode);
|
|
55
|
-
if (
|
|
56
|
-
if (
|
|
57
|
-
if (
|
|
58
|
-
if (
|
|
59
|
-
if (
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
if (
|
|
64
|
-
if (
|
|
53
|
+
if (isStringLiteral(node)) return node.value;
|
|
54
|
+
if (isNumericLiteral(node)) return node.value;
|
|
55
|
+
if (isBooleanLiteral(node)) return node.value;
|
|
56
|
+
if (isNullLiteral(node)) return null;
|
|
57
|
+
if (isIdentifier(node) && node.name === "undefined") return;
|
|
58
|
+
if (isUnaryExpression(node) && node.operator === "-" && isNumericLiteral(node.argument)) return -node.argument.value;
|
|
59
|
+
if (isTemplateLiteral(node) && node.expressions.length === 0) return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? "";
|
|
60
|
+
if (isJSXElement(node) || isJSXFragment(node)) return generateCode(node);
|
|
61
|
+
if (isArrayExpression(node)) return node.elements.map((element) => element ? evaluateLiteral(element) : null);
|
|
62
|
+
if (isObjectExpression(node)) {
|
|
65
63
|
const result = {};
|
|
66
64
|
for (const prop of node.properties) {
|
|
67
|
-
if (!
|
|
65
|
+
if (!isObjectProperty(prop)) continue;
|
|
68
66
|
let key = null;
|
|
69
|
-
if (
|
|
70
|
-
else if (
|
|
71
|
-
else if (
|
|
67
|
+
if (isIdentifier(prop.key)) key = prop.key.name;
|
|
68
|
+
else if (isStringLiteral(prop.key)) key = prop.key.value;
|
|
69
|
+
else if (isNumericLiteral(prop.key)) key = String(prop.key.value);
|
|
72
70
|
if (key === null) continue;
|
|
73
71
|
result[key] = evaluateLiteral(prop.value);
|
|
74
72
|
}
|
|
@@ -88,111 +86,31 @@ const parseValue = (value) => {
|
|
|
88
86
|
}
|
|
89
87
|
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
90
88
|
try {
|
|
91
|
-
const ast =
|
|
92
|
-
if (
|
|
89
|
+
const ast = parseExpression(trimmed, { plugins: ["jsx", "typescript"] });
|
|
90
|
+
if (isObjectExpression(ast) || isArrayExpression(ast)) return evaluateLiteral(ast);
|
|
93
91
|
} catch {}
|
|
94
92
|
return value;
|
|
95
93
|
}
|
|
96
94
|
return value;
|
|
97
95
|
};
|
|
98
|
-
const MAX_FLATTEN_DEPTH = 20;
|
|
99
|
-
const isEditablePrimitive = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
100
|
-
const flattenEditableValue = (value) => {
|
|
101
|
-
const parsed = parseValue(value);
|
|
102
|
-
if (typeof parsed !== "object" || parsed === null || Object.keys(parsed).length === 0) return null;
|
|
103
|
-
const entries = [];
|
|
104
|
-
const walk = (node, path, depth) => {
|
|
105
|
-
if (depth > MAX_FLATTEN_DEPTH) return;
|
|
106
|
-
if (isEditablePrimitive(node)) {
|
|
107
|
-
entries.push({
|
|
108
|
-
path,
|
|
109
|
-
value: node
|
|
110
|
-
});
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (Array.isArray(node)) {
|
|
114
|
-
node.forEach((item, index) => walk(item, [...path, index], depth + 1));
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (typeof node === "object" && node !== null) Object.entries(node).forEach(([key, item]) => walk(item, [...path, key], depth + 1));
|
|
118
|
-
};
|
|
119
|
-
walk(parsed, [], 0);
|
|
120
|
-
return entries.length ? entries : null;
|
|
121
|
-
};
|
|
122
|
-
const findEditableLeaf = (root, path) => {
|
|
123
|
-
let node = unwrapExpression(root);
|
|
124
|
-
for (const segment of path) {
|
|
125
|
-
if (import_lib$1.isArrayExpression(node)) {
|
|
126
|
-
if (typeof segment !== "number") return null;
|
|
127
|
-
const elements = node.elements.slice(0, segment + 1);
|
|
128
|
-
const element = node.elements[segment];
|
|
129
|
-
if (!element || elements.some((item) => import_lib$1.isSpreadElement(item))) return null;
|
|
130
|
-
node = unwrapExpression(element);
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
if (import_lib$1.isObjectExpression(node)) {
|
|
134
|
-
const key = String(segment);
|
|
135
|
-
const matches = (property) => import_lib$1.isObjectProperty(property) && !property.computed && (import_lib$1.isIdentifier(property.key) && property.key.name === key || import_lib$1.isStringLiteral(property.key) && property.key.value === key || import_lib$1.isNumericLiteral(property.key) && String(property.key.value) === key);
|
|
136
|
-
let index = node.properties.length - 1;
|
|
137
|
-
while (index >= 0 && !matches(node.properties[index])) index--;
|
|
138
|
-
const property = node.properties[index];
|
|
139
|
-
if (!property || !import_lib$1.isObjectProperty(property) || node.properties.slice(index + 1).some((item) => import_lib$1.isSpreadElement(item))) return null;
|
|
140
|
-
node = unwrapExpression(property.value);
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return node;
|
|
146
|
-
};
|
|
147
|
-
const isEditableLeaf = (node) => import_lib$1.isStringLiteral(node) || import_lib$1.isNumericLiteral(node) || import_lib$1.isBooleanLiteral(node) || import_lib$1.isUnaryExpression(node) && node.operator === "-" && import_lib$1.isNumericLiteral(node.argument) || import_lib$1.isTemplateLiteral(node) && node.expressions.length === 0 || import_lib$1.isJSXElement(node) || import_lib$1.isJSXFragment(node);
|
|
148
|
-
const quoteString = (text, quote) => {
|
|
149
|
-
if (quote === "`") return `\`${text.replace(/[\\`]|\$\{/g, (match) => `\\${match}`)}\``;
|
|
150
|
-
const escaped = JSON.stringify(text).slice(1, -1);
|
|
151
|
-
return quote === "\"" ? `"${escaped}"` : `'${escaped.replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
|
|
152
|
-
};
|
|
153
|
-
const isJSXSource = (text) => {
|
|
154
|
-
try {
|
|
155
|
-
const expression = (0, import_lib.parseExpression)(text, { plugins: ["jsx"] });
|
|
156
|
-
return import_lib$1.isJSXElement(expression) || import_lib$1.isJSXFragment(expression);
|
|
157
|
-
} catch {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
const leafSource = (value, leaf, next) => {
|
|
162
|
-
if (typeof next !== "string") return String(next);
|
|
163
|
-
if ((import_lib$1.isJSXElement(leaf) || import_lib$1.isJSXFragment(leaf)) && isJSXSource(next)) return next.trim();
|
|
164
|
-
const quote = import_lib$1.isStringLiteral(leaf) || import_lib$1.isTemplateLiteral(leaf) ? value[leaf.start] : "'";
|
|
165
|
-
return quoteString(next, quote);
|
|
166
|
-
};
|
|
167
|
-
const setEditableValue = (value, path, next) => {
|
|
168
|
-
if (!path.length) return value;
|
|
169
|
-
let leaf;
|
|
170
|
-
try {
|
|
171
|
-
leaf = findEditableLeaf((0, import_lib.parseExpression)(value, { plugins: ["jsx", "typescript"] }), path);
|
|
172
|
-
} catch {
|
|
173
|
-
return value;
|
|
174
|
-
}
|
|
175
|
-
if (!leaf || !isEditableLeaf(leaf) || leaf.start == null || leaf.end == null) return value;
|
|
176
|
-
return `${value.slice(0, leaf.start)}${leafSource(value, leaf, next)}${value.slice(leaf.end)}`;
|
|
177
|
-
};
|
|
178
96
|
const extractNodeValue = (node) => {
|
|
179
|
-
if (
|
|
97
|
+
if (isBooleanLiteral(node)) return {
|
|
180
98
|
type: "boolean",
|
|
181
99
|
value: node.value
|
|
182
100
|
};
|
|
183
|
-
if (
|
|
101
|
+
if (isNumericLiteral(node)) return {
|
|
184
102
|
type: "number",
|
|
185
103
|
value: node.value
|
|
186
104
|
};
|
|
187
|
-
if (
|
|
105
|
+
if (isUnaryExpression(node) && node.operator === "-" && isNumericLiteral(node.argument)) return {
|
|
188
106
|
type: "number",
|
|
189
107
|
value: -node.argument.value
|
|
190
108
|
};
|
|
191
|
-
if (
|
|
109
|
+
if (isStringLiteral(node)) return {
|
|
192
110
|
type: "string",
|
|
193
111
|
value: node.value
|
|
194
112
|
};
|
|
195
|
-
if (
|
|
113
|
+
if (isTemplateLiteral(node)) {
|
|
196
114
|
if (node.expressions.length === 0 && node.quasis.length === 1) return {
|
|
197
115
|
type: "string",
|
|
198
116
|
value: dedent(node.quasis[0].value.cooked ?? node.quasis[0].value.raw)
|
|
@@ -202,19 +120,19 @@ const extractNodeValue = (node) => {
|
|
|
202
120
|
value: generateCode(node)
|
|
203
121
|
};
|
|
204
122
|
}
|
|
205
|
-
if (
|
|
123
|
+
if (isNullLiteral(node)) return {
|
|
206
124
|
type: "null",
|
|
207
125
|
value: null
|
|
208
126
|
};
|
|
209
|
-
if (
|
|
127
|
+
if (isArrayExpression(node)) return {
|
|
210
128
|
type: "array",
|
|
211
129
|
value: generateCode(node)
|
|
212
130
|
};
|
|
213
|
-
if (
|
|
131
|
+
if (isObjectExpression(node)) return {
|
|
214
132
|
type: "object",
|
|
215
133
|
value: generateCode(node)
|
|
216
134
|
};
|
|
217
|
-
if (
|
|
135
|
+
if (isJSXElement(node) || isJSXFragment(node)) return {
|
|
218
136
|
type: "string",
|
|
219
137
|
value: generateCode(node)
|
|
220
138
|
};
|
|
@@ -223,39 +141,10 @@ const extractNodeValue = (node) => {
|
|
|
223
141
|
value: null
|
|
224
142
|
};
|
|
225
143
|
};
|
|
226
|
-
const createNodeFromValue = (type, value) => {
|
|
227
|
-
switch (type) {
|
|
228
|
-
case "boolean": return import_lib$1.booleanLiteral(value === true);
|
|
229
|
-
case "number": return import_lib$1.numericLiteral(Number(value));
|
|
230
|
-
case "string": return import_lib$1.stringLiteral(String(value));
|
|
231
|
-
case "null": return import_lib$1.nullLiteral();
|
|
232
|
-
case "array":
|
|
233
|
-
case "object":
|
|
234
|
-
case "unknown": return null;
|
|
235
|
-
default: return null;
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
const valueToExpression = (value) => {
|
|
239
|
-
if (typeof value === "string") return import_lib$1.stringLiteral(value);
|
|
240
|
-
if (typeof value === "number") return value < 0 ? import_lib$1.unaryExpression("-", import_lib$1.numericLiteral(-value)) : import_lib$1.numericLiteral(value);
|
|
241
|
-
if (typeof value === "boolean") return import_lib$1.booleanLiteral(value);
|
|
242
|
-
if (value === null) return import_lib$1.nullLiteral();
|
|
243
|
-
if (Array.isArray(value)) return import_lib$1.arrayExpression(value.map((item) => valueToExpression(item) ?? import_lib$1.nullLiteral()));
|
|
244
|
-
if (typeof value === "object") {
|
|
245
|
-
const properties = [];
|
|
246
|
-
for (const [key, item] of Object.entries(value)) {
|
|
247
|
-
const expr = valueToExpression(item);
|
|
248
|
-
if (expr === null) continue;
|
|
249
|
-
properties.push(import_lib$1.objectProperty(import_lib$1.stringLiteral(key), expr));
|
|
250
|
-
}
|
|
251
|
-
return import_lib$1.objectExpression(properties);
|
|
252
|
-
}
|
|
253
|
-
return null;
|
|
254
|
-
};
|
|
255
144
|
const parseArrayExpression = (value) => {
|
|
256
145
|
try {
|
|
257
|
-
const ast = unwrapExpression(
|
|
258
|
-
if (!
|
|
146
|
+
const ast = unwrapExpression(parseExpression(value, { plugins: ["jsx", "typescript"] }));
|
|
147
|
+
if (!isArrayExpression(ast)) return null;
|
|
259
148
|
return ast;
|
|
260
149
|
} catch (error) {
|
|
261
150
|
console.error("❌ Array parsing error:", error);
|
|
@@ -265,9 +154,9 @@ const parseArrayExpression = (value) => {
|
|
|
265
154
|
const extractObjectProperties = (element) => {
|
|
266
155
|
const properties = {};
|
|
267
156
|
element.properties.forEach((prop) => {
|
|
268
|
-
if (
|
|
157
|
+
if (isObjectProperty(prop) && isIdentifier(prop.key)) {
|
|
269
158
|
const key = prop.key.name;
|
|
270
|
-
if (key === "children" ||
|
|
159
|
+
if (key === "children" || isJSXElement(prop.value) || isJSXFragment(prop.value)) return;
|
|
271
160
|
const extracted = extractNodeValue(prop.value);
|
|
272
161
|
properties[key] = {
|
|
273
162
|
...extracted,
|
|
@@ -277,10 +166,6 @@ const extractObjectProperties = (element) => {
|
|
|
277
166
|
});
|
|
278
167
|
return properties;
|
|
279
168
|
};
|
|
280
|
-
const arrayExpressionToCode = (elements) => {
|
|
281
|
-
const nextAst = import_lib$1.arrayExpression(elements);
|
|
282
|
-
return generateCode(nextAst);
|
|
283
|
-
};
|
|
284
169
|
//#endregion
|
|
285
170
|
//#region src/utils/ast/binding.ts
|
|
286
171
|
const bindingTypeSchema = z.enum(BINDING_TYPES);
|
|
@@ -442,12 +327,12 @@ const getCurrentValue = (node, property) => {
|
|
|
442
327
|
case BINDING_PROP.INNER_HTML: {
|
|
443
328
|
const dsiAttr = node.attributes.find((a) => a.name === "dangerouslySetInnerHTML");
|
|
444
329
|
if (dsiAttr?.value) try {
|
|
445
|
-
const expr =
|
|
446
|
-
if (
|
|
447
|
-
const htmlProp = expr.properties.find((p) =>
|
|
330
|
+
const expr = parseExpression(dsiAttr.value, { plugins: ["jsx", "typescript"] });
|
|
331
|
+
if (isObjectExpression(expr)) {
|
|
332
|
+
const htmlProp = expr.properties.find((p) => isObjectProperty(p) && isIdentifier(p.key) && p.key.name === "__html");
|
|
448
333
|
if (htmlProp) {
|
|
449
|
-
if (
|
|
450
|
-
if (
|
|
334
|
+
if (isStringLiteral(htmlProp.value)) return htmlProp.value.value;
|
|
335
|
+
if (isTemplateLiteral(htmlProp.value) && htmlProp.value.expressions.length === 0) return htmlProp.value.quasis[0]?.value.cooked ?? htmlProp.value.quasis[0]?.value.raw ?? "";
|
|
451
336
|
}
|
|
452
337
|
}
|
|
453
338
|
} catch {}
|
|
@@ -498,13 +383,13 @@ const findEditableChildren = (node) => {
|
|
|
498
383
|
//#endregion
|
|
499
384
|
//#region src/utils/ast/extract.ts
|
|
500
385
|
const collectText = (children) => {
|
|
501
|
-
return children.filter((c) =>
|
|
386
|
+
return children.filter((c) => isJSXText(c)).map((c) => c.value.trim()).filter((v) => v.length).join(" ");
|
|
502
387
|
};
|
|
503
388
|
const parseJSXName = (tagName) => {
|
|
504
389
|
const parts = tagName.split(".");
|
|
505
|
-
if (parts.length === 1) return
|
|
506
|
-
let expr =
|
|
507
|
-
for (let i = 1; i < parts.length; i++) expr =
|
|
390
|
+
if (parts.length === 1) return jsxIdentifier(parts[0]);
|
|
391
|
+
let expr = jsxIdentifier(parts[0]);
|
|
392
|
+
for (let i = 1; i < parts.length; i++) expr = jsxMemberExpression(expr, jsxIdentifier(parts[i]));
|
|
508
393
|
return expr;
|
|
509
394
|
};
|
|
510
395
|
const extractCache = createBoundedCache(CONFIG.CACHE_LIMIT);
|
|
@@ -528,19 +413,19 @@ const extractAttributes = (attributes, source) => {
|
|
|
528
413
|
const allAttrs = [];
|
|
529
414
|
const dataAttrs = [];
|
|
530
415
|
for (const attr of attributes) {
|
|
531
|
-
if (!
|
|
416
|
+
if (!isJSXAttribute(attr) || !isJSXIdentifier(attr.name)) continue;
|
|
532
417
|
const name = attr.name.name;
|
|
533
418
|
let value = null;
|
|
534
|
-
let isStringLiteral = false;
|
|
419
|
+
let isStringLiteral$1 = false;
|
|
535
420
|
if (attr.value) {
|
|
536
|
-
if (
|
|
421
|
+
if (isStringLiteral(attr.value)) {
|
|
537
422
|
value = attr.value.value;
|
|
538
|
-
isStringLiteral = true;
|
|
539
|
-
} else if (
|
|
423
|
+
isStringLiteral$1 = true;
|
|
424
|
+
} else if (isJSXExpressionContainer(attr.value)) try {
|
|
540
425
|
const expression = attr.value.expression;
|
|
541
|
-
const structural =
|
|
426
|
+
const structural = isArrayExpression(unwrapExpression(expression)) || isObjectExpression(unwrapExpression(expression));
|
|
542
427
|
value = source && structural && expression.start != null && expression.end != null ? source.slice(expression.start, expression.end) : generateCode(expression);
|
|
543
|
-
isStringLiteral = false;
|
|
428
|
+
isStringLiteral$1 = false;
|
|
544
429
|
} catch {
|
|
545
430
|
value = null;
|
|
546
431
|
}
|
|
@@ -548,7 +433,7 @@ const extractAttributes = (attributes, source) => {
|
|
|
548
433
|
const entry = {
|
|
549
434
|
name,
|
|
550
435
|
value,
|
|
551
|
-
isStringLiteral
|
|
436
|
+
isStringLiteral: isStringLiteral$1
|
|
552
437
|
};
|
|
553
438
|
allAttrs.push(entry);
|
|
554
439
|
if (name.startsWith("data-")) dataAttrs.push(entry);
|
|
@@ -560,7 +445,7 @@ const extractAttributes = (attributes, source) => {
|
|
|
560
445
|
};
|
|
561
446
|
const buildChildElements = (node) => {
|
|
562
447
|
const childElements = [];
|
|
563
|
-
if (node.textContent) childElements.push(
|
|
448
|
+
if (node.textContent) childElements.push(jsxText(node.textContent));
|
|
564
449
|
node.children?.forEach((child) => {
|
|
565
450
|
const childJSX = nodeToJSX(child);
|
|
566
451
|
if (childJSX) childElements.push(childJSX);
|
|
@@ -571,22 +456,22 @@ const nodeToJSX = (node) => {
|
|
|
571
456
|
try {
|
|
572
457
|
if (node.isFragment) {
|
|
573
458
|
const childElements = buildChildElements(node);
|
|
574
|
-
return
|
|
459
|
+
return jsxFragment(jsxOpeningFragment(), jsxClosingFragment(), childElements);
|
|
575
460
|
}
|
|
576
461
|
if (node.tagName === "div" && node.dataAttributes.some((attr) => attr.name === "data-item")) {
|
|
577
462
|
if (node.children) return nodeToJSX(node.children[0]);
|
|
578
463
|
return null;
|
|
579
464
|
}
|
|
580
465
|
const attributes = node.attributes.map((attr) => {
|
|
581
|
-
const attrName =
|
|
582
|
-
if (!attr.value) return
|
|
583
|
-
return
|
|
466
|
+
const attrName = jsxIdentifier(attr.name);
|
|
467
|
+
if (!attr.value) return jsxAttribute(attrName, null);
|
|
468
|
+
return jsxAttribute(attrName, attrValue(attr));
|
|
584
469
|
});
|
|
585
470
|
const elementName = parseJSXName(node.tagName);
|
|
586
|
-
const openingElement =
|
|
587
|
-
const closingElement =
|
|
471
|
+
const openingElement = jsxOpeningElement(elementName, attributes);
|
|
472
|
+
const closingElement = jsxClosingElement(elementName);
|
|
588
473
|
const children = buildChildElements(node);
|
|
589
|
-
return
|
|
474
|
+
return jsxElement(openingElement, closingElement, children);
|
|
590
475
|
} catch (error) {
|
|
591
476
|
console.error("❌ DataAttrNode to JSX conversion error:", error);
|
|
592
477
|
return null;
|
|
@@ -616,11 +501,11 @@ const createFragmentNode = (textContent, children) => ({
|
|
|
616
501
|
isFragment: true
|
|
617
502
|
});
|
|
618
503
|
const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, source, options) => {
|
|
619
|
-
const jsxChildren = jsxElement.children.filter((child) =>
|
|
504
|
+
const jsxChildren = jsxElement.children.filter((child) => isJSXElement(child) || isJSXFragment(child));
|
|
620
505
|
if (!jsxChildren.length) return;
|
|
621
506
|
const childrenNodes = [];
|
|
622
507
|
jsxChildren.forEach((child) => {
|
|
623
|
-
if (
|
|
508
|
+
if (isJSXElement(child)) {
|
|
624
509
|
const childResults = extractFromNode(child, processedNodes, source, options);
|
|
625
510
|
if (shouldWrap) {
|
|
626
511
|
const wrapperNode = createWrapperNode(collectText(child.children), childResults);
|
|
@@ -629,11 +514,11 @@ const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, s
|
|
|
629
514
|
if (dataId) wrapperNode.id = `child:${dataId}`;
|
|
630
515
|
childrenNodes.push(wrapperNode);
|
|
631
516
|
} else childrenNodes.push(...childResults);
|
|
632
|
-
} else if (
|
|
517
|
+
} else if (isJSXFragment(child)) {
|
|
633
518
|
processedNodes?.add(child);
|
|
634
519
|
const fragmentChildren = [];
|
|
635
520
|
child.children.forEach((fragmentChild) => {
|
|
636
|
-
if (
|
|
521
|
+
if (isJSXElement(fragmentChild)) {
|
|
637
522
|
const childResults = extractFromNode(fragmentChild, processedNodes, source, options);
|
|
638
523
|
fragmentChildren.push(...childResults);
|
|
639
524
|
}
|
|
@@ -648,26 +533,26 @@ const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, s
|
|
|
648
533
|
return childrenNodes.length ? childrenNodes : void 0;
|
|
649
534
|
};
|
|
650
535
|
const skipItemsChildren = (jsxElement, processedNodes, propertyName = "items") => {
|
|
651
|
-
const itemsAttr = jsxElement.openingElement.attributes.find((attr) =>
|
|
652
|
-
if (!itemsAttr || !
|
|
653
|
-
if (itemsAttr.value &&
|
|
654
|
-
if (
|
|
655
|
-
if (
|
|
536
|
+
const itemsAttr = jsxElement.openingElement.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === propertyName);
|
|
537
|
+
if (!itemsAttr || !isJSXAttribute(itemsAttr)) return;
|
|
538
|
+
if (itemsAttr.value && isJSXExpressionContainer(itemsAttr.value) && isArrayExpression(itemsAttr.value.expression)) itemsAttr.value.expression.elements.forEach((element) => {
|
|
539
|
+
if (isObjectExpression(element)) element.properties.forEach((prop) => {
|
|
540
|
+
if (isObjectProperty(prop) && isIdentifier(prop.key) && isJSXElement(prop.value)) markProcessedJSX(prop.value, processedNodes);
|
|
656
541
|
});
|
|
657
542
|
});
|
|
658
543
|
};
|
|
659
544
|
const markProcessedJSX = (node, processedNodes) => {
|
|
660
|
-
if (
|
|
545
|
+
if (isJSXElement(node) || isJSXFragment(node)) {
|
|
661
546
|
processedNodes.add(node);
|
|
662
547
|
node.children.forEach((child) => markProcessedJSX(child, processedNodes));
|
|
663
548
|
return;
|
|
664
549
|
}
|
|
665
|
-
if (
|
|
550
|
+
if (isJSXExpressionContainer(node) || isParenthesizedExpression(node)) markProcessedJSX(node.expression, processedNodes);
|
|
666
551
|
};
|
|
667
552
|
const getBindingExpression = (opening) => {
|
|
668
|
-
for (const attr of opening.attributes) if (
|
|
553
|
+
for (const attr of opening.attributes) if (isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.BINDING && attr.value && isJSXExpressionContainer(attr.value)) {
|
|
669
554
|
const expression = unwrapExpression(attr.value.expression);
|
|
670
|
-
if (
|
|
555
|
+
if (isArrayExpression(expression)) return expression;
|
|
671
556
|
}
|
|
672
557
|
return null;
|
|
673
558
|
};
|
|
@@ -696,7 +581,7 @@ const readNodeBindingInfo = (node, source, options) => {
|
|
|
696
581
|
};
|
|
697
582
|
const parseToNodes = (raw, options) => {
|
|
698
583
|
const wrapped = wrap(raw);
|
|
699
|
-
const ast =
|
|
584
|
+
const ast = parse(wrapped, {
|
|
700
585
|
sourceType: "module",
|
|
701
586
|
plugins: ["jsx", "typescript"],
|
|
702
587
|
errorRecovery: true
|
|
@@ -873,7 +758,7 @@ const getChildrenSignatures = (nodes) => {
|
|
|
873
758
|
};
|
|
874
759
|
const indicesAreValid = (indices, count) => Array.isArray(indices) && new Set(indices).size === indices.length && indices.every((index) => Number.isInteger(index) && index >= 0 && index < count);
|
|
875
760
|
const copySource = (source, usedIds) => {
|
|
876
|
-
const node =
|
|
761
|
+
const node = parseExpression(source, { plugins: ["jsx", "typescript"] });
|
|
877
762
|
const edits = [];
|
|
878
763
|
const newId = () => {
|
|
879
764
|
let id = nanoid(12);
|
|
@@ -881,15 +766,15 @@ const copySource = (source, usedIds) => {
|
|
|
881
766
|
usedIds.add(id);
|
|
882
767
|
return id;
|
|
883
768
|
};
|
|
884
|
-
|
|
885
|
-
if (!
|
|
886
|
-
const ids = child.attributes.filter((attr) =>
|
|
769
|
+
traverseFast(node, (child) => {
|
|
770
|
+
if (!isJSXOpeningElement(child)) return;
|
|
771
|
+
const ids = child.attributes.filter((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name, { name: "data-id" }));
|
|
887
772
|
if (ids.length > 1) throw new Error("Duplicate data-id attributes");
|
|
888
773
|
const attr = ids[0];
|
|
889
|
-
if (attr && child.attributes.slice(child.attributes.indexOf(attr) + 1).some((attribute) =>
|
|
774
|
+
if (attr && child.attributes.slice(child.attributes.indexOf(attr) + 1).some((attribute) => isJSXSpreadAttribute(attribute))) throw new Error("A spread may override the copied data-id");
|
|
890
775
|
if (attr) {
|
|
891
776
|
const value = attr.value;
|
|
892
|
-
if (!
|
|
777
|
+
if (!isStringLiteral(value) || value.start == null || value.end == null) throw new Error("Cannot copy a dynamic data-id");
|
|
893
778
|
edits.push({
|
|
894
779
|
start: value.start,
|
|
895
780
|
end: value.end,
|
|
@@ -911,7 +796,7 @@ const editChildrenSource = (source, parent, input, options) => {
|
|
|
911
796
|
try {
|
|
912
797
|
if (!parent.closingElement || parent.start == null || parent.end == null) return null;
|
|
913
798
|
const value = typeof input === "string" ? JSON.parse(input) : input;
|
|
914
|
-
const children = parent.children.filter((child) =>
|
|
799
|
+
const children = parent.children.filter((child) => isJSXElement(child) || isJSXFragment(child));
|
|
915
800
|
const raw = children.map((child) => source.slice(child.start, child.end));
|
|
916
801
|
const models = extract(source.slice(parent.start, parent.end), options)[0]?.children ?? [];
|
|
917
802
|
if (models.length !== children.length) return null;
|
|
@@ -934,7 +819,7 @@ const editChildrenSource = (source, parent, input, options) => {
|
|
|
934
819
|
};
|
|
935
820
|
if (Array.isArray(value)) {
|
|
936
821
|
const desired = modeledSignatures(value);
|
|
937
|
-
const lossless = raw.every((text, index) => generateCode(
|
|
822
|
+
const lossless = raw.every((text, index) => generateCode(parseExpression(text, { plugins: ["jsx", "typescript"] })) === signatures[index]);
|
|
938
823
|
const consumed = /* @__PURE__ */ new Set();
|
|
939
824
|
const next = desired.map((signature, position) => {
|
|
940
825
|
const index = signatures.findIndex((candidate, i) => candidate === signature && !consumed.has(i) && (value[position].source === void 0 || value[position].source === raw[i]));
|
|
@@ -947,8 +832,8 @@ const editChildrenSource = (source, parent, input, options) => {
|
|
|
947
832
|
});
|
|
948
833
|
const countIds = (text) => {
|
|
949
834
|
const counts = /* @__PURE__ */ new Map();
|
|
950
|
-
|
|
951
|
-
if (
|
|
835
|
+
traverseFast(parseExpression(text, { plugins: ["jsx", "typescript"] }), (node) => {
|
|
836
|
+
if (isJSXAttribute(node) && isJSXIdentifier(node.name, { name: "data-id" }) && isStringLiteral(node.value)) counts.set(node.value.value, (counts.get(node.value.value) ?? 0) + 1);
|
|
952
837
|
});
|
|
953
838
|
return counts;
|
|
954
839
|
};
|
|
@@ -960,8 +845,8 @@ const editChildrenSource = (source, parent, input, options) => {
|
|
|
960
845
|
if (request?.kind !== "children-edit" || !Array.isArray(request.expected) || request.expected.length !== signatures.length || !getChildrenSignatures(models).every((signature, index) => signature === request.expected[index]) || !request.action) return null;
|
|
961
846
|
const { action } = request;
|
|
962
847
|
const usedIds = /* @__PURE__ */ new Set();
|
|
963
|
-
|
|
964
|
-
if (
|
|
848
|
+
traverseFast(parent, (node) => {
|
|
849
|
+
if (isJSXAttribute(node) && isJSXIdentifier(node.name, { name: "data-id" }) && isStringLiteral(node.value)) usedIds.add(node.value.value);
|
|
965
850
|
});
|
|
966
851
|
switch (action.type) {
|
|
967
852
|
case "move": {
|
|
@@ -1007,7 +892,42 @@ const editChildrenSource = (source, parent, input, options) => {
|
|
|
1007
892
|
}
|
|
1008
893
|
};
|
|
1009
894
|
//#endregion
|
|
1010
|
-
//#region src/utils/ast/
|
|
895
|
+
//#region src/utils/ast/value-expression.ts
|
|
896
|
+
const createNodeFromValue = (type, value) => {
|
|
897
|
+
switch (type) {
|
|
898
|
+
case "boolean": return booleanLiteral(value === true);
|
|
899
|
+
case "number": return numericLiteral(Number(value));
|
|
900
|
+
case "string": return stringLiteral(String(value));
|
|
901
|
+
case "null": return nullLiteral();
|
|
902
|
+
case "array":
|
|
903
|
+
case "object":
|
|
904
|
+
case "unknown": return null;
|
|
905
|
+
default: return null;
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
const valueToExpression = (value) => {
|
|
909
|
+
if (typeof value === "string") return stringLiteral(value);
|
|
910
|
+
if (typeof value === "number") return value < 0 ? unaryExpression("-", numericLiteral(-value)) : numericLiteral(value);
|
|
911
|
+
if (typeof value === "boolean") return booleanLiteral(value);
|
|
912
|
+
if (value === null) return nullLiteral();
|
|
913
|
+
if (Array.isArray(value)) return arrayExpression(value.map((item) => valueToExpression(item) ?? nullLiteral()));
|
|
914
|
+
if (typeof value === "object") {
|
|
915
|
+
const properties = [];
|
|
916
|
+
for (const [key, item] of Object.entries(value)) {
|
|
917
|
+
const expr = valueToExpression(item);
|
|
918
|
+
if (expr === null) continue;
|
|
919
|
+
properties.push(objectProperty(stringLiteral(key), expr));
|
|
920
|
+
}
|
|
921
|
+
return objectExpression(properties);
|
|
922
|
+
}
|
|
923
|
+
return null;
|
|
924
|
+
};
|
|
925
|
+
const arrayExpressionToCode = (elements) => {
|
|
926
|
+
const nextAst = arrayExpression(elements);
|
|
927
|
+
return generateCode(nextAst);
|
|
928
|
+
};
|
|
929
|
+
//#endregion
|
|
930
|
+
//#region src/utils/ast/edit-source.ts
|
|
1011
931
|
const childrenRange = (element) => {
|
|
1012
932
|
const { openingElement, closingElement } = element;
|
|
1013
933
|
if (!closingElement || openingElement.end == null || closingElement.start == null) return null;
|
|
@@ -1017,7 +937,7 @@ const childrenRange = (element) => {
|
|
|
1017
937
|
};
|
|
1018
938
|
};
|
|
1019
939
|
const findAttribute = (opening, propertyName) => {
|
|
1020
|
-
return opening.attributes.find((attr) =>
|
|
940
|
+
return opening.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === propertyName);
|
|
1021
941
|
};
|
|
1022
942
|
const attributeInsertPoint = (opening) => {
|
|
1023
943
|
return opening.attributes[opening.attributes.length - 1]?.end ?? opening.name.end ?? null;
|
|
@@ -1026,7 +946,7 @@ const editInnerText = (source, element, value) => {
|
|
|
1026
946
|
const range = childrenRange(element);
|
|
1027
947
|
if (!range) return [];
|
|
1028
948
|
const [only] = element.children;
|
|
1029
|
-
if (element.children.length === 1 &&
|
|
949
|
+
if (element.children.length === 1 && isJSXText(only) && only.start != null && only.end != null) {
|
|
1030
950
|
const raw = source.slice(only.start, only.end);
|
|
1031
951
|
if (raw.trim() !== "") {
|
|
1032
952
|
const leading = raw.length - raw.trimStart().length;
|
|
@@ -1039,7 +959,7 @@ const editInnerText = (source, element, value) => {
|
|
|
1039
959
|
}
|
|
1040
960
|
}
|
|
1041
961
|
const edits = [];
|
|
1042
|
-
for (const child of element.children) if (
|
|
962
|
+
for (const child of element.children) if (isJSXText(child) && child.start != null && child.end != null) edits.push({
|
|
1043
963
|
start: child.start,
|
|
1044
964
|
end: child.end,
|
|
1045
965
|
content: ""
|
|
@@ -1069,7 +989,7 @@ const editRichtext = (element, value) => {
|
|
|
1069
989
|
content: ""
|
|
1070
990
|
});
|
|
1071
991
|
const opening = element.openingElement;
|
|
1072
|
-
const attribute =
|
|
992
|
+
const attribute = jsxAttribute(jsxIdentifier("dangerouslySetInnerHTML"), jsxExpressionContainer(objectExpression([objectProperty(identifier("__html"), stringLiteral(value))])));
|
|
1073
993
|
const content = generateCode(attribute);
|
|
1074
994
|
const existing = findAttribute(opening, "dangerouslySetInnerHTML");
|
|
1075
995
|
if (existing && existing.start != null && existing.end != null) {
|
|
@@ -1108,11 +1028,11 @@ const editJsxAttribute = (opening, propertyName, value) => {
|
|
|
1108
1028
|
content: `=${content}`
|
|
1109
1029
|
}];
|
|
1110
1030
|
};
|
|
1111
|
-
const holdsStructuralExpression = (value) =>
|
|
1031
|
+
const holdsStructuralExpression = (value) => isJSXExpressionContainer(value) && (isArrayExpression(unwrapExpression(value.expression)) || isObjectExpression(unwrapExpression(value.expression)));
|
|
1112
1032
|
const structuralSource = (value) => {
|
|
1113
1033
|
try {
|
|
1114
|
-
const expression =
|
|
1115
|
-
return
|
|
1034
|
+
const expression = parseExpression(value.trim(), { plugins: ["jsx", "typescript"] });
|
|
1035
|
+
return isArrayExpression(unwrapExpression(expression)) || isObjectExpression(unwrapExpression(expression)) ? expression : null;
|
|
1116
1036
|
} catch {
|
|
1117
1037
|
return null;
|
|
1118
1038
|
}
|
|
@@ -1120,29 +1040,29 @@ const structuralSource = (value) => {
|
|
|
1120
1040
|
const buildAttributeValue = (value, type, current) => {
|
|
1121
1041
|
if (type === "array" || type === "object") {
|
|
1122
1042
|
if (typeof value === "string") try {
|
|
1123
|
-
return
|
|
1043
|
+
return jsxExpressionContainer(parseExpression(value.trim(), { plugins: ["jsx", "typescript"] }));
|
|
1124
1044
|
} catch {
|
|
1125
|
-
return
|
|
1045
|
+
return stringLiteral(value);
|
|
1126
1046
|
}
|
|
1127
1047
|
const expr = valueToExpression(value);
|
|
1128
|
-
return expr ?
|
|
1048
|
+
return expr ? jsxExpressionContainer(expr) : stringLiteral("");
|
|
1129
1049
|
}
|
|
1130
1050
|
if (typeof value === "string") {
|
|
1131
1051
|
if (holdsStructuralExpression(current) && !(type && STRING_VALUED_TYPES.has(type))) {
|
|
1132
1052
|
const structural = structuralSource(value);
|
|
1133
|
-
if (structural) return
|
|
1053
|
+
if (structural) return jsxExpressionContainer(structural);
|
|
1134
1054
|
}
|
|
1135
|
-
return
|
|
1055
|
+
return stringLiteral(value);
|
|
1136
1056
|
}
|
|
1137
1057
|
const expr = valueToExpression(value);
|
|
1138
|
-
return expr ?
|
|
1058
|
+
return expr ? jsxExpressionContainer(expr) : stringLiteral(String(value));
|
|
1139
1059
|
};
|
|
1140
1060
|
const editAttribute = (opening, propertyName, value, type) => {
|
|
1141
1061
|
const attribute = findAttribute(opening, propertyName);
|
|
1142
1062
|
if (!attribute || attribute.start == null || attribute.end == null) return null;
|
|
1143
1063
|
if (typeof value === "string" && (type === "array" || type === "object" || holdsStructuralExpression(attribute.value) && !(type && STRING_VALUED_TYPES.has(type)))) {
|
|
1144
1064
|
const expression = structuralSource(value);
|
|
1145
|
-
if (expression &&
|
|
1065
|
+
if (expression && isJSXExpressionContainer(attribute.value)) {
|
|
1146
1066
|
const text = value.trim();
|
|
1147
1067
|
const lineComment = expression.trailingComments?.some((comment) => comment.type === "CommentLine");
|
|
1148
1068
|
return [{
|
|
@@ -1152,7 +1072,7 @@ const editAttribute = (opening, propertyName, value, type) => {
|
|
|
1152
1072
|
}];
|
|
1153
1073
|
}
|
|
1154
1074
|
}
|
|
1155
|
-
const content = generateCode(
|
|
1075
|
+
const content = generateCode(jsxAttribute(attribute.name, buildAttributeValue(value, type, attribute.value)));
|
|
1156
1076
|
return [{
|
|
1157
1077
|
start: attribute.start,
|
|
1158
1078
|
end: attribute.end,
|
|
@@ -1178,168 +1098,165 @@ const addAttribute = (source, opening, propertyName, value, type) => {
|
|
|
1178
1098
|
return [{
|
|
1179
1099
|
start: insertAt,
|
|
1180
1100
|
end: insertAt,
|
|
1181
|
-
content: `${lastStart != null && lineStart > 0 && /^\s*$/.test(source.slice(lineStart, lastStart)) ? "\n" : " "}${type === "jsx" ? `${propertyName}={${String(value).trim()}}` : generateCode(
|
|
1101
|
+
content: `${lastStart != null && lineStart > 0 && /^\s*$/.test(source.slice(lineStart, lastStart)) ? "\n" : " "}${type === "jsx" ? `${propertyName}={${String(value).trim()}}` : generateCode(jsxAttribute(jsxIdentifier(propertyName), buildAttributeValue(value, type)))}`,
|
|
1182
1102
|
indent: true
|
|
1183
1103
|
}];
|
|
1184
1104
|
};
|
|
1185
1105
|
const canEditAttributeValue = (attribute, value, type) => {
|
|
1186
|
-
if (!
|
|
1106
|
+
if (!isJSXExpressionContainer(attribute.value) || isJSXEmptyExpression(attribute.value.expression) || isLosslesslyEvaluable(attribute.value.expression)) return true;
|
|
1187
1107
|
return typeof value === "string" && holdsStructuralExpression(attribute.value) && !(type && STRING_VALUED_TYPES.has(type)) && structuralSource(value) !== null;
|
|
1188
1108
|
};
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region src/utils/ast/update.ts
|
|
1111
|
+
const hasDataId = (opening, dataId) => opening.attributes.some((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.ID && attr.value && isStringLiteral(attr.value) && attr.value.value === dataId);
|
|
1112
|
+
const findJSXAttribute = (opening, name) => opening.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === name);
|
|
1113
|
+
const findBinding = (opening, { dataId, label, property, options }) => {
|
|
1114
|
+
const bindingAttr = findJSXAttribute(opening, DATA_ATTR.BINDING);
|
|
1115
|
+
if (bindingAttr && !bindingAttr.value) return { failure: {
|
|
1116
|
+
reason: "no-binding",
|
|
1117
|
+
dataId
|
|
1118
|
+
} };
|
|
1119
|
+
let own;
|
|
1120
|
+
if (bindingAttr?.value) {
|
|
1121
|
+
let bindingValue = "";
|
|
1122
|
+
if (isStringLiteral(bindingAttr.value)) bindingValue = bindingAttr.value.value;
|
|
1123
|
+
else if (isJSXExpressionContainer(bindingAttr.value)) try {
|
|
1124
|
+
bindingValue = generateCode(bindingAttr.value.expression);
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
return { failure: {
|
|
1127
|
+
reason: "parse-error",
|
|
1128
|
+
error
|
|
1129
|
+
} };
|
|
1130
|
+
}
|
|
1131
|
+
own = parseBinding(bindingValue);
|
|
1132
|
+
}
|
|
1133
|
+
const keyAttr = findJSXAttribute(opening, DATA_ATTR.BINDING_KEY);
|
|
1134
|
+
const bindings = resolveBindings(own, keyAttr && (keyAttr.value && isStringLiteral(keyAttr.value) ? keyAttr.value.value : null), getJSXTagName(opening), options);
|
|
1135
|
+
if (!own && bindings.length === 0) return { failure: {
|
|
1136
|
+
reason: "no-binding",
|
|
1137
|
+
dataId
|
|
1138
|
+
} };
|
|
1139
|
+
const matches = bindings.filter((binding) => property !== void 0 ? binding.property === property : binding.label === label);
|
|
1140
|
+
if (matches.length === 0) return { failure: {
|
|
1141
|
+
reason: "binding-not-declared",
|
|
1142
|
+
dataId,
|
|
1143
|
+
label,
|
|
1144
|
+
property
|
|
1145
|
+
} };
|
|
1146
|
+
if (matches.length > 1) return { failure: {
|
|
1147
|
+
reason: "duplicate-binding",
|
|
1148
|
+
dataId,
|
|
1149
|
+
label,
|
|
1150
|
+
property,
|
|
1151
|
+
count: matches.length
|
|
1152
|
+
} };
|
|
1153
|
+
return { binding: matches[0] };
|
|
1154
|
+
};
|
|
1155
|
+
const checkEdit = (binding, { dataId, value }) => {
|
|
1156
|
+
const property = binding.property;
|
|
1157
|
+
if (RESERVED_BINDING_PROPERTIES.includes(property)) return {
|
|
1158
|
+
reason: "reserved-property",
|
|
1159
|
+
dataId,
|
|
1160
|
+
property
|
|
1161
|
+
};
|
|
1162
|
+
if (value === void 0 && binding.required) return {
|
|
1163
|
+
reason: "required-property",
|
|
1164
|
+
dataId,
|
|
1165
|
+
property
|
|
1166
|
+
};
|
|
1167
|
+
};
|
|
1168
|
+
const toElementEdit = (result, onNull) => result ? { edits: result } : { failure: onNull() };
|
|
1169
|
+
const editProperty = (source, element, binding, { dataId, value, options }) => {
|
|
1170
|
+
const opening = element.openingElement;
|
|
1171
|
+
const prop = binding.property;
|
|
1172
|
+
const unset = value === void 0;
|
|
1173
|
+
const couldNotUpdate = () => ({
|
|
1174
|
+
reason: "parse-error",
|
|
1175
|
+
error: /* @__PURE__ */ new Error(`could not update "${prop}"`)
|
|
1176
|
+
});
|
|
1177
|
+
const contentWithoutSlot = !unset && String(value) !== "" && !childrenRange(element);
|
|
1178
|
+
switch (prop) {
|
|
1179
|
+
case BINDING_PROP.INNER_TEXT:
|
|
1180
|
+
if (contentWithoutSlot) return { failure: {
|
|
1181
|
+
reason: "self-closing",
|
|
1182
|
+
dataId,
|
|
1183
|
+
property: prop
|
|
1184
|
+
} };
|
|
1185
|
+
return toElementEdit(editInnerText(source, element, unset ? "" : String(value)), couldNotUpdate);
|
|
1186
|
+
case BINDING_PROP.INNER_HTML:
|
|
1187
|
+
if (contentWithoutSlot && binding.type !== "richtext") return { failure: {
|
|
1188
|
+
reason: "self-closing",
|
|
1189
|
+
dataId,
|
|
1190
|
+
property: prop
|
|
1191
|
+
} };
|
|
1192
|
+
return toElementEdit(binding.type === "richtext" ? editRichtext(element, unset ? "" : String(value)) : editInnerHTML(element, unset ? "" : String(value)), couldNotUpdate);
|
|
1193
|
+
case BINDING_PROP.CHILDREN:
|
|
1194
|
+
if (unset) return { failure: {
|
|
1195
|
+
reason: "unsupported-syntax",
|
|
1196
|
+
dataId,
|
|
1197
|
+
property: prop
|
|
1198
|
+
} };
|
|
1199
|
+
return toElementEdit(editChildrenSource(source, element, value, options), () => ({
|
|
1200
|
+
reason: "parse-error",
|
|
1201
|
+
error: /* @__PURE__ */ new Error("Unsupported or stale children edit; source was preserved")
|
|
1202
|
+
}));
|
|
1203
|
+
default: {
|
|
1204
|
+
const attribute = findAttribute(opening, prop);
|
|
1205
|
+
if (unset) return toElementEdit(attribute ? removeAttribute(source, attribute) : [], () => ({
|
|
1206
|
+
reason: "parse-error",
|
|
1207
|
+
error: /* @__PURE__ */ new Error(`could not remove "${prop}"`)
|
|
1208
|
+
}));
|
|
1209
|
+
if (!attribute) return toElementEdit(value === "" ? [] : addAttribute(source, opening, prop, value, binding.type), () => ({
|
|
1210
|
+
reason: "attribute-not-found",
|
|
1211
|
+
dataId,
|
|
1212
|
+
property: prop
|
|
1213
|
+
}));
|
|
1214
|
+
if (binding.type !== "jsx" && !canEditAttributeValue(attribute, value, binding.type)) return { failure: {
|
|
1215
|
+
reason: "unsupported-syntax",
|
|
1216
|
+
dataId,
|
|
1217
|
+
property: prop
|
|
1218
|
+
} };
|
|
1219
|
+
return toElementEdit(binding.type === "jsx" ? editJsxAttribute(opening, prop, value) : editAttribute(opening, prop, value, binding.type), () => ({
|
|
1220
|
+
reason: "attribute-not-found",
|
|
1221
|
+
dataId,
|
|
1222
|
+
property: prop
|
|
1223
|
+
}));
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
const editElement = (source, element, request) => {
|
|
1228
|
+
const found = findBinding(element.openingElement, request);
|
|
1229
|
+
if ("failure" in found) return found;
|
|
1230
|
+
const refused = checkEdit(found.binding, request);
|
|
1231
|
+
if (refused) return { failure: refused };
|
|
1232
|
+
return editProperty(source, element, found.binding, request);
|
|
1233
|
+
};
|
|
1189
1234
|
const update = (code, dataId, label, value, property, options = {}) => {
|
|
1235
|
+
const request = {
|
|
1236
|
+
dataId,
|
|
1237
|
+
label,
|
|
1238
|
+
value,
|
|
1239
|
+
property,
|
|
1240
|
+
options
|
|
1241
|
+
};
|
|
1190
1242
|
try {
|
|
1191
1243
|
const wrapped = wrap(code);
|
|
1192
|
-
const ast =
|
|
1244
|
+
const ast = parse(wrapped, {
|
|
1193
1245
|
sourceType: "module",
|
|
1194
1246
|
plugins: ["jsx", "typescript"]
|
|
1195
1247
|
});
|
|
1196
1248
|
let changed = false;
|
|
1197
1249
|
let failure;
|
|
1198
1250
|
const edits = [];
|
|
1199
|
-
const collect = (result, onNull) => {
|
|
1200
|
-
if (!result) {
|
|
1201
|
-
failure = onNull();
|
|
1202
|
-
return;
|
|
1203
|
-
}
|
|
1204
|
-
edits.push(...result);
|
|
1205
|
-
changed = true;
|
|
1206
|
-
};
|
|
1207
1251
|
traverse(ast, { JSXElement(path) {
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
const bindingAttr = opening.attributes.find((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.BINDING);
|
|
1213
|
-
if (bindingAttr && !bindingAttr.value) {
|
|
1214
|
-
failure = {
|
|
1215
|
-
reason: "no-binding",
|
|
1216
|
-
dataId
|
|
1217
|
-
};
|
|
1252
|
+
if (!hasDataId(path.node.openingElement, dataId)) return;
|
|
1253
|
+
const result = editElement(wrapped, path.node, request);
|
|
1254
|
+
if ("failure" in result) {
|
|
1255
|
+
failure = result.failure;
|
|
1218
1256
|
return;
|
|
1219
1257
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
let bindingValue = "";
|
|
1223
|
-
if (import_lib$1.isStringLiteral(bindingAttr.value)) bindingValue = bindingAttr.value.value;
|
|
1224
|
-
else if (import_lib$1.isJSXExpressionContainer(bindingAttr.value)) try {
|
|
1225
|
-
bindingValue = generateCode(bindingAttr.value.expression);
|
|
1226
|
-
} catch (error) {
|
|
1227
|
-
failure = {
|
|
1228
|
-
reason: "parse-error",
|
|
1229
|
-
error
|
|
1230
|
-
};
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
own = parseBinding(bindingValue);
|
|
1234
|
-
}
|
|
1235
|
-
const keyAttr = opening.attributes.find((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.BINDING_KEY);
|
|
1236
|
-
const bindings = resolveBindings(own, keyAttr && (keyAttr.value && import_lib$1.isStringLiteral(keyAttr.value) ? keyAttr.value.value : null), getJSXTagName(opening), options);
|
|
1237
|
-
if (!own && bindings.length === 0) {
|
|
1238
|
-
failure = {
|
|
1239
|
-
reason: "no-binding",
|
|
1240
|
-
dataId
|
|
1241
|
-
};
|
|
1242
|
-
return;
|
|
1243
|
-
}
|
|
1244
|
-
const matches = bindings.filter((binding) => property !== void 0 ? binding.property === property : binding.label === label);
|
|
1245
|
-
if (matches.length === 0) {
|
|
1246
|
-
failure = {
|
|
1247
|
-
reason: "binding-not-declared",
|
|
1248
|
-
dataId,
|
|
1249
|
-
label,
|
|
1250
|
-
property
|
|
1251
|
-
};
|
|
1252
|
-
return;
|
|
1253
|
-
}
|
|
1254
|
-
if (matches.length > 1) {
|
|
1255
|
-
failure = {
|
|
1256
|
-
reason: "duplicate-binding",
|
|
1257
|
-
dataId,
|
|
1258
|
-
label,
|
|
1259
|
-
property,
|
|
1260
|
-
count: matches.length
|
|
1261
|
-
};
|
|
1262
|
-
return;
|
|
1263
|
-
}
|
|
1264
|
-
const propertyBinding = matches[0];
|
|
1265
|
-
const prop = propertyBinding.property;
|
|
1266
|
-
if (RESERVED_BINDING_PROPERTIES.includes(prop)) {
|
|
1267
|
-
failure = {
|
|
1268
|
-
reason: "reserved-property",
|
|
1269
|
-
dataId,
|
|
1270
|
-
property: prop
|
|
1271
|
-
};
|
|
1272
|
-
return;
|
|
1273
|
-
}
|
|
1274
|
-
const unset = value === void 0;
|
|
1275
|
-
if (unset && propertyBinding.required) {
|
|
1276
|
-
failure = {
|
|
1277
|
-
reason: "required-property",
|
|
1278
|
-
dataId,
|
|
1279
|
-
property: prop
|
|
1280
|
-
};
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
switch (prop) {
|
|
1284
|
-
case BINDING_PROP.INNER_TEXT:
|
|
1285
|
-
collect(editInnerText(wrapped, path.node, unset ? "" : String(value)), () => ({
|
|
1286
|
-
reason: "parse-error",
|
|
1287
|
-
error: /* @__PURE__ */ new Error(`could not update "${prop}"`)
|
|
1288
|
-
}));
|
|
1289
|
-
break;
|
|
1290
|
-
case BINDING_PROP.INNER_HTML:
|
|
1291
|
-
collect(propertyBinding.type === "richtext" ? editRichtext(path.node, unset ? "" : String(value)) : editInnerHTML(path.node, unset ? "" : String(value)), () => ({
|
|
1292
|
-
reason: "parse-error",
|
|
1293
|
-
error: /* @__PURE__ */ new Error(`could not update "${prop}"`)
|
|
1294
|
-
}));
|
|
1295
|
-
break;
|
|
1296
|
-
case BINDING_PROP.CHILDREN:
|
|
1297
|
-
if (unset) {
|
|
1298
|
-
failure = {
|
|
1299
|
-
reason: "unsupported-syntax",
|
|
1300
|
-
dataId,
|
|
1301
|
-
property: prop
|
|
1302
|
-
};
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1305
|
-
collect(editChildrenSource(wrapped, path.node, value, options), () => ({
|
|
1306
|
-
reason: "parse-error",
|
|
1307
|
-
error: /* @__PURE__ */ new Error("Unsupported or stale children edit; source was preserved")
|
|
1308
|
-
}));
|
|
1309
|
-
break;
|
|
1310
|
-
default: {
|
|
1311
|
-
const attribute = findAttribute(opening, prop);
|
|
1312
|
-
if (unset) {
|
|
1313
|
-
collect(attribute ? removeAttribute(wrapped, attribute) : [], () => ({
|
|
1314
|
-
reason: "parse-error",
|
|
1315
|
-
error: /* @__PURE__ */ new Error(`could not remove "${prop}"`)
|
|
1316
|
-
}));
|
|
1317
|
-
break;
|
|
1318
|
-
}
|
|
1319
|
-
if (!attribute) {
|
|
1320
|
-
collect(value === "" ? [] : addAttribute(wrapped, opening, prop, value, propertyBinding.type), () => ({
|
|
1321
|
-
reason: "attribute-not-found",
|
|
1322
|
-
dataId,
|
|
1323
|
-
property: prop
|
|
1324
|
-
}));
|
|
1325
|
-
break;
|
|
1326
|
-
}
|
|
1327
|
-
if (attribute && propertyBinding.type !== "jsx" && !canEditAttributeValue(attribute, value, propertyBinding.type)) {
|
|
1328
|
-
failure = {
|
|
1329
|
-
reason: "unsupported-syntax",
|
|
1330
|
-
dataId,
|
|
1331
|
-
property: prop
|
|
1332
|
-
};
|
|
1333
|
-
break;
|
|
1334
|
-
}
|
|
1335
|
-
collect(propertyBinding.type === "jsx" ? editJsxAttribute(opening, prop, value) : editAttribute(opening, prop, value, propertyBinding.type), () => ({
|
|
1336
|
-
reason: "attribute-not-found",
|
|
1337
|
-
dataId,
|
|
1338
|
-
property: prop
|
|
1339
|
-
}));
|
|
1340
|
-
break;
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1258
|
+
edits.push(...result.edits);
|
|
1259
|
+
changed = true;
|
|
1343
1260
|
} });
|
|
1344
1261
|
if (!changed) return {
|
|
1345
1262
|
code,
|
|
@@ -1427,7 +1344,7 @@ const commaIn = (source, start, end) => {
|
|
|
1427
1344
|
};
|
|
1428
1345
|
const denseArraySource = (source) => {
|
|
1429
1346
|
const array = parseArrayExpression(source);
|
|
1430
|
-
if (!array || array.elements.some((node) => !
|
|
1347
|
+
if (!array || array.elements.some((node) => !isExpression(node) || node.extra?.parenthesized)) return null;
|
|
1431
1348
|
const elements = array.elements;
|
|
1432
1349
|
const commas = elements.slice(0, -1).map((node, index) => commaIn(source, node.end, elements[index + 1].start));
|
|
1433
1350
|
if (commas.some((comma) => comma === null)) return null;
|
|
@@ -1487,9 +1404,9 @@ const appendArraySource = (source, data, copies) => {
|
|
|
1487
1404
|
//#endregion
|
|
1488
1405
|
//#region src/utils/ast/items.ts
|
|
1489
1406
|
const elementsOf = (code) => parseArrayExpression(code)?.elements ?? null;
|
|
1490
|
-
const kindOf = (element) =>
|
|
1407
|
+
const kindOf = (element) => isObjectExpression(element) ? "object" : "primitive";
|
|
1491
1408
|
const parseItems = (code) => {
|
|
1492
|
-
return elementsOf(code)?.flatMap((node, index) =>
|
|
1409
|
+
return elementsOf(code)?.flatMap((node, index) => isExpression(node) ? [{
|
|
1493
1410
|
index,
|
|
1494
1411
|
kind: kindOf(node),
|
|
1495
1412
|
node
|
|
@@ -1505,23 +1422,23 @@ const toTemplateRaw = (value) => {
|
|
|
1505
1422
|
const buildPropertyValue = (value, declaredType, renderLeaf, current) => {
|
|
1506
1423
|
if (renderLeaf?.property === BINDING_PROP.INNER_HTML) {
|
|
1507
1424
|
const raw = String(value);
|
|
1508
|
-
return
|
|
1425
|
+
return templateLiteral([templateElement({
|
|
1509
1426
|
raw: toTemplateRaw(raw),
|
|
1510
1427
|
cooked: raw
|
|
1511
1428
|
}, true)], []);
|
|
1512
1429
|
}
|
|
1513
|
-
if (renderLeaf?.type === "jsx" ||
|
|
1430
|
+
if (renderLeaf?.type === "jsx" || isJSXElement(current) || isJSXFragment(current)) {
|
|
1514
1431
|
const trimmed = String(value).trim();
|
|
1515
|
-
if (!trimmed.startsWith("<")) return
|
|
1432
|
+
if (!trimmed.startsWith("<")) return stringLiteral(trimmed);
|
|
1516
1433
|
try {
|
|
1517
|
-
return
|
|
1434
|
+
return parseExpression(trimmed, { plugins: ["jsx", "typescript"] });
|
|
1518
1435
|
} catch {
|
|
1519
1436
|
return;
|
|
1520
1437
|
}
|
|
1521
1438
|
}
|
|
1522
1439
|
if (declaredType === "array" || declaredType === "object") {
|
|
1523
1440
|
if (typeof value === "string") try {
|
|
1524
|
-
return
|
|
1441
|
+
return parseExpression(value, { plugins: ["jsx", "typescript"] });
|
|
1525
1442
|
} catch {
|
|
1526
1443
|
return;
|
|
1527
1444
|
}
|
|
@@ -1533,13 +1450,13 @@ const buildPropertyValue = (value, declaredType, renderLeaf, current) => {
|
|
|
1533
1450
|
const updateArrayItemProperty = (code, index, key, value, render) => {
|
|
1534
1451
|
const elements = elementsOf(code);
|
|
1535
1452
|
const element = elements?.[index];
|
|
1536
|
-
if (!elements || !
|
|
1537
|
-
const target = element.properties.find((property) =>
|
|
1453
|
+
if (!elements || !isObjectExpression(element)) return null;
|
|
1454
|
+
const target = element.properties.find((property) => isObjectProperty(property) && isIdentifier(property.key) && property.key.name === key);
|
|
1538
1455
|
if (!target) return null;
|
|
1539
1456
|
const declaredType = extractObjectProperties(element)[key]?.type ?? "string";
|
|
1540
1457
|
const nextValue = buildPropertyValue(value, declaredType, resolveRenderLeaf(render, key), target.value);
|
|
1541
1458
|
if (!nextValue) return null;
|
|
1542
|
-
let serialized = typeof value === "string" && (declaredType === "array" || declaredType === "object" ||
|
|
1459
|
+
let serialized = typeof value === "string" && (declaredType === "array" || declaredType === "object" || isJSXElement(nextValue) || isJSXFragment(nextValue)) ? value.trim() : generateCode(nextValue);
|
|
1543
1460
|
if (nextValue.trailingComments?.some((comment) => comment.type === "CommentLine")) serialized += "\n";
|
|
1544
1461
|
const content = target.shorthand ? `${key}: ${serialized}` : serialized;
|
|
1545
1462
|
return applyEdits(code, [{
|
|
@@ -1551,7 +1468,7 @@ const updateArrayItemProperty = (code, index, key, value, render) => {
|
|
|
1551
1468
|
const updateArrayItemValue = (code, index, value) => {
|
|
1552
1469
|
const elements = elementsOf(code);
|
|
1553
1470
|
const element = elements?.[index];
|
|
1554
|
-
if (!elements || !
|
|
1471
|
+
if (!elements || !isExpression(element)) return null;
|
|
1555
1472
|
const nextValue = createNodeFromValue(extractNodeValue(element).type, parseValue(value));
|
|
1556
1473
|
if (!nextValue) return null;
|
|
1557
1474
|
return applyEdits(code, [{
|
|
@@ -1592,25 +1509,25 @@ const copyItem = (code, element, generateId, usedIds) => {
|
|
|
1592
1509
|
usedIds.add(id);
|
|
1593
1510
|
return JSON.stringify(id);
|
|
1594
1511
|
};
|
|
1595
|
-
|
|
1596
|
-
if (!
|
|
1597
|
-
const ids = node.attributes.filter((attr) =>
|
|
1512
|
+
traverseFast(element, (node) => {
|
|
1513
|
+
if (!isJSXOpeningElement(node)) return;
|
|
1514
|
+
const ids = node.attributes.filter((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name, { name: "data-id" }));
|
|
1598
1515
|
const attr = ids[0];
|
|
1599
|
-
if (ids.length > 1 || attr && (!
|
|
1516
|
+
if (ids.length > 1 || attr && (!isStringLiteral(attr.value) || node.attributes.slice(node.attributes.indexOf(attr) + 1).some((a) => isJSXSpreadAttribute(a)))) {
|
|
1600
1517
|
unsupported = true;
|
|
1601
1518
|
return;
|
|
1602
1519
|
}
|
|
1603
|
-
if (attr &&
|
|
1520
|
+
if (attr && isStringLiteral(attr.value)) edits.push({
|
|
1604
1521
|
start: attr.value.start,
|
|
1605
1522
|
end: attr.value.end,
|
|
1606
1523
|
content: reserveId(generateId())
|
|
1607
1524
|
});
|
|
1608
1525
|
});
|
|
1609
|
-
if (
|
|
1610
|
-
const keys = element.properties.filter((prop) =>
|
|
1526
|
+
if (isObjectExpression(element)) {
|
|
1527
|
+
const keys = element.properties.filter((prop) => isObjectProperty(prop) && !prop.computed && (isIdentifier(prop.key, { name: "key" }) || isStringLiteral(prop.key, { value: "key" })));
|
|
1611
1528
|
const key = keys[0];
|
|
1612
|
-
if (keys.length > 1 || key && (!
|
|
1613
|
-
if (key &&
|
|
1529
|
+
if (keys.length > 1 || key && (!isStringLiteral(key.value) || element.properties.slice(element.properties.indexOf(key) + 1).some((prop) => isSpreadElement(prop) || "computed" in prop && prop.computed))) return null;
|
|
1530
|
+
if (key && isStringLiteral(key.value)) edits.push({
|
|
1614
1531
|
start: key.value.start,
|
|
1615
1532
|
end: key.value.end,
|
|
1616
1533
|
content: reserveId(`${key.value.value}-${generateId()}`)
|
|
@@ -1627,9 +1544,9 @@ const duplicateArrayItems = (code, indices, generateId = () => nanoid(6)) => {
|
|
|
1627
1544
|
const data = denseArraySource(code);
|
|
1628
1545
|
if (!data || !indices.size || !validArrayIndices(indices, data.elements.length)) return null;
|
|
1629
1546
|
const usedIds = /* @__PURE__ */ new Set();
|
|
1630
|
-
|
|
1631
|
-
if (
|
|
1632
|
-
else if (
|
|
1547
|
+
traverseFast(data.array, (node) => {
|
|
1548
|
+
if (isJSXAttribute(node) && isJSXIdentifier(node.name, { name: "data-id" }) && isStringLiteral(node.value)) usedIds.add(node.value.value);
|
|
1549
|
+
else if (isObjectProperty(node) && !node.computed && (isIdentifier(node.key, { name: "key" }) || isStringLiteral(node.key, { value: "key" })) && isStringLiteral(node.value)) usedIds.add(node.value.value);
|
|
1633
1550
|
});
|
|
1634
1551
|
const copies = [...indices].sort((a, b) => a - b).map((index) => copyItem(code, data.elements[index], generateId, usedIds));
|
|
1635
1552
|
return copies.every((copy) => copy !== null) ? appendArraySource(code, data, copies) : null;
|
|
@@ -1639,6 +1556,6 @@ const appendArrayItem = (code, kind, generateId = () => nanoid(6)) => {
|
|
|
1639
1556
|
return index < 0 ? null : duplicateArrayItems(code, /* @__PURE__ */ new Set([index]), generateId);
|
|
1640
1557
|
};
|
|
1641
1558
|
//#endregion
|
|
1642
|
-
export { extractNodeValue as A,
|
|
1559
|
+
export { extractNodeValue as A, getStructuredValue as C, readNodeBindings as D, parseBindingExpression as E, parseArrayExpression as M, parseValue as N, resolveBindings as O, unwrapExpression as P, getRegistryBindings as S, parseBinding as T, clearExtractCache as _, parseItems as a, getCurrentValue as b, updateArrayItemValue as c, update as d, updateAll as f, moveSelectedIndices as g, getChildrenSignatures as h, moveArrayItems as i, extractObjectProperties as j, canLosslesslyEvaluateSource as k, canStructurallyEditArray as l, createNodeFromValue as m, duplicateArrayItems as n, removeArrayItems as o, arrayExpressionToCode as p, moveArrayItem as r, updateArrayItemProperty as s, appendArrayItem as t, bulkUpdate as u, extract as v, isComponentTagName as w, getKeyBindings as x, findEditableChildren as y };
|
|
1643
1560
|
|
|
1644
|
-
//# sourceMappingURL=items-
|
|
1561
|
+
//# sourceMappingURL=items-BXXtMUNI.js.map
|