@jbpark/live-editor 4.6.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/{boundary-BLB80tyw.js → boundary-6_nTsWxP.js} +2 -2
  4. package/dist/{boundary-BLB80tyw.js.map → boundary-6_nTsWxP.js.map} +1 -1
  5. package/dist/{compile-Dxas-D05.js → compile-DwOyWrmI.js} +8 -7
  6. package/dist/compile-DwOyWrmI.js.map +1 -0
  7. package/dist/constants-D-XKuEY2.js +58 -0
  8. package/dist/constants-D-XKuEY2.js.map +1 -0
  9. package/dist/{context-B8MzP7_p.js → context-DDR1xVKo.js} +3 -3
  10. package/dist/{context-B8MzP7_p.js.map → context-DDR1xVKo.js.map} +1 -1
  11. package/dist/{core-Bgfek364.js → core-CKazr4tT.js} +2 -2
  12. package/dist/core-CKazr4tT.js.map +1 -0
  13. package/dist/{detect-typescript-Dr_oLniM.js → detect-typescript-CoAO-QUJ.js} +2 -2
  14. package/dist/{detect-typescript-Dr_oLniM.js.map → detect-typescript-CoAO-QUJ.js.map} +1 -1
  15. package/dist/dnd/index.d.ts +2 -2
  16. package/dist/dnd/index.js +2 -2
  17. package/dist/dnd-BlC1gqUy.js +4446 -0
  18. package/dist/dnd-BlC1gqUy.js.map +1 -0
  19. package/dist/document-BQhb7YR8.d.ts +17 -0
  20. package/dist/document-DcwIEHRV.js +34077 -0
  21. package/dist/document-DcwIEHRV.js.map +1 -0
  22. package/dist/editor/index.js +2 -2
  23. package/dist/{editor-CMElfHer.js → editor-Bty5XzpV.js} +2 -2
  24. package/dist/{editor-CMElfHer.js.map → editor-Bty5XzpV.js.map} +1 -1
  25. package/dist/error/index.d.ts +1 -1
  26. package/dist/error/index.js +2 -2
  27. package/dist/{error-CN_GCnXB.js → error-DyYx2NQ2.js} +17 -31
  28. package/dist/error-DyYx2NQ2.js.map +1 -0
  29. package/dist/{index-C69Lv-jR.d.ts → index-0VB5C3Jk.d.ts} +28 -50
  30. package/dist/{index-DpDU1IAw.d.ts → index-92L7F440.d.ts} +2 -2
  31. package/dist/index-C8h8TcIl.d.ts +15 -0
  32. package/dist/{index-DQkL37eL.d.ts → index-Cl79M7ZJ.d.ts} +6 -4
  33. package/dist/{index-CRwEhJ7w.d.ts → index-kKUjo9lr.d.ts} +2 -2
  34. package/dist/{index-DrWtSKXu.d.ts → index-tAiuHZsC.d.ts} +2 -2
  35. package/dist/index.d.ts +9 -9
  36. package/dist/index.js +6 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/{messages-CSrMI4Rm.js → messages-Bt5WXKTE.js} +5 -2
  39. package/dist/messages-Bt5WXKTE.js.map +1 -0
  40. package/dist/{messages-IBPs4TkZ.d.ts → messages-Yb3b7YJt.d.ts} +5 -2
  41. package/dist/preview/index.d.ts +1 -1
  42. package/dist/preview/index.js +2 -2
  43. package/dist/{preview-CtyG5UbH.js → preview-DC0pyOdu.js} +4 -4
  44. package/dist/preview-DC0pyOdu.js.map +1 -0
  45. package/dist/provider/index.d.ts +2 -2
  46. package/dist/provider/index.js +2 -2
  47. package/dist/{sections-BYWOBISr.js → sections-4uirsXRU.js} +4 -7
  48. package/dist/sections-4uirsXRU.js.map +1 -0
  49. package/dist/style.css +776 -346
  50. package/dist/{validate-DB59Z_Nx.d.ts → types-Czps1Txy.d.ts} +12 -28
  51. package/dist/update-2PJbwoS8.d.ts +68 -0
  52. package/dist/{items-B6OXxcLG.js → update-DNInQSM7.js} +261 -512
  53. package/dist/update-DNInQSM7.js.map +1 -0
  54. package/dist/{use-dynamic-tailwind-BP1toJkW.js → use-dynamic-tailwind-CSYKXDmX.js} +301 -273
  55. package/dist/use-dynamic-tailwind-CSYKXDmX.js.map +1 -0
  56. package/dist/utils/ast/index.d.ts +47 -4
  57. package/dist/utils/ast/index.js +15 -77
  58. package/dist/utils/ast/index.js.map +1 -1
  59. package/dist/utils/index.d.ts +13 -32
  60. package/dist/utils/index.js +4 -26
  61. package/dist/validate-CZz30Pnb.js +122 -0
  62. package/dist/validate-CZz30Pnb.js.map +1 -0
  63. package/dist/validate-CiA1LF6S.d.ts +33 -0
  64. package/package.json +13 -15
  65. package/dist/compile-Dxas-D05.js.map +0 -1
  66. package/dist/constants-DU17Tdwo.js +0 -1459
  67. package/dist/constants-DU17Tdwo.js.map +0 -1
  68. package/dist/core-Bgfek364.js.map +0 -1
  69. package/dist/dnd-UoJILA75.js +0 -2756
  70. package/dist/dnd-UoJILA75.js.map +0 -1
  71. package/dist/document-CGbe6bSV.js +0 -38667
  72. package/dist/document-CGbe6bSV.js.map +0 -1
  73. package/dist/document-Ct4jW78J.d.ts +0 -1553
  74. package/dist/error-CN_GCnXB.js.map +0 -1
  75. package/dist/index-DKYUxi-E.d.ts +0 -227
  76. package/dist/items-B6OXxcLG.js.map +0 -1
  77. package/dist/messages-CSrMI4Rm.js.map +0 -1
  78. package/dist/preview-CtyG5UbH.js.map +0 -1
  79. package/dist/sections-BYWOBISr.js.map +0 -1
  80. package/dist/use-dynamic-tailwind-BP1toJkW.js.map +0 -1
  81. package/dist/utils/index.js.map +0 -1
  82. package/dist/validate-iLo8IONY.js +0 -64
  83. package/dist/validate-iLo8IONY.js.map +0 -1
@@ -1,11 +1,9 @@
1
- import { C as require_lib, S as require_lib$1, _ as generateCode, b as getJSXTagName, d as traverse, g as attrValue, v as unwrap, w as __toESM, x as nanoid, y as wrap } from "./document-CGbe6bSV.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";
1
+ import { $ as jsxOpeningFragment, A as isJSXText, B as isTSSatisfiesExpression, C as isJSXElement, D as isJSXIdentifier, E as isJSXFragment, F as isParenthesizedExpression, G as jsxClosingElement, H as isTemplateLiteral, J as jsxExpressionContainer, K as jsxClosingFragment, L as isStringLiteral, M as isNumericLiteral, N as isObjectExpression, O as isJSXOpeningElement, P as isObjectProperty, Q as jsxOpeningElement, R as isTSAsExpression, S as isJSXAttribute, T as isJSXExpressionContainer, U as isUnaryExpression, V as isTSTypeAssertion, W as jsxAttribute, X as jsxIdentifier, Y as jsxFragment, Z as jsxMemberExpression, _ as identifier, at as stringLiteral, c as traverse, ct as traverseFast, d as applyEdits, dt as parseExpression, et as jsxText, f as getJSXTagName, g as booleanLiteral, h as arrayExpression, it as objectProperty, j as isNullLiteral, k as isJSXSpreadAttribute, lt as unaryExpression, m as generate, nt as numericLiteral, p as nanoid, q as jsxElement, rt as objectExpression, tt as nullLiteral, ut as parse, v as isArrayExpression, w as isJSXEmptyExpression, x as isIdentifier, y as isBooleanLiteral, z as isTSNonNullExpression } from "./document-DcwIEHRV.js";
2
+ import { n as CONFIG, o as REGEX, r as DATA_ATTR, s as RESERVED_BINDING_PROPERTIES, t as BINDING_PROP } from "./constants-D-XKuEY2.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",
@@ -16,9 +14,40 @@ const BINDING_TYPES = [
16
14
  "jsx",
17
15
  "richtext",
18
16
  "date",
19
- "url"
17
+ "url",
18
+ "email",
19
+ "tel",
20
+ "time",
21
+ "datetime"
20
22
  ];
21
23
  //#endregion
24
+ //#region src/utils/ast/helpers.ts
25
+ const wrap = (code) => {
26
+ return `<>${code}</>`;
27
+ };
28
+ const unwrap = (generated) => {
29
+ return generated.replace(/^<>\s*/g, "").replace(/\s*<\/>\s*;?\s*$/g, "").trim();
30
+ };
31
+ const attrValue = ({ value, isStringLiteral }) => {
32
+ if (value === null) return null;
33
+ if (isStringLiteral) return stringLiteral(value);
34
+ const trimmed = value.trim();
35
+ if (REGEX.NUMBER.test(trimmed)) return jsxExpressionContainer(numericLiteral(parseFloat(trimmed)));
36
+ if (REGEX.BOOLEAN_OR_NULL.test(trimmed)) {
37
+ const expr = parseExpression(trimmed, { plugins: ["jsx", "typescript"] });
38
+ return jsxExpressionContainer(expr);
39
+ }
40
+ try {
41
+ const expr = parseExpression(trimmed, { plugins: ["jsx", "typescript"] });
42
+ return jsxExpressionContainer(expr);
43
+ } catch {
44
+ return stringLiteral(trimmed);
45
+ }
46
+ };
47
+ const generateCode = (node) => {
48
+ return generate(node, { jsescOption: { minimal: true } }).code;
49
+ };
50
+ //#endregion
22
51
  //#region src/utils/ast/value.ts
23
52
  const dedent = (str) => {
24
53
  const lines = str.replace(/^\n/, "").replace(/\n\s*$/, "").split("\n");
@@ -31,44 +60,44 @@ const dedent = (str) => {
31
60
  };
32
61
  const unwrapExpression = (node) => {
33
62
  let current = node;
34
- while (import_lib$1.isTSAsExpression(current) || import_lib$1.isTSSatisfiesExpression(current) || import_lib$1.isTSNonNullExpression(current) || import_lib$1.isTSTypeAssertion(current) || import_lib$1.isParenthesizedExpression(current)) current = current.expression;
63
+ while (isTSAsExpression(current) || isTSSatisfiesExpression(current) || isTSNonNullExpression(current) || isTSTypeAssertion(current) || isParenthesizedExpression(current)) current = current.expression;
35
64
  return current;
36
65
  };
37
66
  const isLosslesslyEvaluable = (node) => {
38
67
  const value = unwrapExpression(node);
39
- if (import_lib$1.isStringLiteral(value) || import_lib$1.isNumericLiteral(value) || import_lib$1.isBooleanLiteral(value) || import_lib$1.isNullLiteral(value)) return true;
40
- if (import_lib$1.isUnaryExpression(value) && value.operator === "-" && import_lib$1.isNumericLiteral(value.argument)) return true;
41
- if (import_lib$1.isTemplateLiteral(value)) return value.expressions.length === 0;
42
- if (import_lib$1.isArrayExpression(value)) return value.elements.every((element) => element !== null && isLosslesslyEvaluable(element));
43
- if (import_lib$1.isObjectExpression(value)) return value.properties.every((property) => import_lib$1.isObjectProperty(property) && !property.computed && (import_lib$1.isIdentifier(property.key) || import_lib$1.isStringLiteral(property.key) || import_lib$1.isNumericLiteral(property.key)) && isLosslesslyEvaluable(property.value));
68
+ if (isStringLiteral(value) || isNumericLiteral(value) || isBooleanLiteral(value) || isNullLiteral(value)) return true;
69
+ if (isUnaryExpression(value) && value.operator === "-" && isNumericLiteral(value.argument)) return true;
70
+ if (isTemplateLiteral(value)) return value.expressions.length === 0;
71
+ if (isArrayExpression(value)) return value.elements.every((element) => element !== null && isLosslesslyEvaluable(element));
72
+ 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
73
  return false;
45
74
  };
46
75
  const canLosslesslyEvaluateSource = (source) => {
47
76
  try {
48
- return isLosslesslyEvaluable((0, import_lib.parseExpression)(source, { plugins: ["jsx", "typescript"] }));
77
+ return isLosslesslyEvaluable(parseExpression(source, { plugins: ["jsx", "typescript"] }));
49
78
  } catch {
50
79
  return false;
51
80
  }
52
81
  };
53
82
  const evaluateLiteral = (rawNode) => {
54
83
  const node = unwrapExpression(rawNode);
55
- if (import_lib$1.isStringLiteral(node)) return node.value;
56
- if (import_lib$1.isNumericLiteral(node)) return node.value;
57
- if (import_lib$1.isBooleanLiteral(node)) return node.value;
58
- if (import_lib$1.isNullLiteral(node)) return null;
59
- if (import_lib$1.isIdentifier(node) && node.name === "undefined") return;
60
- if (import_lib$1.isUnaryExpression(node) && node.operator === "-" && import_lib$1.isNumericLiteral(node.argument)) return -node.argument.value;
61
- if (import_lib$1.isTemplateLiteral(node) && node.expressions.length === 0) return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? "";
62
- if (import_lib$1.isJSXElement(node) || import_lib$1.isJSXFragment(node)) return generateCode(node);
63
- if (import_lib$1.isArrayExpression(node)) return node.elements.map((element) => element ? evaluateLiteral(element) : null);
64
- if (import_lib$1.isObjectExpression(node)) {
84
+ if (isStringLiteral(node)) return node.value;
85
+ if (isNumericLiteral(node)) return node.value;
86
+ if (isBooleanLiteral(node)) return node.value;
87
+ if (isNullLiteral(node)) return null;
88
+ if (isIdentifier(node) && node.name === "undefined") return;
89
+ if (isUnaryExpression(node) && node.operator === "-" && isNumericLiteral(node.argument)) return -node.argument.value;
90
+ if (isTemplateLiteral(node) && node.expressions.length === 0) return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? "";
91
+ if (isJSXElement(node) || isJSXFragment(node)) return generateCode(node);
92
+ if (isArrayExpression(node)) return node.elements.map((element) => element ? evaluateLiteral(element) : null);
93
+ if (isObjectExpression(node)) {
65
94
  const result = {};
66
95
  for (const prop of node.properties) {
67
- if (!import_lib$1.isObjectProperty(prop)) continue;
96
+ if (!isObjectProperty(prop)) continue;
68
97
  let key = null;
69
- if (import_lib$1.isIdentifier(prop.key)) key = prop.key.name;
70
- else if (import_lib$1.isStringLiteral(prop.key)) key = prop.key.value;
71
- else if (import_lib$1.isNumericLiteral(prop.key)) key = String(prop.key.value);
98
+ if (isIdentifier(prop.key)) key = prop.key.name;
99
+ else if (isStringLiteral(prop.key)) key = prop.key.value;
100
+ else if (isNumericLiteral(prop.key)) key = String(prop.key.value);
72
101
  if (key === null) continue;
73
102
  result[key] = evaluateLiteral(prop.value);
74
103
  }
@@ -88,31 +117,31 @@ const parseValue = (value) => {
88
117
  }
89
118
  if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]")) {
90
119
  try {
91
- const ast = (0, import_lib.parseExpression)(trimmed, { plugins: ["jsx", "typescript"] });
92
- if (import_lib$1.isObjectExpression(ast) || import_lib$1.isArrayExpression(ast)) return evaluateLiteral(ast);
120
+ const ast = parseExpression(trimmed, { plugins: ["jsx", "typescript"] });
121
+ if (isObjectExpression(ast) || isArrayExpression(ast)) return evaluateLiteral(ast);
93
122
  } catch {}
94
123
  return value;
95
124
  }
96
125
  return value;
97
126
  };
98
127
  const extractNodeValue = (node) => {
99
- if (import_lib$1.isBooleanLiteral(node)) return {
128
+ if (isBooleanLiteral(node)) return {
100
129
  type: "boolean",
101
130
  value: node.value
102
131
  };
103
- if (import_lib$1.isNumericLiteral(node)) return {
132
+ if (isNumericLiteral(node)) return {
104
133
  type: "number",
105
134
  value: node.value
106
135
  };
107
- if (import_lib$1.isUnaryExpression(node) && node.operator === "-" && import_lib$1.isNumericLiteral(node.argument)) return {
136
+ if (isUnaryExpression(node) && node.operator === "-" && isNumericLiteral(node.argument)) return {
108
137
  type: "number",
109
138
  value: -node.argument.value
110
139
  };
111
- if (import_lib$1.isStringLiteral(node)) return {
140
+ if (isStringLiteral(node)) return {
112
141
  type: "string",
113
142
  value: node.value
114
143
  };
115
- if (import_lib$1.isTemplateLiteral(node)) {
144
+ if (isTemplateLiteral(node)) {
116
145
  if (node.expressions.length === 0 && node.quasis.length === 1) return {
117
146
  type: "string",
118
147
  value: dedent(node.quasis[0].value.cooked ?? node.quasis[0].value.raw)
@@ -122,19 +151,19 @@ const extractNodeValue = (node) => {
122
151
  value: generateCode(node)
123
152
  };
124
153
  }
125
- if (import_lib$1.isNullLiteral(node)) return {
154
+ if (isNullLiteral(node)) return {
126
155
  type: "null",
127
156
  value: null
128
157
  };
129
- if (import_lib$1.isArrayExpression(node)) return {
158
+ if (isArrayExpression(node)) return {
130
159
  type: "array",
131
160
  value: generateCode(node)
132
161
  };
133
- if (import_lib$1.isObjectExpression(node)) return {
162
+ if (isObjectExpression(node)) return {
134
163
  type: "object",
135
164
  value: generateCode(node)
136
165
  };
137
- if (import_lib$1.isJSXElement(node) || import_lib$1.isJSXFragment(node)) return {
166
+ if (isJSXElement(node) || isJSXFragment(node)) return {
138
167
  type: "string",
139
168
  value: generateCode(node)
140
169
  };
@@ -145,8 +174,8 @@ const extractNodeValue = (node) => {
145
174
  };
146
175
  const parseArrayExpression = (value) => {
147
176
  try {
148
- const ast = unwrapExpression((0, import_lib.parseExpression)(value, { plugins: ["jsx", "typescript"] }));
149
- if (!import_lib$1.isArrayExpression(ast)) return null;
177
+ const ast = unwrapExpression(parseExpression(value, { plugins: ["jsx", "typescript"] }));
178
+ if (!isArrayExpression(ast)) return null;
150
179
  return ast;
151
180
  } catch (error) {
152
181
  console.error("❌ Array parsing error:", error);
@@ -156,9 +185,9 @@ const parseArrayExpression = (value) => {
156
185
  const extractObjectProperties = (element) => {
157
186
  const properties = {};
158
187
  element.properties.forEach((prop) => {
159
- if (import_lib$1.isObjectProperty(prop) && import_lib$1.isIdentifier(prop.key)) {
188
+ if (isObjectProperty(prop) && isIdentifier(prop.key)) {
160
189
  const key = prop.key.name;
161
- if (key === "children" || import_lib$1.isJSXElement(prop.value) || import_lib$1.isJSXFragment(prop.value)) return;
190
+ if (key === "children" || isJSXElement(prop.value) || isJSXFragment(prop.value)) return;
162
191
  const extracted = extractNodeValue(prop.value);
163
192
  properties[key] = {
164
193
  ...extracted,
@@ -171,6 +200,8 @@ const extractObjectProperties = (element) => {
171
200
  //#endregion
172
201
  //#region src/utils/ast/binding.ts
173
202
  const bindingTypeSchema = z.enum(BINDING_TYPES);
203
+ const countSchema = z.number().int().nonnegative();
204
+ const dateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2})?$/);
174
205
  const bindingOptionSchema = z.object({
175
206
  label: z.string(),
176
207
  value: z.string()
@@ -206,7 +237,16 @@ const KNOWN_BINDING_KEYS = /* @__PURE__ */ new Set([
206
237
  "min",
207
238
  "max",
208
239
  "pattern",
209
- "required"
240
+ "patternMessage",
241
+ "required",
242
+ "minLength",
243
+ "maxLength",
244
+ "step",
245
+ "minItems",
246
+ "maxItems",
247
+ "minDate",
248
+ "maxDate",
249
+ "protocols"
210
250
  ]);
211
251
  const isPlainObject = (value) => {
212
252
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -223,7 +263,16 @@ const sanitizeField = (raw) => {
223
263
  min: pick(z.number(), raw.min),
224
264
  max: pick(z.number(), raw.max),
225
265
  pattern: pick(z.string(), raw.pattern),
266
+ patternMessage: pick(z.string(), raw.patternMessage),
226
267
  required: pick(z.boolean(), raw.required),
268
+ minLength: pick(countSchema, raw.minLength),
269
+ maxLength: pick(countSchema, raw.maxLength),
270
+ step: pick(z.number().positive(), raw.step),
271
+ minItems: pick(countSchema, raw.minItems),
272
+ maxItems: pick(countSchema, raw.maxItems),
273
+ minDate: pick(dateSchema, raw.minDate),
274
+ maxDate: pick(dateSchema, raw.maxDate),
275
+ protocols: pick(z.array(z.string().min(1)), raw.protocols),
227
276
  meta: metaEntries.length > 0 ? Object.fromEntries(metaEntries) : void 0
228
277
  };
229
278
  return Object.fromEntries(Object.entries(field).filter(([, value]) => value !== void 0));
@@ -329,12 +378,12 @@ const getCurrentValue = (node, property) => {
329
378
  case BINDING_PROP.INNER_HTML: {
330
379
  const dsiAttr = node.attributes.find((a) => a.name === "dangerouslySetInnerHTML");
331
380
  if (dsiAttr?.value) try {
332
- const expr = (0, import_lib.parseExpression)(dsiAttr.value, { plugins: ["jsx", "typescript"] });
333
- if (import_lib$1.isObjectExpression(expr)) {
334
- const htmlProp = expr.properties.find((p) => import_lib$1.isObjectProperty(p) && import_lib$1.isIdentifier(p.key) && p.key.name === "__html");
381
+ const expr = parseExpression(dsiAttr.value, { plugins: ["jsx", "typescript"] });
382
+ if (isObjectExpression(expr)) {
383
+ const htmlProp = expr.properties.find((p) => isObjectProperty(p) && isIdentifier(p.key) && p.key.name === "__html");
335
384
  if (htmlProp) {
336
- if (import_lib$1.isStringLiteral(htmlProp.value)) return htmlProp.value.value;
337
- if (import_lib$1.isTemplateLiteral(htmlProp.value) && htmlProp.value.expressions.length === 0) return htmlProp.value.quasis[0]?.value.cooked ?? htmlProp.value.quasis[0]?.value.raw ?? "";
385
+ if (isStringLiteral(htmlProp.value)) return htmlProp.value.value;
386
+ if (isTemplateLiteral(htmlProp.value) && htmlProp.value.expressions.length === 0) return htmlProp.value.quasis[0]?.value.cooked ?? htmlProp.value.quasis[0]?.value.raw ?? "";
338
387
  }
339
388
  }
340
389
  } catch {}
@@ -347,7 +396,11 @@ const getCurrentValue = (node, property) => {
347
396
  const STRING_VALUED_TYPES = /* @__PURE__ */ new Set([
348
397
  "string",
349
398
  "url",
399
+ "email",
400
+ "tel",
350
401
  "date",
402
+ "time",
403
+ "datetime",
351
404
  "color",
352
405
  "jsx",
353
406
  "richtext"
@@ -383,15 +436,42 @@ const findEditableChildren = (node) => {
383
436
  return editableChildren;
384
437
  };
385
438
  //#endregion
439
+ //#region src/utils/selection.ts
440
+ const removeIndices = (items, indices) => {
441
+ return items.filter((_, index) => !indices.has(index));
442
+ };
443
+ /**
444
+ * Shifts every selected index up/down by one step as a block, preserving
445
+ * relative order — scattered selections stop moving individually once they
446
+ * hit an unselected neighbor, so the whole group slides together instead of
447
+ * items passing through each other.
448
+ */
449
+ const moveSelectedIndices = (items, indices, direction) => {
450
+ const next = [...items];
451
+ const nextIndices = new Set(indices);
452
+ const ordered = [...indices].sort((a, b) => direction === "up" ? a - b : b - a);
453
+ for (const index of ordered) {
454
+ const target = direction === "up" ? index - 1 : index + 1;
455
+ if (target < 0 || target >= next.length || nextIndices.has(target)) continue;
456
+ [next[index], next[target]] = [next[target], next[index]];
457
+ nextIndices.delete(index);
458
+ nextIndices.add(target);
459
+ }
460
+ return {
461
+ items: next,
462
+ indices: nextIndices
463
+ };
464
+ };
465
+ //#endregion
386
466
  //#region src/utils/ast/extract.ts
387
467
  const collectText = (children) => {
388
- return children.filter((c) => import_lib$1.isJSXText(c)).map((c) => c.value.trim()).filter((v) => v.length).join(" ");
468
+ return children.filter((c) => isJSXText(c)).map((c) => c.value.trim()).filter((v) => v.length).join(" ");
389
469
  };
390
470
  const parseJSXName = (tagName) => {
391
471
  const parts = tagName.split(".");
392
- if (parts.length === 1) return import_lib$1.jsxIdentifier(parts[0]);
393
- let expr = import_lib$1.jsxIdentifier(parts[0]);
394
- for (let i = 1; i < parts.length; i++) expr = import_lib$1.jsxMemberExpression(expr, import_lib$1.jsxIdentifier(parts[i]));
472
+ if (parts.length === 1) return jsxIdentifier(parts[0]);
473
+ let expr = jsxIdentifier(parts[0]);
474
+ for (let i = 1; i < parts.length; i++) expr = jsxMemberExpression(expr, jsxIdentifier(parts[i]));
395
475
  return expr;
396
476
  };
397
477
  const extractCache = createBoundedCache(CONFIG.CACHE_LIMIT);
@@ -415,19 +495,19 @@ const extractAttributes = (attributes, source) => {
415
495
  const allAttrs = [];
416
496
  const dataAttrs = [];
417
497
  for (const attr of attributes) {
418
- if (!import_lib$1.isJSXAttribute(attr) || !import_lib$1.isJSXIdentifier(attr.name)) continue;
498
+ if (!isJSXAttribute(attr) || !isJSXIdentifier(attr.name)) continue;
419
499
  const name = attr.name.name;
420
500
  let value = null;
421
- let isStringLiteral = false;
501
+ let isStringLiteral$1 = false;
422
502
  if (attr.value) {
423
- if (import_lib$1.isStringLiteral(attr.value)) {
503
+ if (isStringLiteral(attr.value)) {
424
504
  value = attr.value.value;
425
- isStringLiteral = true;
426
- } else if (import_lib$1.isJSXExpressionContainer(attr.value)) try {
505
+ isStringLiteral$1 = true;
506
+ } else if (isJSXExpressionContainer(attr.value)) try {
427
507
  const expression = attr.value.expression;
428
- const structural = import_lib$1.isArrayExpression(unwrapExpression(expression)) || import_lib$1.isObjectExpression(unwrapExpression(expression));
508
+ const structural = isArrayExpression(unwrapExpression(expression)) || isObjectExpression(unwrapExpression(expression));
429
509
  value = source && structural && expression.start != null && expression.end != null ? source.slice(expression.start, expression.end) : generateCode(expression);
430
- isStringLiteral = false;
510
+ isStringLiteral$1 = false;
431
511
  } catch {
432
512
  value = null;
433
513
  }
@@ -435,7 +515,7 @@ const extractAttributes = (attributes, source) => {
435
515
  const entry = {
436
516
  name,
437
517
  value,
438
- isStringLiteral
518
+ isStringLiteral: isStringLiteral$1
439
519
  };
440
520
  allAttrs.push(entry);
441
521
  if (name.startsWith("data-")) dataAttrs.push(entry);
@@ -447,7 +527,7 @@ const extractAttributes = (attributes, source) => {
447
527
  };
448
528
  const buildChildElements = (node) => {
449
529
  const childElements = [];
450
- if (node.textContent) childElements.push(import_lib$1.jsxText(node.textContent));
530
+ if (node.textContent) childElements.push(jsxText(node.textContent));
451
531
  node.children?.forEach((child) => {
452
532
  const childJSX = nodeToJSX(child);
453
533
  if (childJSX) childElements.push(childJSX);
@@ -458,22 +538,22 @@ const nodeToJSX = (node) => {
458
538
  try {
459
539
  if (node.isFragment) {
460
540
  const childElements = buildChildElements(node);
461
- return import_lib$1.jsxFragment(import_lib$1.jsxOpeningFragment(), import_lib$1.jsxClosingFragment(), childElements);
541
+ return jsxFragment(jsxOpeningFragment(), jsxClosingFragment(), childElements);
462
542
  }
463
543
  if (node.tagName === "div" && node.dataAttributes.some((attr) => attr.name === "data-item")) {
464
544
  if (node.children) return nodeToJSX(node.children[0]);
465
545
  return null;
466
546
  }
467
547
  const attributes = node.attributes.map((attr) => {
468
- const attrName = import_lib$1.jsxIdentifier(attr.name);
469
- if (!attr.value) return import_lib$1.jsxAttribute(attrName, null);
470
- return import_lib$1.jsxAttribute(attrName, attrValue(attr));
548
+ const attrName = jsxIdentifier(attr.name);
549
+ if (!attr.value) return jsxAttribute(attrName, null);
550
+ return jsxAttribute(attrName, attrValue(attr));
471
551
  });
472
552
  const elementName = parseJSXName(node.tagName);
473
- const openingElement = import_lib$1.jsxOpeningElement(elementName, attributes);
474
- const closingElement = import_lib$1.jsxClosingElement(elementName);
553
+ const openingElement = jsxOpeningElement(elementName, attributes);
554
+ const closingElement = jsxClosingElement(elementName);
475
555
  const children = buildChildElements(node);
476
- return import_lib$1.jsxElement(openingElement, closingElement, children, false);
556
+ return jsxElement(openingElement, closingElement, children);
477
557
  } catch (error) {
478
558
  console.error("❌ DataAttrNode to JSX conversion error:", error);
479
559
  return null;
@@ -503,11 +583,11 @@ const createFragmentNode = (textContent, children) => ({
503
583
  isFragment: true
504
584
  });
505
585
  const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, source, options) => {
506
- const jsxChildren = jsxElement.children.filter((child) => import_lib$1.isJSXElement(child) || import_lib$1.isJSXFragment(child));
586
+ const jsxChildren = jsxElement.children.filter((child) => isJSXElement(child) || isJSXFragment(child));
507
587
  if (!jsxChildren.length) return;
508
588
  const childrenNodes = [];
509
589
  jsxChildren.forEach((child) => {
510
- if (import_lib$1.isJSXElement(child)) {
590
+ if (isJSXElement(child)) {
511
591
  const childResults = extractFromNode(child, processedNodes, source, options);
512
592
  if (shouldWrap) {
513
593
  const wrapperNode = createWrapperNode(collectText(child.children), childResults);
@@ -516,11 +596,11 @@ const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, s
516
596
  if (dataId) wrapperNode.id = `child:${dataId}`;
517
597
  childrenNodes.push(wrapperNode);
518
598
  } else childrenNodes.push(...childResults);
519
- } else if (import_lib$1.isJSXFragment(child)) {
599
+ } else if (isJSXFragment(child)) {
520
600
  processedNodes?.add(child);
521
601
  const fragmentChildren = [];
522
602
  child.children.forEach((fragmentChild) => {
523
- if (import_lib$1.isJSXElement(fragmentChild)) {
603
+ if (isJSXElement(fragmentChild)) {
524
604
  const childResults = extractFromNode(fragmentChild, processedNodes, source, options);
525
605
  fragmentChildren.push(...childResults);
526
606
  }
@@ -535,26 +615,26 @@ const processChildrenBinding = (jsxElement, processedNodes, shouldWrap = true, s
535
615
  return childrenNodes.length ? childrenNodes : void 0;
536
616
  };
537
617
  const skipItemsChildren = (jsxElement, processedNodes, propertyName = "items") => {
538
- const itemsAttr = jsxElement.openingElement.attributes.find((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === propertyName);
539
- if (!itemsAttr || !import_lib$1.isJSXAttribute(itemsAttr)) return;
540
- if (itemsAttr.value && import_lib$1.isJSXExpressionContainer(itemsAttr.value) && import_lib$1.isArrayExpression(itemsAttr.value.expression)) itemsAttr.value.expression.elements.forEach((element) => {
541
- if (import_lib$1.isObjectExpression(element)) element.properties.forEach((prop) => {
542
- if (import_lib$1.isObjectProperty(prop) && import_lib$1.isIdentifier(prop.key) && import_lib$1.isJSXElement(prop.value)) markProcessedJSX(prop.value, processedNodes);
618
+ const itemsAttr = jsxElement.openingElement.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === propertyName);
619
+ if (!itemsAttr || !isJSXAttribute(itemsAttr)) return;
620
+ if (itemsAttr.value && isJSXExpressionContainer(itemsAttr.value) && isArrayExpression(itemsAttr.value.expression)) itemsAttr.value.expression.elements.forEach((element) => {
621
+ if (isObjectExpression(element)) element.properties.forEach((prop) => {
622
+ if (isObjectProperty(prop) && isIdentifier(prop.key) && isJSXElement(prop.value)) markProcessedJSX(prop.value, processedNodes);
543
623
  });
544
624
  });
545
625
  };
546
626
  const markProcessedJSX = (node, processedNodes) => {
547
- if (import_lib$1.isJSXElement(node) || import_lib$1.isJSXFragment(node)) {
627
+ if (isJSXElement(node) || isJSXFragment(node)) {
548
628
  processedNodes.add(node);
549
629
  node.children.forEach((child) => markProcessedJSX(child, processedNodes));
550
630
  return;
551
631
  }
552
- if (import_lib$1.isJSXExpressionContainer(node) || import_lib$1.isParenthesizedExpression(node)) markProcessedJSX(node.expression, processedNodes);
632
+ if (isJSXExpressionContainer(node) || isParenthesizedExpression(node)) markProcessedJSX(node.expression, processedNodes);
553
633
  };
554
634
  const getBindingExpression = (opening) => {
555
- for (const attr of opening.attributes) if (import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.BINDING && attr.value && import_lib$1.isJSXExpressionContainer(attr.value)) {
635
+ for (const attr of opening.attributes) if (isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.BINDING && attr.value && isJSXExpressionContainer(attr.value)) {
556
636
  const expression = unwrapExpression(attr.value.expression);
557
- if (import_lib$1.isArrayExpression(expression)) return expression;
637
+ if (isArrayExpression(expression)) return expression;
558
638
  }
559
639
  return null;
560
640
  };
@@ -583,7 +663,7 @@ const readNodeBindingInfo = (node, source, options) => {
583
663
  };
584
664
  const parseToNodes = (raw, options) => {
585
665
  const wrapped = wrap(raw);
586
- const ast = (0, import_lib.parse)(wrapped, {
666
+ const ast = parse(wrapped, {
587
667
  sourceType: "module",
588
668
  plugins: ["jsx", "typescript"],
589
669
  errorRecovery: true
@@ -648,106 +728,6 @@ function clearExtractCache() {
648
728
  }
649
729
  registerEditorCache(clearExtractCache);
650
730
  //#endregion
651
- //#region src/utils/selection.ts
652
- const removeIndices = (items, indices) => {
653
- return items.filter((_, index) => !indices.has(index));
654
- };
655
- /**
656
- * Shifts every selected index up/down by one step as a block, preserving
657
- * relative order — scattered selections stop moving individually once they
658
- * hit an unselected neighbor, so the whole group slides together instead of
659
- * items passing through each other.
660
- */
661
- const moveSelectedIndices = (items, indices, direction) => {
662
- const next = [...items];
663
- const nextIndices = new Set(indices);
664
- const ordered = [...indices].sort((a, b) => direction === "up" ? a - b : b - a);
665
- for (const index of ordered) {
666
- const target = direction === "up" ? index - 1 : index + 1;
667
- if (target < 0 || target >= next.length || nextIndices.has(target)) continue;
668
- [next[index], next[target]] = [next[target], next[index]];
669
- nextIndices.delete(index);
670
- nextIndices.add(target);
671
- }
672
- return {
673
- items: next,
674
- indices: nextIndices
675
- };
676
- };
677
- //#endregion
678
- //#region src/utils/ast/patch.ts
679
- const hasOnlyLayoutNewlines = (content) => {
680
- let index = 0;
681
- while (index < content.length) {
682
- const char = content[index];
683
- if (char === "`" || char === "<") return false;
684
- if (char === "\"" || char === "'") {
685
- const next = skipStringLiteral(content, index);
686
- if (next === -1) return false;
687
- index = next;
688
- continue;
689
- }
690
- if (char === "/") {
691
- const following = content[index + 1];
692
- if (following === "/") {
693
- const lineEnd = content.indexOf("\n", index + 2);
694
- index = lineEnd === -1 ? content.length : lineEnd;
695
- continue;
696
- }
697
- if (following === "*") {
698
- const commentEnd = content.indexOf("*/", index + 2);
699
- if (commentEnd === -1) return false;
700
- index = commentEnd + 2;
701
- continue;
702
- }
703
- return false;
704
- }
705
- index++;
706
- }
707
- return true;
708
- };
709
- const skipStringLiteral = (content, start) => {
710
- const quote = content[start];
711
- for (let index = start + 1; index < content.length; index++) {
712
- const char = content[index];
713
- if (char === "\\") {
714
- const escaped = content[index + 1];
715
- if (escaped === "\n" || escaped === "\r") return -1;
716
- index++;
717
- continue;
718
- }
719
- if (char === quote) return index + 1;
720
- if (char === "\n") return -1;
721
- }
722
- return -1;
723
- };
724
- const lineIndentAt = (source, offset) => {
725
- const lineStart = source.lastIndexOf("\n", offset - 1) + 1;
726
- return /^[ \t]*/.exec(source.slice(lineStart, offset))?.[0] ?? "";
727
- };
728
- const lineTerminatorOf = (source) => {
729
- return source.includes("\r\n") ? "\r\n" : "\n";
730
- };
731
- const applyEdits = (source, edits) => {
732
- if (edits.length === 0) return source;
733
- const ordered = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
734
- for (const edit of ordered) if (!Number.isInteger(edit.start) || !Number.isInteger(edit.end) || edit.start < 0 || edit.end > source.length || edit.start > edit.end) throw new Error(`Invalid source edit [${edit.start}, ${edit.end}) for a source of length ${source.length}`);
735
- for (let i = 1; i < ordered.length; i++) {
736
- const previous = ordered[i - 1];
737
- const current = ordered[i];
738
- if (current.start < previous.end) throw new Error(`Overlapping source edits: [${previous.start}, ${previous.end}) and [${current.start}, ${current.end})`);
739
- }
740
- let result = "";
741
- let cursor = 0;
742
- const terminator = lineTerminatorOf(source);
743
- for (const edit of ordered) {
744
- const content = edit.indent && edit.content.includes("\n") && hasOnlyLayoutNewlines(edit.content) ? edit.content.replace(/\n/g, `${terminator}${lineIndentAt(source, edit.start)}`) : edit.content;
745
- result += source.slice(cursor, edit.start) + content;
746
- cursor = edit.end;
747
- }
748
- return result + source.slice(cursor);
749
- };
750
- //#endregion
751
731
  //#region src/utils/ast/children.ts
752
732
  const modeledSignatures = (nodes) => nodes.map((node) => {
753
733
  const jsx = nodeToJSX(node);
@@ -760,7 +740,7 @@ const getChildrenSignatures = (nodes) => {
760
740
  };
761
741
  const indicesAreValid = (indices, count) => Array.isArray(indices) && new Set(indices).size === indices.length && indices.every((index) => Number.isInteger(index) && index >= 0 && index < count);
762
742
  const copySource = (source, usedIds) => {
763
- const node = (0, import_lib.parseExpression)(source, { plugins: ["jsx", "typescript"] });
743
+ const node = parseExpression(source, { plugins: ["jsx", "typescript"] });
764
744
  const edits = [];
765
745
  const newId = () => {
766
746
  let id = nanoid(12);
@@ -768,15 +748,15 @@ const copySource = (source, usedIds) => {
768
748
  usedIds.add(id);
769
749
  return id;
770
750
  };
771
- import_lib$1.traverseFast(node, (child) => {
772
- if (!import_lib$1.isJSXOpeningElement(child)) return;
773
- const ids = child.attributes.filter((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name, { name: "data-id" }));
751
+ traverseFast(node, (child) => {
752
+ if (!isJSXOpeningElement(child)) return;
753
+ const ids = child.attributes.filter((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name, { name: "data-id" }));
774
754
  if (ids.length > 1) throw new Error("Duplicate data-id attributes");
775
755
  const attr = ids[0];
776
- if (attr && child.attributes.slice(child.attributes.indexOf(attr) + 1).some((attribute) => import_lib$1.isJSXSpreadAttribute(attribute))) throw new Error("A spread may override the copied data-id");
756
+ 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");
777
757
  if (attr) {
778
758
  const value = attr.value;
779
- if (!import_lib$1.isStringLiteral(value) || value.start == null || value.end == null) throw new Error("Cannot copy a dynamic data-id");
759
+ if (!isStringLiteral(value) || value.start == null || value.end == null) throw new Error("Cannot copy a dynamic data-id");
780
760
  edits.push({
781
761
  start: value.start,
782
762
  end: value.end,
@@ -794,11 +774,29 @@ const copySource = (source, usedIds) => {
794
774
  });
795
775
  return applyEdits(source, edits);
796
776
  };
777
+ const insertChildren = (source, parent, last, copies) => {
778
+ const closing = parent.closingElement.start;
779
+ if (last?.start != null && last.end != null) {
780
+ const lineStart = source.lastIndexOf("\n", last.start - 1) + 1;
781
+ const indent = source.slice(lineStart, last.start);
782
+ const after = /^[ \t]*(\r?\n)/.exec(source.slice(last.end, closing));
783
+ if (after && /^[ \t]*$/.test(indent)) return {
784
+ start: last.end,
785
+ end: last.end,
786
+ content: copies.map((copy) => `${after[1]}${indent}${copy}`).join("")
787
+ };
788
+ }
789
+ return {
790
+ start: closing,
791
+ end: closing,
792
+ content: copies.join("")
793
+ };
794
+ };
797
795
  const editChildrenSource = (source, parent, input, options) => {
798
796
  try {
799
797
  if (!parent.closingElement || parent.start == null || parent.end == null) return null;
800
798
  const value = typeof input === "string" ? JSON.parse(input) : input;
801
- const children = parent.children.filter((child) => import_lib$1.isJSXElement(child) || import_lib$1.isJSXFragment(child));
799
+ const children = parent.children.filter((child) => isJSXElement(child) || isJSXFragment(child));
802
800
  const raw = children.map((child) => source.slice(child.start, child.end));
803
801
  const models = extract(source.slice(parent.start, parent.end), options)[0]?.children ?? [];
804
802
  if (models.length !== children.length) return null;
@@ -809,19 +807,12 @@ const editChildrenSource = (source, parent, input, options) => {
809
807
  end: child.end,
810
808
  content: next[index] ?? ""
811
809
  }));
812
- if (next.length > children.length) {
813
- const at = parent.closingElement.start;
814
- edits.push({
815
- start: at,
816
- end: at,
817
- content: next.slice(children.length).join("")
818
- });
819
- }
810
+ if (next.length > children.length) edits.push(insertChildren(source, parent, children.at(-1), next.slice(children.length)));
820
811
  return edits;
821
812
  };
822
813
  if (Array.isArray(value)) {
823
814
  const desired = modeledSignatures(value);
824
- const lossless = raw.every((text, index) => generateCode((0, import_lib.parseExpression)(text, { plugins: ["jsx", "typescript"] })) === signatures[index]);
815
+ const lossless = raw.every((text, index) => generateCode(parseExpression(text, { plugins: ["jsx", "typescript"] })) === signatures[index]);
825
816
  const consumed = /* @__PURE__ */ new Set();
826
817
  const next = desired.map((signature, position) => {
827
818
  const index = signatures.findIndex((candidate, i) => candidate === signature && !consumed.has(i) && (value[position].source === void 0 || value[position].source === raw[i]));
@@ -834,8 +825,8 @@ const editChildrenSource = (source, parent, input, options) => {
834
825
  });
835
826
  const countIds = (text) => {
836
827
  const counts = /* @__PURE__ */ new Map();
837
- import_lib$1.traverseFast((0, import_lib.parseExpression)(text, { plugins: ["jsx", "typescript"] }), (node) => {
838
- if (import_lib$1.isJSXAttribute(node) && import_lib$1.isJSXIdentifier(node.name, { name: "data-id" }) && import_lib$1.isStringLiteral(node.value)) counts.set(node.value.value, (counts.get(node.value.value) ?? 0) + 1);
828
+ traverseFast(parseExpression(text, { plugins: ["jsx", "typescript"] }), (node) => {
829
+ if (isJSXAttribute(node) && isJSXIdentifier(node.name, { name: "data-id" }) && isStringLiteral(node.value)) counts.set(node.value.value, (counts.get(node.value.value) ?? 0) + 1);
839
830
  });
840
831
  return counts;
841
832
  };
@@ -847,8 +838,8 @@ const editChildrenSource = (source, parent, input, options) => {
847
838
  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;
848
839
  const { action } = request;
849
840
  const usedIds = /* @__PURE__ */ new Set();
850
- import_lib$1.traverseFast(parent, (node) => {
851
- if (import_lib$1.isJSXAttribute(node) && import_lib$1.isJSXIdentifier(node.name, { name: "data-id" }) && import_lib$1.isStringLiteral(node.value)) usedIds.add(node.value.value);
841
+ traverseFast(parent, (node) => {
842
+ if (isJSXAttribute(node) && isJSXIdentifier(node.name, { name: "data-id" }) && isStringLiteral(node.value)) usedIds.add(node.value.value);
852
843
  });
853
844
  switch (action.type) {
854
845
  case "move": {
@@ -870,22 +861,12 @@ const editChildrenSource = (source, parent, input, options) => {
870
861
  }));
871
862
  case "duplicate": {
872
863
  if (!indicesAreValid(action.indices, raw.length)) return null;
873
- const content = [...action.indices].sort((a, b) => a - b).map((index) => copySource(raw[index], usedIds)).join("");
874
- const at = parent.closingElement.start;
875
- return [{
876
- start: at,
877
- end: at,
878
- content
879
- }];
864
+ const copies = [...action.indices].sort((a, b) => a - b).map((index) => copySource(raw[index], usedIds));
865
+ return [insertChildren(source, parent, children.at(-1), copies)];
880
866
  }
881
867
  case "append": {
882
- const content = copySource(raw[0] ?? "<div></div>", usedIds);
883
- const at = parent.closingElement.start;
884
- return [{
885
- start: at,
886
- end: at,
887
- content
888
- }];
868
+ const copy = copySource(raw[0] ?? "<div></div>", usedIds);
869
+ return [insertChildren(source, parent, children.at(-1), [copy])];
889
870
  }
890
871
  default: return null;
891
872
  }
@@ -897,10 +878,10 @@ const editChildrenSource = (source, parent, input, options) => {
897
878
  //#region src/utils/ast/value-expression.ts
898
879
  const createNodeFromValue = (type, value) => {
899
880
  switch (type) {
900
- case "boolean": return import_lib$1.booleanLiteral(value === true);
901
- case "number": return import_lib$1.numericLiteral(Number(value));
902
- case "string": return import_lib$1.stringLiteral(String(value));
903
- case "null": return import_lib$1.nullLiteral();
881
+ case "boolean": return booleanLiteral(value === true);
882
+ case "number": return numericLiteral(Number(value));
883
+ case "string": return stringLiteral(String(value));
884
+ case "null": return nullLiteral();
904
885
  case "array":
905
886
  case "object":
906
887
  case "unknown": return null;
@@ -908,26 +889,22 @@ const createNodeFromValue = (type, value) => {
908
889
  }
909
890
  };
910
891
  const valueToExpression = (value) => {
911
- if (typeof value === "string") return import_lib$1.stringLiteral(value);
912
- if (typeof value === "number") return value < 0 ? import_lib$1.unaryExpression("-", import_lib$1.numericLiteral(-value)) : import_lib$1.numericLiteral(value);
913
- if (typeof value === "boolean") return import_lib$1.booleanLiteral(value);
914
- if (value === null) return import_lib$1.nullLiteral();
915
- if (Array.isArray(value)) return import_lib$1.arrayExpression(value.map((item) => valueToExpression(item) ?? import_lib$1.nullLiteral()));
892
+ if (typeof value === "string") return stringLiteral(value);
893
+ if (typeof value === "number") return value < 0 ? unaryExpression("-", numericLiteral(-value)) : numericLiteral(value);
894
+ if (typeof value === "boolean") return booleanLiteral(value);
895
+ if (value === null) return nullLiteral();
896
+ if (Array.isArray(value)) return arrayExpression(value.map((item) => valueToExpression(item) ?? nullLiteral()));
916
897
  if (typeof value === "object") {
917
898
  const properties = [];
918
899
  for (const [key, item] of Object.entries(value)) {
919
900
  const expr = valueToExpression(item);
920
901
  if (expr === null) continue;
921
- properties.push(import_lib$1.objectProperty(import_lib$1.stringLiteral(key), expr));
902
+ properties.push(objectProperty(stringLiteral(key), expr));
922
903
  }
923
- return import_lib$1.objectExpression(properties);
904
+ return objectExpression(properties);
924
905
  }
925
906
  return null;
926
907
  };
927
- const arrayExpressionToCode = (elements) => {
928
- const nextAst = import_lib$1.arrayExpression(elements);
929
- return generateCode(nextAst);
930
- };
931
908
  //#endregion
932
909
  //#region src/utils/ast/edit-source.ts
933
910
  const childrenRange = (element) => {
@@ -939,29 +916,33 @@ const childrenRange = (element) => {
939
916
  };
940
917
  };
941
918
  const findAttribute = (opening, propertyName) => {
942
- return opening.attributes.find((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === propertyName);
919
+ return opening.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === propertyName);
943
920
  };
944
921
  const attributeInsertPoint = (opening) => {
945
922
  return opening.attributes[opening.attributes.length - 1]?.end ?? opening.name.end ?? null;
946
923
  };
924
+ const escapeJsxText = (value) => value.replace(/&(?=#?[A-Za-z0-9]+;)/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\{/g, "&#123;").replace(/\}/g, "&#125;");
947
925
  const editInnerText = (source, element, value) => {
948
926
  const range = childrenRange(element);
949
927
  if (!range) return [];
928
+ const text = escapeJsxText(value);
950
929
  const [only] = element.children;
951
- if (element.children.length === 1 && import_lib$1.isJSXText(only) && only.start != null && only.end != null) {
930
+ if (element.children.length === 1 && isJSXText(only) && only.start != null && only.end != null) {
952
931
  const raw = source.slice(only.start, only.end);
953
932
  if (raw.trim() !== "") {
954
- const leading = raw.length - raw.trimStart().length;
955
- const trailing = raw.length - raw.trimEnd().length;
933
+ const leadingSpace = raw.slice(0, raw.length - raw.trimStart().length);
934
+ const trailingSpace = raw.slice(raw.trimEnd().length);
935
+ const leading = /[\r\n]/.test(leadingSpace) ? leadingSpace.length : 0;
936
+ const trailing = /[\r\n]/.test(trailingSpace) ? trailingSpace.length : 0;
956
937
  return [{
957
938
  start: only.start + leading,
958
939
  end: only.end - trailing,
959
- content: value
940
+ content: text
960
941
  }];
961
942
  }
962
943
  }
963
944
  const edits = [];
964
- for (const child of element.children) if (import_lib$1.isJSXText(child) && child.start != null && child.end != null) edits.push({
945
+ for (const child of element.children) if (isJSXText(child) && child.start != null && child.end != null) edits.push({
965
946
  start: child.start,
966
947
  end: child.end,
967
948
  content: ""
@@ -969,7 +950,7 @@ const editInnerText = (source, element, value) => {
969
950
  edits.push({
970
951
  start: range.end,
971
952
  end: range.end,
972
- content: value
953
+ content: text
973
954
  });
974
955
  return edits;
975
956
  };
@@ -991,7 +972,7 @@ const editRichtext = (element, value) => {
991
972
  content: ""
992
973
  });
993
974
  const opening = element.openingElement;
994
- const attribute = import_lib$1.jsxAttribute(import_lib$1.jsxIdentifier("dangerouslySetInnerHTML"), import_lib$1.jsxExpressionContainer(import_lib$1.objectExpression([import_lib$1.objectProperty(import_lib$1.identifier("__html"), import_lib$1.stringLiteral(value))])));
975
+ const attribute = jsxAttribute(jsxIdentifier("dangerouslySetInnerHTML"), jsxExpressionContainer(objectExpression([objectProperty(identifier("__html"), stringLiteral(value))])));
995
976
  const content = generateCode(attribute);
996
977
  const existing = findAttribute(opening, "dangerouslySetInnerHTML");
997
978
  if (existing && existing.start != null && existing.end != null) {
@@ -1030,41 +1011,54 @@ const editJsxAttribute = (opening, propertyName, value) => {
1030
1011
  content: `=${content}`
1031
1012
  }];
1032
1013
  };
1033
- const holdsStructuralExpression = (value) => import_lib$1.isJSXExpressionContainer(value) && (import_lib$1.isArrayExpression(unwrapExpression(value.expression)) || import_lib$1.isObjectExpression(unwrapExpression(value.expression)));
1014
+ const holdsStructuralExpression = (value) => isJSXExpressionContainer(value) && (isArrayExpression(unwrapExpression(value.expression)) || isObjectExpression(unwrapExpression(value.expression)));
1034
1015
  const structuralSource = (value) => {
1035
1016
  try {
1036
- const expression = (0, import_lib.parseExpression)(value.trim(), { plugins: ["jsx", "typescript"] });
1037
- return import_lib$1.isArrayExpression(unwrapExpression(expression)) || import_lib$1.isObjectExpression(unwrapExpression(expression)) ? expression : null;
1017
+ const expression = parseExpression(value.trim(), { plugins: ["jsx", "typescript"] });
1018
+ return isArrayExpression(unwrapExpression(expression)) || isObjectExpression(unwrapExpression(expression)) ? expression : null;
1038
1019
  } catch {
1039
1020
  return null;
1040
1021
  }
1041
1022
  };
1023
+ const hasControlCharacter = (value) => Array.from(value).some((char) => char.charCodeAt(0) < 32);
1024
+ const jsxStringValue = (value) => {
1025
+ if (hasControlCharacter(value)) return jsxExpressionContainer(stringLiteral(value));
1026
+ const quote = value.includes("\"") && !value.includes("'") ? "'" : "\"";
1027
+ const text = value.replace(/&(?=#?[A-Za-z0-9]+;)/g, "&amp;");
1028
+ const escaped = quote === "\"" ? text.replace(/"/g, "&quot;") : text;
1029
+ const literal = stringLiteral(value);
1030
+ literal.extra = {
1031
+ raw: `${quote}${escaped}${quote}`,
1032
+ rawValue: value
1033
+ };
1034
+ return literal;
1035
+ };
1042
1036
  const buildAttributeValue = (value, type, current) => {
1043
1037
  if (type === "array" || type === "object") {
1044
1038
  if (typeof value === "string") try {
1045
- return import_lib$1.jsxExpressionContainer((0, import_lib.parseExpression)(value.trim(), { plugins: ["jsx", "typescript"] }));
1039
+ return jsxExpressionContainer(parseExpression(value.trim(), { plugins: ["jsx", "typescript"] }));
1046
1040
  } catch {
1047
- return import_lib$1.stringLiteral(value);
1041
+ return jsxStringValue(value);
1048
1042
  }
1049
1043
  const expr = valueToExpression(value);
1050
- return expr ? import_lib$1.jsxExpressionContainer(expr) : import_lib$1.stringLiteral("");
1044
+ return expr ? jsxExpressionContainer(expr) : stringLiteral("");
1051
1045
  }
1052
1046
  if (typeof value === "string") {
1053
1047
  if (holdsStructuralExpression(current) && !(type && STRING_VALUED_TYPES.has(type))) {
1054
1048
  const structural = structuralSource(value);
1055
- if (structural) return import_lib$1.jsxExpressionContainer(structural);
1049
+ if (structural) return jsxExpressionContainer(structural);
1056
1050
  }
1057
- return import_lib$1.stringLiteral(value);
1051
+ return jsxStringValue(value);
1058
1052
  }
1059
1053
  const expr = valueToExpression(value);
1060
- return expr ? import_lib$1.jsxExpressionContainer(expr) : import_lib$1.stringLiteral(String(value));
1054
+ return expr ? jsxExpressionContainer(expr) : jsxStringValue(String(value));
1061
1055
  };
1062
1056
  const editAttribute = (opening, propertyName, value, type) => {
1063
1057
  const attribute = findAttribute(opening, propertyName);
1064
1058
  if (!attribute || attribute.start == null || attribute.end == null) return null;
1065
1059
  if (typeof value === "string" && (type === "array" || type === "object" || holdsStructuralExpression(attribute.value) && !(type && STRING_VALUED_TYPES.has(type)))) {
1066
1060
  const expression = structuralSource(value);
1067
- if (expression && import_lib$1.isJSXExpressionContainer(attribute.value)) {
1061
+ if (expression && isJSXExpressionContainer(attribute.value)) {
1068
1062
  const text = value.trim();
1069
1063
  const lineComment = expression.trailingComments?.some((comment) => comment.type === "CommentLine");
1070
1064
  return [{
@@ -1074,7 +1068,7 @@ const editAttribute = (opening, propertyName, value, type) => {
1074
1068
  }];
1075
1069
  }
1076
1070
  }
1077
- const content = generateCode(import_lib$1.jsxAttribute(attribute.name, buildAttributeValue(value, type, attribute.value)));
1071
+ const content = generateCode(jsxAttribute(attribute.name, buildAttributeValue(value, type, attribute.value)));
1078
1072
  return [{
1079
1073
  start: attribute.start,
1080
1074
  end: attribute.end,
@@ -1082,8 +1076,16 @@ const editAttribute = (opening, propertyName, value, type) => {
1082
1076
  indent: true
1083
1077
  }];
1084
1078
  };
1079
+ const TRAILING_COMMENTS = /^[ \t]*(?:\/\*[^\r\n]*?\*\/[ \t]*)*(?:\/\/[^\r\n]*)?\r?\n/;
1085
1080
  const removeAttribute = (source, attribute) => {
1086
1081
  if (attribute.start == null || attribute.end == null) return null;
1082
+ const lineStart = source.lastIndexOf("\n", attribute.start - 1) + 1;
1083
+ const rest = TRAILING_COMMENTS.exec(source.slice(attribute.end));
1084
+ if (/^[ \t]*$/.test(source.slice(lineStart, attribute.start)) && rest) return [{
1085
+ start: lineStart,
1086
+ end: attribute.end + rest[0].length,
1087
+ content: ""
1088
+ }];
1087
1089
  let start = attribute.start;
1088
1090
  while (start > 0 && /\s/.test(source[start - 1])) start -= 1;
1089
1091
  return [{
@@ -1100,18 +1102,18 @@ const addAttribute = (source, opening, propertyName, value, type) => {
1100
1102
  return [{
1101
1103
  start: insertAt,
1102
1104
  end: insertAt,
1103
- content: `${lastStart != null && lineStart > 0 && /^\s*$/.test(source.slice(lineStart, lastStart)) ? "\n" : " "}${type === "jsx" ? `${propertyName}={${String(value).trim()}}` : generateCode(import_lib$1.jsxAttribute(import_lib$1.jsxIdentifier(propertyName), buildAttributeValue(value, type)))}`,
1105
+ 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)))}`,
1104
1106
  indent: true
1105
1107
  }];
1106
1108
  };
1107
1109
  const canEditAttributeValue = (attribute, value, type) => {
1108
- if (!import_lib$1.isJSXExpressionContainer(attribute.value) || import_lib$1.isJSXEmptyExpression(attribute.value.expression) || isLosslesslyEvaluable(attribute.value.expression)) return true;
1110
+ if (!isJSXExpressionContainer(attribute.value) || isJSXEmptyExpression(attribute.value.expression) || isLosslesslyEvaluable(attribute.value.expression)) return true;
1109
1111
  return typeof value === "string" && holdsStructuralExpression(attribute.value) && !(type && STRING_VALUED_TYPES.has(type)) && structuralSource(value) !== null;
1110
1112
  };
1111
1113
  //#endregion
1112
1114
  //#region src/utils/ast/update.ts
1113
- const hasDataId = (opening, dataId) => opening.attributes.some((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === DATA_ATTR.ID && attr.value && import_lib$1.isStringLiteral(attr.value) && attr.value.value === dataId);
1114
- const findJSXAttribute = (opening, name) => opening.attributes.find((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name) && attr.name.name === name);
1115
+ 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);
1116
+ const findJSXAttribute = (opening, name) => opening.attributes.find((attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === name);
1115
1117
  const findBinding = (opening, { dataId, label, property, options }) => {
1116
1118
  const bindingAttr = findJSXAttribute(opening, DATA_ATTR.BINDING);
1117
1119
  if (bindingAttr && !bindingAttr.value) return { failure: {
@@ -1121,8 +1123,8 @@ const findBinding = (opening, { dataId, label, property, options }) => {
1121
1123
  let own;
1122
1124
  if (bindingAttr?.value) {
1123
1125
  let bindingValue = "";
1124
- if (import_lib$1.isStringLiteral(bindingAttr.value)) bindingValue = bindingAttr.value.value;
1125
- else if (import_lib$1.isJSXExpressionContainer(bindingAttr.value)) try {
1126
+ if (isStringLiteral(bindingAttr.value)) bindingValue = bindingAttr.value.value;
1127
+ else if (isJSXExpressionContainer(bindingAttr.value)) try {
1126
1128
  bindingValue = generateCode(bindingAttr.value.expression);
1127
1129
  } catch (error) {
1128
1130
  return { failure: {
@@ -1133,7 +1135,7 @@ const findBinding = (opening, { dataId, label, property, options }) => {
1133
1135
  own = parseBinding(bindingValue);
1134
1136
  }
1135
1137
  const keyAttr = findJSXAttribute(opening, DATA_ATTR.BINDING_KEY);
1136
- const bindings = resolveBindings(own, keyAttr && (keyAttr.value && import_lib$1.isStringLiteral(keyAttr.value) ? keyAttr.value.value : null), getJSXTagName(opening), options);
1138
+ const bindings = resolveBindings(own, keyAttr && (keyAttr.value && isStringLiteral(keyAttr.value) ? keyAttr.value.value : null), getJSXTagName(opening), options);
1137
1139
  if (!own && bindings.length === 0) return { failure: {
1138
1140
  reason: "no-binding",
1139
1141
  dataId
@@ -1243,7 +1245,7 @@ const update = (code, dataId, label, value, property, options = {}) => {
1243
1245
  };
1244
1246
  try {
1245
1247
  const wrapped = wrap(code);
1246
- const ast = (0, import_lib.parse)(wrapped, {
1248
+ const ast = parse(wrapped, {
1247
1249
  sourceType: "module",
1248
1250
  plugins: ["jsx", "typescript"]
1249
1251
  });
@@ -1304,260 +1306,7 @@ const updateAll = (raw, entries, options = {}) => {
1304
1306
  code: current
1305
1307
  };
1306
1308
  };
1307
- /**
1308
- * @deprecated Not atomic: when an entry fails, the ones before and after it
1309
- * are still applied, and the returned `code` carries them. Use `updateAll`,
1310
- * which applies every entry or none. Will be removed in the next major.
1311
- */
1312
- const bulkUpdate = (raw, entries) => {
1313
- let current = raw;
1314
- const failures = [];
1315
- for (const entry of entries) {
1316
- const result = update(current, entry.dataId, entry.label, entry.value, entry.property);
1317
- current = result.code;
1318
- if (!result.success && result.failure) failures.push(result.failure);
1319
- }
1320
- return failures.length > 0 ? {
1321
- code: current,
1322
- success: false,
1323
- failures
1324
- } : {
1325
- code: current,
1326
- success: true
1327
- };
1328
- };
1329
- //#endregion
1330
- //#region src/utils/ast/array-source.ts
1331
- const commaIn = (source, start, end) => {
1332
- let comma = null;
1333
- for (let at = start; at < end; at++) {
1334
- if (/\s/.test(source[at])) continue;
1335
- if (source.startsWith("/*", at)) {
1336
- const close = source.indexOf("*/", at + 2);
1337
- if (close < 0 || close + 2 > end) return null;
1338
- at = close + 1;
1339
- } else if (source.startsWith("//", at)) {
1340
- const newline = source.indexOf("\n", at + 2);
1341
- at = newline < 0 ? end : newline;
1342
- } else if (source[at] === "," && comma === null) comma = at;
1343
- else return null;
1344
- }
1345
- return comma;
1346
- };
1347
- const denseArraySource = (source) => {
1348
- const array = parseArrayExpression(source);
1349
- if (!array || array.elements.some((node) => !import_lib$1.isExpression(node) || node.extra?.parenthesized)) return null;
1350
- const elements = array.elements;
1351
- const commas = elements.slice(0, -1).map((node, index) => commaIn(source, node.end, elements[index + 1].start));
1352
- if (commas.some((comma) => comma === null)) return null;
1353
- const last = elements.at(-1);
1354
- return {
1355
- array,
1356
- elements,
1357
- commas,
1358
- trailing: last ? commaIn(source, last.end, array.end - 1) : null
1359
- };
1360
- };
1361
- const canStructurallyEditArray = (source) => denseArraySource(source) !== null;
1362
- const validArrayIndices = (indices, length) => [...indices].every((index) => Number.isInteger(index) && index >= 0 && index < length);
1363
- const reorderArraySource = (source, elements, next) => applyEdits(source, elements.map((node, index) => ({
1364
- start: node.start,
1365
- end: node.end,
1366
- content: source.slice(next[index].start, next[index].end)
1367
- })));
1368
- const removeArraySource = (source, data, indices) => {
1369
- const edits = [];
1370
- const removedCommas = /* @__PURE__ */ new Set();
1371
- const { elements, commas, trailing } = data;
1372
- for (let index = 0; index < elements.length; index++) {
1373
- if (!indices.has(index)) continue;
1374
- const start = index;
1375
- while (index + 1 < elements.length && indices.has(index + 1)) index++;
1376
- for (let current = start; current <= index; current++) {
1377
- const node = elements[current];
1378
- edits.push({
1379
- start: node.start,
1380
- end: node.end,
1381
- content: ""
1382
- });
1383
- if (current < elements.length - 1) removedCommas.add(commas[current]);
1384
- }
1385
- if (index === elements.length - 1) {
1386
- if (trailing !== null) removedCommas.add(trailing);
1387
- else if (start > 0) removedCommas.add(commas[start - 1]);
1388
- }
1389
- }
1390
- for (const comma of removedCommas) edits.push({
1391
- start: comma,
1392
- end: comma + 1,
1393
- content: ""
1394
- });
1395
- return applyEdits(source, edits);
1396
- };
1397
- const appendArraySource = (source, data, copies) => {
1398
- const last = data.elements.at(-1);
1399
- if (!last || copies.length === 0) return source;
1400
- return applyEdits(source, [{
1401
- start: last.end,
1402
- end: last.end,
1403
- content: `, ${copies.join(", ")}`
1404
- }]);
1405
- };
1406
- //#endregion
1407
- //#region src/utils/ast/items.ts
1408
- const elementsOf = (code) => parseArrayExpression(code)?.elements ?? null;
1409
- const kindOf = (element) => import_lib$1.isObjectExpression(element) ? "object" : "primitive";
1410
- const parseItems = (code) => {
1411
- return elementsOf(code)?.flatMap((node, index) => import_lib$1.isExpression(node) ? [{
1412
- index,
1413
- kind: kindOf(node),
1414
- node
1415
- }] : []) ?? null;
1416
- };
1417
- const resolveRenderLeaf = (render, key) => {
1418
- const leaf = render?.[key];
1419
- return leaf && "type" in leaf ? leaf : null;
1420
- };
1421
- const toTemplateRaw = (value) => {
1422
- return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\r/g, "\\r");
1423
- };
1424
- const buildPropertyValue = (value, declaredType, renderLeaf, current) => {
1425
- if (renderLeaf?.property === BINDING_PROP.INNER_HTML) {
1426
- const raw = String(value);
1427
- return import_lib$1.templateLiteral([import_lib$1.templateElement({
1428
- raw: toTemplateRaw(raw),
1429
- cooked: raw
1430
- }, true)], []);
1431
- }
1432
- if (renderLeaf?.type === "jsx" || import_lib$1.isJSXElement(current) || import_lib$1.isJSXFragment(current)) {
1433
- const trimmed = String(value).trim();
1434
- if (!trimmed.startsWith("<")) return import_lib$1.stringLiteral(trimmed);
1435
- try {
1436
- return (0, import_lib.parseExpression)(trimmed, { plugins: ["jsx", "typescript"] });
1437
- } catch {
1438
- return;
1439
- }
1440
- }
1441
- if (declaredType === "array" || declaredType === "object") {
1442
- if (typeof value === "string") try {
1443
- return (0, import_lib.parseExpression)(value, { plugins: ["jsx", "typescript"] });
1444
- } catch {
1445
- return;
1446
- }
1447
- if (!isLosslesslyEvaluable(current)) return;
1448
- return valueToExpression(value) ?? void 0;
1449
- }
1450
- return createNodeFromValue(declaredType, parseValue(value)) ?? void 0;
1451
- };
1452
- const updateArrayItemProperty = (code, index, key, value, render) => {
1453
- const elements = elementsOf(code);
1454
- const element = elements?.[index];
1455
- if (!elements || !import_lib$1.isObjectExpression(element)) return null;
1456
- const target = element.properties.find((property) => import_lib$1.isObjectProperty(property) && import_lib$1.isIdentifier(property.key) && property.key.name === key);
1457
- if (!target) return null;
1458
- const declaredType = extractObjectProperties(element)[key]?.type ?? "string";
1459
- const nextValue = buildPropertyValue(value, declaredType, resolveRenderLeaf(render, key), target.value);
1460
- if (!nextValue) return null;
1461
- let serialized = typeof value === "string" && (declaredType === "array" || declaredType === "object" || import_lib$1.isJSXElement(nextValue) || import_lib$1.isJSXFragment(nextValue)) ? value.trim() : generateCode(nextValue);
1462
- if (nextValue.trailingComments?.some((comment) => comment.type === "CommentLine")) serialized += "\n";
1463
- const content = target.shorthand ? `${key}: ${serialized}` : serialized;
1464
- return applyEdits(code, [{
1465
- start: target.value.start,
1466
- end: target.value.end,
1467
- content
1468
- }]);
1469
- };
1470
- const updateArrayItemValue = (code, index, value) => {
1471
- const elements = elementsOf(code);
1472
- const element = elements?.[index];
1473
- if (!elements || !import_lib$1.isExpression(element)) return null;
1474
- const nextValue = createNodeFromValue(extractNodeValue(element).type, parseValue(value));
1475
- if (!nextValue) return null;
1476
- return applyEdits(code, [{
1477
- start: element.start,
1478
- end: element.end,
1479
- content: generateCode(nextValue)
1480
- }]);
1481
- };
1482
- const moveArrayItem = (code, from, to) => {
1483
- const data = denseArraySource(code);
1484
- if (!data || !validArrayIndices([from], data.elements.length) || !Number.isInteger(to)) return null;
1485
- const next = [...data.elements];
1486
- const [moved] = next.splice(from, 1);
1487
- next.splice(to, 0, moved);
1488
- return reorderArraySource(code, data.elements, next);
1489
- };
1490
- const moveArrayItems = (code, indices, direction) => {
1491
- const data = denseArraySource(code);
1492
- if (!data || !validArrayIndices(indices, data.elements.length) || !["up", "down"].includes(direction)) return null;
1493
- const next = moveSelectedIndices(data.elements, indices, direction);
1494
- return {
1495
- code: reorderArraySource(code, data.elements, next.items),
1496
- indices: next.indices
1497
- };
1498
- };
1499
- const removeArrayItems = (code, indices, kind) => {
1500
- const data = denseArraySource(code);
1501
- if (!data || !validArrayIndices(indices, data.elements.length)) return null;
1502
- const remaining = removeIndices(data.elements, indices);
1503
- if (!(kind === void 0 ? remaining : remaining.filter((node) => kindOf(node) === kind)).length) return null;
1504
- return removeArraySource(code, data, indices);
1505
- };
1506
- const copyItem = (code, element, generateId, usedIds) => {
1507
- const edits = [];
1508
- let unsupported = false;
1509
- const reserveId = (id) => {
1510
- if (usedIds.has(id)) unsupported = true;
1511
- usedIds.add(id);
1512
- return JSON.stringify(id);
1513
- };
1514
- import_lib$1.traverseFast(element, (node) => {
1515
- if (!import_lib$1.isJSXOpeningElement(node)) return;
1516
- const ids = node.attributes.filter((attr) => import_lib$1.isJSXAttribute(attr) && import_lib$1.isJSXIdentifier(attr.name, { name: "data-id" }));
1517
- const attr = ids[0];
1518
- if (ids.length > 1 || attr && (!import_lib$1.isStringLiteral(attr.value) || node.attributes.slice(node.attributes.indexOf(attr) + 1).some((a) => import_lib$1.isJSXSpreadAttribute(a)))) {
1519
- unsupported = true;
1520
- return;
1521
- }
1522
- if (attr && import_lib$1.isStringLiteral(attr.value)) edits.push({
1523
- start: attr.value.start,
1524
- end: attr.value.end,
1525
- content: reserveId(generateId())
1526
- });
1527
- });
1528
- if (import_lib$1.isObjectExpression(element)) {
1529
- const keys = element.properties.filter((prop) => import_lib$1.isObjectProperty(prop) && !prop.computed && (import_lib$1.isIdentifier(prop.key, { name: "key" }) || import_lib$1.isStringLiteral(prop.key, { value: "key" })));
1530
- const key = keys[0];
1531
- if (keys.length > 1 || key && (!import_lib$1.isStringLiteral(key.value) || element.properties.slice(element.properties.indexOf(key) + 1).some((prop) => import_lib$1.isSpreadElement(prop) || "computed" in prop && prop.computed))) return null;
1532
- if (key && import_lib$1.isStringLiteral(key.value)) edits.push({
1533
- start: key.value.start,
1534
- end: key.value.end,
1535
- content: reserveId(`${key.value.value}-${generateId()}`)
1536
- });
1537
- }
1538
- if (unsupported) return null;
1539
- return applyEdits(code.slice(element.start, element.end), edits.map((edit) => ({
1540
- ...edit,
1541
- start: edit.start - element.start,
1542
- end: edit.end - element.start
1543
- })));
1544
- };
1545
- const duplicateArrayItems = (code, indices, generateId = () => nanoid(6)) => {
1546
- const data = denseArraySource(code);
1547
- if (!data || !indices.size || !validArrayIndices(indices, data.elements.length)) return null;
1548
- const usedIds = /* @__PURE__ */ new Set();
1549
- import_lib$1.traverseFast(data.array, (node) => {
1550
- if (import_lib$1.isJSXAttribute(node) && import_lib$1.isJSXIdentifier(node.name, { name: "data-id" }) && import_lib$1.isStringLiteral(node.value)) usedIds.add(node.value.value);
1551
- else if (import_lib$1.isObjectProperty(node) && !node.computed && (import_lib$1.isIdentifier(node.key, { name: "key" }) || import_lib$1.isStringLiteral(node.key, { value: "key" })) && import_lib$1.isStringLiteral(node.value)) usedIds.add(node.value.value);
1552
- });
1553
- const copies = [...indices].sort((a, b) => a - b).map((index) => copyItem(code, data.elements[index], generateId, usedIds));
1554
- return copies.every((copy) => copy !== null) ? appendArraySource(code, data, copies) : null;
1555
- };
1556
- const appendArrayItem = (code, kind, generateId = () => nanoid(6)) => {
1557
- const index = denseArraySource(code)?.elements.findIndex((node) => kindOf(node) === kind) ?? -1;
1558
- return index < 0 ? null : duplicateArrayItems(code, /* @__PURE__ */ new Set([index]), generateId);
1559
- };
1560
1309
  //#endregion
1561
- 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 };
1310
+ export { parseArrayExpression as _, getChildrenSignatures as a, generateCode as b, removeIndices as c, getStructuredValue as d, readNodeBindings as f, isLosslesslyEvaluable as g, extractObjectProperties as h, valueToExpression as i, findEditableChildren as l, extractNodeValue as m, updateAll as n, extract as o, canLosslesslyEvaluateSource as p, createNodeFromValue as r, moveSelectedIndices as s, update as t, getCurrentValue as u, parseValue as v, unwrapExpression as y };
1562
1311
 
1563
- //# sourceMappingURL=items-B6OXxcLG.js.map
1312
+ //# sourceMappingURL=update-DNInQSM7.js.map