@pixerate/editor 0.14.3 → 0.15.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 (71) hide show
  1. package/dist/agent/index.cjs +28 -220
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +1 -1
  4. package/dist/agent/index.d.ts +1 -1
  5. package/dist/agent/index.js +5 -154
  6. package/dist/agent/index.js.map +1 -1
  7. package/dist/canvas/index.cjs +113 -377
  8. package/dist/canvas/index.cjs.map +1 -1
  9. package/dist/canvas/index.d.cts +2 -2
  10. package/dist/canvas/index.d.ts +2 -2
  11. package/dist/canvas/index.js +18 -208
  12. package/dist/canvas/index.js.map +1 -1
  13. package/dist/chunk-33UVEDOS.cjs +233 -0
  14. package/dist/chunk-33UVEDOS.cjs.map +1 -0
  15. package/dist/chunk-7FWEWE6T.js +1888 -0
  16. package/dist/chunk-7FWEWE6T.js.map +1 -0
  17. package/dist/chunk-BYCOFZAA.js +514 -0
  18. package/dist/chunk-BYCOFZAA.js.map +1 -0
  19. package/dist/chunk-CYKQLDYH.cjs +1290 -0
  20. package/dist/chunk-CYKQLDYH.cjs.map +1 -0
  21. package/dist/chunk-GLSIZKOX.js +17 -0
  22. package/dist/chunk-GLSIZKOX.js.map +1 -0
  23. package/dist/chunk-GWHJVZPI.js +233 -0
  24. package/dist/chunk-GWHJVZPI.js.map +1 -0
  25. package/dist/chunk-LDES3EOS.cjs +1888 -0
  26. package/dist/chunk-LDES3EOS.cjs.map +1 -0
  27. package/dist/chunk-MPPXH7U5.cjs +336 -0
  28. package/dist/chunk-MPPXH7U5.cjs.map +1 -0
  29. package/dist/chunk-NNJRJJSC.js +1290 -0
  30. package/dist/chunk-NNJRJJSC.js.map +1 -0
  31. package/dist/chunk-O7LOPQMH.js +336 -0
  32. package/dist/chunk-O7LOPQMH.js.map +1 -0
  33. package/dist/chunk-SEDR75VH.cjs +17 -0
  34. package/dist/chunk-SEDR75VH.cjs.map +1 -0
  35. package/dist/chunk-SHWP2A43.cjs +514 -0
  36. package/dist/chunk-SHWP2A43.cjs.map +1 -0
  37. package/dist/chunk-VHZCXHS4.js +222 -0
  38. package/dist/chunk-VHZCXHS4.js.map +1 -0
  39. package/dist/chunk-WADCJ7A7.cjs +222 -0
  40. package/dist/chunk-WADCJ7A7.cjs.map +1 -0
  41. package/dist/extensions/index.cjs +25 -1920
  42. package/dist/extensions/index.cjs.map +1 -1
  43. package/dist/extensions/index.js +22 -1868
  44. package/dist/extensions/index.js.map +1 -1
  45. package/dist/grammar/index.cjs +44 -387
  46. package/dist/grammar/index.cjs.map +1 -1
  47. package/dist/grammar/index.js +23 -321
  48. package/dist/grammar/index.js.map +1 -1
  49. package/dist/history/index.cjs +6 -257
  50. package/dist/history/index.cjs.map +1 -1
  51. package/dist/history/index.js +4 -227
  52. package/dist/history/index.js.map +1 -1
  53. package/dist/image-editor/index.cjs +63 -106
  54. package/dist/image-editor/index.cjs.map +1 -1
  55. package/dist/index.cjs +324 -7232
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +0 -4
  58. package/dist/index.d.ts +0 -4
  59. package/dist/index.js +258 -7007
  60. package/dist/index.js.map +1 -1
  61. package/dist/serializers/index.cjs +28 -558
  62. package/dist/serializers/index.cjs.map +1 -1
  63. package/dist/serializers/index.js +16 -496
  64. package/dist/serializers/index.js.map +1 -1
  65. package/dist/spreadsheet/index.cjs +21 -1319
  66. package/dist/spreadsheet/index.cjs.map +1 -1
  67. package/dist/spreadsheet/index.js +14 -1274
  68. package/dist/spreadsheet/index.js.map +1 -1
  69. package/dist/{types-lGtRobRV.d.cts → types-DC8b2TsA.d.cts} +1 -1
  70. package/dist/{types-lGtRobRV.d.ts → types-DC8b2TsA.d.ts} +1 -1
  71. package/package.json +1 -1
@@ -1,324 +1,26 @@
1
- // src/grammar/tokens.ts
2
- var TEMPLATE_REGEX = /{{\s*([^}]+?)\s*}}/g;
3
- var VARIABLE_REGEX = /(?<!\{)\{([^{}]+)\}(?!\})/g;
4
- var INSTRUCTION_REGEX = /__(.+?)__/g;
5
- var templateRegex = TEMPLATE_REGEX;
6
- var variableRegex = VARIABLE_REGEX;
7
- var instructionRegex = INSTRUCTION_REGEX;
8
-
9
- // src/grammar/tokenizer.ts
10
- function tokenizePrompt(text) {
11
- if (!text) {
12
- return [];
13
- }
14
- const rawMatches = [];
15
- const tmplRegex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
16
- let match;
17
- while ((match = tmplRegex.exec(text)) !== null) {
18
- rawMatches.push({
19
- type: "template",
20
- raw: match[0],
21
- value: match[1].trim(),
22
- start: match.index,
23
- end: match.index + match[0].length
24
- });
25
- }
26
- const varRegex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);
27
- while ((match = varRegex.exec(text)) !== null) {
28
- const start = match.index;
29
- const end = start + match[0].length;
30
- const overlaps = rawMatches.some(
31
- (m) => !(end <= m.start || start >= m.end)
32
- );
33
- if (!overlaps) {
34
- rawMatches.push({
35
- type: "variable",
36
- raw: match[0],
37
- value: match[1].trim(),
38
- start,
39
- end
40
- });
41
- }
42
- }
43
- const instRegex = new RegExp(
44
- INSTRUCTION_REGEX.source,
45
- INSTRUCTION_REGEX.flags
46
- );
47
- while ((match = instRegex.exec(text)) !== null) {
48
- const start = match.index;
49
- const end = start + match[0].length;
50
- const overlaps = rawMatches.some(
51
- (m) => !(end <= m.start || start >= m.end)
52
- );
53
- if (!overlaps) {
54
- rawMatches.push({
55
- type: "instruction",
56
- raw: match[0],
57
- value: match[1].trim(),
58
- start,
59
- end
60
- });
61
- }
62
- }
63
- rawMatches.sort((a, b) => a.start - b.start);
64
- const tokens = [];
65
- let currentIdx = 0;
66
- for (const m of rawMatches) {
67
- if (m.start > currentIdx) {
68
- const textChunk = text.slice(currentIdx, m.start);
69
- tokens.push({
70
- type: "text",
71
- raw: textChunk,
72
- value: textChunk,
73
- start: currentIdx,
74
- end: m.start
75
- });
76
- }
77
- tokens.push({
78
- type: m.type,
79
- raw: m.raw,
80
- value: m.value,
81
- start: m.start,
82
- end: m.end
83
- });
84
- currentIdx = m.end;
85
- }
86
- if (currentIdx < text.length) {
87
- const textChunk = text.slice(currentIdx);
88
- tokens.push({
89
- type: "text",
90
- raw: textChunk,
91
- value: textChunk,
92
- start: currentIdx,
93
- end: text.length
94
- });
95
- }
96
- return tokens;
97
- }
98
-
99
- // src/grammar/resolver.ts
100
- function getLatestVersion(template) {
101
- if (!template.versions || template.versions.length === 0) {
102
- if (template.body !== void 0) {
103
- return {
104
- id: template.id || "default",
105
- version: "1.0",
106
- body: template.body
107
- };
108
- }
109
- return void 0;
110
- }
111
- if (template.latestVersion) {
112
- const found = template.versions.find(
113
- (v) => v.version === template.latestVersion
114
- );
115
- if (found) return found;
116
- }
117
- return template.versions[template.versions.length - 1];
118
- }
119
- var TEMPLATE_LOOP_ERROR = "[Template loop detected]";
120
- var TEMPLATE_DEPTH_ERROR = "[Template max depth exceeded]";
121
- function getTemplateBody(template, bindings) {
122
- const boundVersionId = bindings?.[template.name];
123
- if (boundVersionId && template.versions) {
124
- const boundVersion = template.versions.find(
125
- (v) => v.id === boundVersionId || v.version === boundVersionId
126
- );
127
- return boundVersion?.body;
128
- }
129
- return getLatestVersion(template)?.body ?? template.body;
130
- }
131
- function resolveTemplates(text, templates = [], options) {
132
- const templateMap = /* @__PURE__ */ new Map();
133
- for (const t of templates) {
134
- templateMap.set(t.name, t);
135
- }
136
- const maxDepth = options?.maxDepth ?? 10;
137
- function resolveRecursive(currentText, visited, depth) {
138
- const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
139
- return currentText.replace(regex, (fullMatch, rawTemplateName) => {
140
- const templateName = rawTemplateName.trim();
141
- if (visited.has(templateName)) {
142
- return TEMPLATE_LOOP_ERROR;
143
- }
144
- const template = templateMap.get(templateName);
145
- if (!template) {
146
- return fullMatch;
147
- }
148
- const versionBody = getTemplateBody(template, options?.bindings);
149
- if (versionBody === void 0) {
150
- return fullMatch;
151
- }
152
- if (depth + 1 > maxDepth) {
153
- return TEMPLATE_DEPTH_ERROR;
154
- }
155
- const nextVisited = new Set(visited);
156
- nextVisited.add(templateName);
157
- return resolveRecursive(versionBody, nextVisited, depth + 1);
158
- });
159
- }
160
- return resolveRecursive(text, /* @__PURE__ */ new Set(), 0);
161
- }
162
- function resolveVariables(text, values) {
163
- if (!text) return "";
164
- return text.replace(
165
- new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags),
166
- (fullMatch, varName) => {
167
- const key = varName.trim();
168
- if (Object.prototype.hasOwnProperty.call(values, key)) {
169
- return String(values[key]);
170
- }
171
- return fullMatch;
172
- }
173
- );
174
- }
175
- function extractTemplateNames(text) {
176
- if (!text) return [];
177
- const set = /* @__PURE__ */ new Set();
178
- const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
179
- let match;
180
- while ((match = regex.exec(text)) !== null) {
181
- set.add(match[1].trim());
182
- }
183
- return Array.from(set);
184
- }
185
- function extractVariableNames(text) {
186
- if (!text) return [];
187
- const set = /* @__PURE__ */ new Set();
188
- const regex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);
189
- let match;
190
- while ((match = regex.exec(text)) !== null) {
191
- set.add(match[1].trim());
192
- }
193
- return Array.from(set);
194
- }
195
- function extractInstructionNames(text) {
196
- if (!text) return [];
197
- const set = /* @__PURE__ */ new Set();
198
- const regex = new RegExp(INSTRUCTION_REGEX.source, INSTRUCTION_REGEX.flags);
199
- let match;
200
- while ((match = regex.exec(text)) !== null) {
201
- set.add(match[1].trim());
202
- }
203
- return Array.from(set);
204
- }
205
-
206
- // src/grammar/sourcemap.ts
207
- function resolveTemplatesWithMapping(text, templates = [], templateBindings, options) {
208
- if (!templates || templates.length === 0 || !text.includes("{{")) {
209
- return {
210
- text,
211
- map: [
212
- {
213
- resolvedStart: 0,
214
- resolvedEnd: text.length,
215
- source: "raw",
216
- rawStart: 0,
217
- rawEnd: text.length
218
- }
219
- ]
220
- };
221
- }
222
- const templateMap = new Map(templates.map((t) => [t.name, t]));
223
- const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
224
- let match;
225
- let lastIndex = 0;
226
- let resolvedText = "";
227
- const map = [];
228
- while ((match = regex.exec(text)) !== null) {
229
- const [fullMatch, rawTemplateName] = match;
230
- const templateName = rawTemplateName.trim();
231
- const matchIndex = match.index;
232
- if (matchIndex > lastIndex) {
233
- const rawSegment = text.substring(lastIndex, matchIndex);
234
- map.push({
235
- resolvedStart: resolvedText.length,
236
- resolvedEnd: resolvedText.length + rawSegment.length,
237
- source: "raw",
238
- rawStart: lastIndex,
239
- rawEnd: matchIndex
240
- });
241
- resolvedText += rawSegment;
242
- }
243
- let resolvedBody = fullMatch;
244
- let isTemplate = false;
245
- const template = templateMap.get(templateName);
246
- if (template && getTemplateBody(template, templateBindings) !== void 0) {
247
- resolvedBody = resolveTemplates(fullMatch, templates, {
248
- bindings: templateBindings,
249
- maxDepth: options?.maxDepth
250
- });
251
- isTemplate = true;
252
- }
253
- if (isTemplate) {
254
- map.push({
255
- resolvedStart: resolvedText.length,
256
- resolvedEnd: resolvedText.length + resolvedBody.length,
257
- source: "template",
258
- rawStart: matchIndex,
259
- rawEnd: matchIndex + fullMatch.length,
260
- templateName
261
- });
262
- resolvedText += resolvedBody;
263
- } else {
264
- map.push({
265
- resolvedStart: resolvedText.length,
266
- resolvedEnd: resolvedText.length + fullMatch.length,
267
- source: "raw",
268
- rawStart: matchIndex,
269
- rawEnd: matchIndex + fullMatch.length
270
- });
271
- resolvedText += fullMatch;
272
- }
273
- lastIndex = matchIndex + fullMatch.length;
274
- }
275
- if (lastIndex < text.length) {
276
- const rawSegment = text.substring(lastIndex);
277
- map.push({
278
- resolvedStart: resolvedText.length,
279
- resolvedEnd: resolvedText.length + rawSegment.length,
280
- source: "raw",
281
- rawStart: lastIndex,
282
- rawEnd: text.length
283
- });
284
- resolvedText += rawSegment;
285
- }
286
- return { text: resolvedText, map };
287
- }
288
- function mapResolvedOffsetToRaw(resolvedOffset, map) {
289
- for (let i = 0; i < map.length; i++) {
290
- const seg = map[i];
291
- const isLast = i === map.length - 1;
292
- const inRange = isLast ? resolvedOffset >= seg.resolvedStart && resolvedOffset <= seg.resolvedEnd : resolvedOffset >= seg.resolvedStart && resolvedOffset < seg.resolvedEnd;
293
- if (inRange) {
294
- if (seg.source === "raw") {
295
- return seg.rawStart + (resolvedOffset - seg.resolvedStart);
296
- }
297
- if (resolvedOffset === seg.resolvedEnd) {
298
- return seg.rawEnd;
299
- }
300
- return seg.rawStart;
301
- }
302
- }
303
- return resolvedOffset;
304
- }
305
- function mapRawOffsetToResolved(rawOffset, map) {
306
- for (let i = 0; i < map.length; i++) {
307
- const seg = map[i];
308
- const isLast = i === map.length - 1;
309
- const inRange = isLast ? rawOffset >= seg.rawStart && rawOffset <= seg.rawEnd : rawOffset >= seg.rawStart && rawOffset < seg.rawEnd;
310
- if (inRange) {
311
- if (seg.source === "raw") {
312
- return seg.resolvedStart + (rawOffset - seg.rawStart);
313
- }
314
- if (rawOffset === seg.rawEnd) {
315
- return seg.resolvedEnd;
316
- }
317
- return seg.resolvedStart;
318
- }
319
- }
320
- return rawOffset;
321
- }
1
+ import {
2
+ TEMPLATE_DEPTH_ERROR,
3
+ TEMPLATE_LOOP_ERROR,
4
+ extractInstructionNames,
5
+ extractTemplateNames,
6
+ extractVariableNames,
7
+ getLatestVersion,
8
+ getTemplateBody,
9
+ mapRawOffsetToResolved,
10
+ mapResolvedOffsetToRaw,
11
+ resolveTemplates,
12
+ resolveTemplatesWithMapping,
13
+ resolveVariables,
14
+ tokenizePrompt
15
+ } from "../chunk-O7LOPQMH.js";
16
+ import {
17
+ INSTRUCTION_REGEX,
18
+ TEMPLATE_REGEX,
19
+ VARIABLE_REGEX,
20
+ instructionRegex,
21
+ templateRegex,
22
+ variableRegex
23
+ } from "../chunk-GLSIZKOX.js";
322
24
  export {
323
25
  INSTRUCTION_REGEX,
324
26
  TEMPLATE_DEPTH_ERROR,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/grammar/tokens.ts","../../src/grammar/tokenizer.ts","../../src/grammar/resolver.ts","../../src/grammar/sourcemap.ts"],"sourcesContent":["/**\n * Canonical regex patterns for prompt editing tokens.\n */\nexport const TEMPLATE_REGEX = /{{\\s*([^}]+?)\\s*}}/g;\nexport const VARIABLE_REGEX = /(?<!\\{)\\{([^{}]+)\\}(?!\\})/g;\nexport const INSTRUCTION_REGEX = /__(.+?)__/g;\n\n// Backward-compatible camelCase aliases\nexport const templateRegex = TEMPLATE_REGEX;\nexport const variableRegex = VARIABLE_REGEX;\nexport const instructionRegex = INSTRUCTION_REGEX;\n\nexport type TokenType = \"template\" | \"variable\" | \"instruction\" | \"text\";\n\nexport interface Token {\n type: TokenType;\n raw: string;\n value: string;\n start: number;\n end: number;\n}\n\nexport interface TemplateVersion {\n id: string;\n version: string | number;\n body: string;\n createdAt?: any;\n [key: string]: any;\n}\n\nexport interface Template {\n id?: string;\n name: string;\n body?: string;\n latestVersion?: string | number;\n versions?: TemplateVersion[];\n color?: string;\n [key: string]: any;\n}\n\nexport interface ColorGradient {\n from: string;\n to: string;\n}\n","import {\n TEMPLATE_REGEX,\n VARIABLE_REGEX,\n INSTRUCTION_REGEX,\n Token,\n} from \"./tokens\";\n\ninterface RawMatch {\n type: \"template\" | \"variable\" | \"instruction\";\n raw: string;\n value: string;\n start: number;\n end: number;\n}\n\n/**\n * Parses any prompt string into an array of typed tokens in linear order.\n * Plain text between tokens is preserved as `{ type: 'text' }`.\n */\nexport function tokenizePrompt(text: string): Token[] {\n if (!text) {\n return [];\n }\n\n const rawMatches: RawMatch[] = [];\n\n // Match {{template}}\n const tmplRegex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = tmplRegex.exec(text)) !== null) {\n rawMatches.push({\n type: \"template\",\n raw: match[0],\n value: match[1].trim(),\n start: match.index,\n end: match.index + match[0].length,\n });\n }\n\n // Match {variable}\n const varRegex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);\n while ((match = varRegex.exec(text)) !== null) {\n // Avoid double matching if overlapping with template\n const start = match.index;\n const end = start + match[0].length;\n const overlaps = rawMatches.some(\n (m) => !(end <= m.start || start >= m.end),\n );\n if (!overlaps) {\n rawMatches.push({\n type: \"variable\",\n raw: match[0],\n value: match[1].trim(),\n start,\n end,\n });\n }\n }\n\n // Match __instruction__\n const instRegex = new RegExp(\n INSTRUCTION_REGEX.source,\n INSTRUCTION_REGEX.flags,\n );\n while ((match = instRegex.exec(text)) !== null) {\n const start = match.index;\n const end = start + match[0].length;\n const overlaps = rawMatches.some(\n (m) => !(end <= m.start || start >= m.end),\n );\n if (!overlaps) {\n rawMatches.push({\n type: \"instruction\",\n raw: match[0],\n value: match[1].trim(),\n start,\n end,\n });\n }\n }\n\n // Sort matches by start index\n rawMatches.sort((a, b) => a.start - b.start);\n\n const tokens: Token[] = [];\n let currentIdx = 0;\n\n for (const m of rawMatches) {\n if (m.start > currentIdx) {\n const textChunk = text.slice(currentIdx, m.start);\n tokens.push({\n type: \"text\",\n raw: textChunk,\n value: textChunk,\n start: currentIdx,\n end: m.start,\n });\n }\n tokens.push({\n type: m.type,\n raw: m.raw,\n value: m.value,\n start: m.start,\n end: m.end,\n });\n currentIdx = m.end;\n }\n\n if (currentIdx < text.length) {\n const textChunk = text.slice(currentIdx);\n tokens.push({\n type: \"text\",\n raw: textChunk,\n value: textChunk,\n start: currentIdx,\n end: text.length,\n });\n }\n\n return tokens;\n}\n","import {\n TEMPLATE_REGEX,\n VARIABLE_REGEX,\n INSTRUCTION_REGEX,\n Template,\n TemplateVersion,\n} from \"./tokens\";\n\n/**\n * Finds the latest version of a template based on `latestVersion` or last version entry.\n */\nexport function getLatestVersion(\n template: Template,\n): TemplateVersion | undefined {\n if (!template.versions || template.versions.length === 0) {\n if (template.body !== undefined) {\n return {\n id: template.id || \"default\",\n version: \"1.0\",\n body: template.body,\n };\n }\n return undefined;\n }\n if (template.latestVersion) {\n const found = template.versions.find(\n (v) => v.version === template.latestVersion,\n );\n if (found) return found;\n }\n return template.versions[template.versions.length - 1];\n}\n\nexport interface ResolveTemplatesOptions {\n bindings?: Record<string, string>;\n maxDepth?: number;\n}\n\n/** Marker substituted for a template tag that would recurse into itself. */\nexport const TEMPLATE_LOOP_ERROR = \"[Template loop detected]\";\n/** Marker substituted for a template tag nested deeper than `maxDepth`. */\nexport const TEMPLATE_DEPTH_ERROR = \"[Template max depth exceeded]\";\n\n/**\n * Returns the body a template tag resolves to, honoring version bindings.\n */\nexport function getTemplateBody(\n template: Template,\n bindings?: Record<string, string>,\n): string | undefined {\n const boundVersionId = bindings?.[template.name];\n if (boundVersionId && template.versions) {\n const boundVersion = template.versions.find(\n (v) => v.id === boundVersionId || v.version === boundVersionId,\n );\n return boundVersion?.body;\n }\n return getLatestVersion(template)?.body ?? template.body;\n}\n\n/**\n * Recursively resolves template tags `{{template_name}}` in a given text.\n * A tag that would recurse into itself is replaced with `TEMPLATE_LOOP_ERROR`,\n * and a tag nested deeper than `maxDepth` with `TEMPLATE_DEPTH_ERROR`; the rest\n * of the text still resolves normally.\n */\nexport function resolveTemplates(\n text: string,\n templates: Template[] = [],\n options?: ResolveTemplatesOptions,\n): string {\n const templateMap = new Map<string, Template>();\n for (const t of templates) {\n templateMap.set(t.name, t);\n }\n\n const maxDepth = options?.maxDepth ?? 10;\n\n function resolveRecursive(\n currentText: string,\n visited: Set<string>,\n depth: number,\n ): string {\n const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n\n // A function replacer keeps `$&`, `$'` etc. in template bodies literal.\n return currentText.replace(regex, (fullMatch, rawTemplateName: string) => {\n const templateName = rawTemplateName.trim();\n\n if (visited.has(templateName)) {\n return TEMPLATE_LOOP_ERROR;\n }\n\n const template = templateMap.get(templateName);\n if (!template) {\n return fullMatch;\n }\n\n const versionBody = getTemplateBody(template, options?.bindings);\n if (versionBody === undefined) {\n return fullMatch;\n }\n\n if (depth + 1 > maxDepth) {\n return TEMPLATE_DEPTH_ERROR;\n }\n\n const nextVisited = new Set(visited);\n nextVisited.add(templateName);\n\n return resolveRecursive(versionBody, nextVisited, depth + 1);\n });\n }\n\n return resolveRecursive(text, new Set(), 0);\n}\n\n/**\n * Replaces `{variableName}` with values from a dictionary.\n */\nexport function resolveVariables(\n text: string,\n values: Record<string, string | number>,\n): string {\n if (!text) return \"\";\n return text.replace(\n new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags),\n (fullMatch, varName) => {\n const key = varName.trim();\n if (Object.prototype.hasOwnProperty.call(values, key)) {\n return String(values[key]);\n }\n return fullMatch;\n },\n );\n}\n\n/**\n * Extracts unique template names referenced in text.\n */\nexport function extractTemplateNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(match[1].trim());\n }\n return Array.from(set);\n}\n\n/**\n * Extracts unique variable names referenced in text.\n */\nexport function extractVariableNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(match[1].trim());\n }\n return Array.from(set);\n}\n\n/**\n * Extracts unique instruction names referenced in text.\n */\nexport function extractInstructionNames(text: string): string[] {\n if (!text) return [];\n const set = new Set<string>();\n const regex = new RegExp(INSTRUCTION_REGEX.source, INSTRUCTION_REGEX.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n set.add(match[1].trim());\n }\n return Array.from(set);\n}\n","import { TEMPLATE_REGEX, Template } from \"./tokens\";\nimport {\n getTemplateBody,\n resolveTemplates,\n type ResolveTemplatesOptions,\n} from \"./resolver\";\n\nexport interface SourceMapSegment {\n resolvedStart: number;\n resolvedEnd: number;\n source: \"raw\" | \"template\";\n rawStart: number;\n rawEnd: number;\n templateName?: string;\n}\n\n/**\n * Resolves templates in text while tracking character offset mapping\n * between the raw input and the fully resolved output.\n */\nexport function resolveTemplatesWithMapping(\n text: string,\n templates: Template[] = [],\n templateBindings?: Record<string, string>,\n options?: Pick<ResolveTemplatesOptions, \"maxDepth\">,\n): { text: string; map: SourceMapSegment[] } {\n if (!templates || templates.length === 0 || !text.includes(\"{{\")) {\n return {\n text,\n map: [\n {\n resolvedStart: 0,\n resolvedEnd: text.length,\n source: \"raw\",\n rawStart: 0,\n rawEnd: text.length,\n },\n ],\n };\n }\n\n const templateMap = new Map(templates.map((t) => [t.name, t]));\n const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n let lastIndex = 0;\n let resolvedText = \"\";\n const map: SourceMapSegment[] = [];\n\n while ((match = regex.exec(text)) !== null) {\n const [fullMatch, rawTemplateName] = match;\n const templateName = rawTemplateName.trim();\n const matchIndex = match.index;\n\n // Add raw text preceding this template match\n if (matchIndex > lastIndex) {\n const rawSegment = text.substring(lastIndex, matchIndex);\n map.push({\n resolvedStart: resolvedText.length,\n resolvedEnd: resolvedText.length + rawSegment.length,\n source: \"raw\",\n rawStart: lastIndex,\n rawEnd: matchIndex,\n });\n resolvedText += rawSegment;\n }\n\n let resolvedBody = fullMatch;\n let isTemplate = false;\n\n const template = templateMap.get(templateName);\n if (template && getTemplateBody(template, templateBindings) !== undefined) {\n // Resolve the tag itself so loop and depth handling match resolveTemplates.\n resolvedBody = resolveTemplates(fullMatch, templates, {\n bindings: templateBindings,\n maxDepth: options?.maxDepth,\n });\n isTemplate = true;\n }\n\n if (isTemplate) {\n map.push({\n resolvedStart: resolvedText.length,\n resolvedEnd: resolvedText.length + resolvedBody.length,\n source: \"template\",\n rawStart: matchIndex,\n rawEnd: matchIndex + fullMatch.length,\n templateName,\n });\n resolvedText += resolvedBody;\n } else {\n map.push({\n resolvedStart: resolvedText.length,\n resolvedEnd: resolvedText.length + fullMatch.length,\n source: \"raw\",\n rawStart: matchIndex,\n rawEnd: matchIndex + fullMatch.length,\n });\n resolvedText += fullMatch;\n }\n\n lastIndex = matchIndex + fullMatch.length;\n }\n\n // Add any remaining raw text after the final match\n if (lastIndex < text.length) {\n const rawSegment = text.substring(lastIndex);\n map.push({\n resolvedStart: resolvedText.length,\n resolvedEnd: resolvedText.length + rawSegment.length,\n source: \"raw\",\n rawStart: lastIndex,\n rawEnd: text.length,\n });\n resolvedText += rawSegment;\n }\n\n return { text: resolvedText, map };\n}\n\n/**\n * Maps an offset in resolved text back to the corresponding offset in raw text.\n */\nexport function mapResolvedOffsetToRaw(\n resolvedOffset: number,\n map: SourceMapSegment[],\n): number {\n for (let i = 0; i < map.length; i++) {\n const seg = map[i];\n const isLast = i === map.length - 1;\n const inRange = isLast\n ? resolvedOffset >= seg.resolvedStart && resolvedOffset <= seg.resolvedEnd\n : resolvedOffset >= seg.resolvedStart && resolvedOffset < seg.resolvedEnd;\n\n if (inRange) {\n if (seg.source === \"raw\") {\n return seg.rawStart + (resolvedOffset - seg.resolvedStart);\n }\n // The end of the text maps to the end of the tag; anywhere inside a\n // resolved template maps to the start of its tag.\n if (resolvedOffset === seg.resolvedEnd) {\n return seg.rawEnd;\n }\n return seg.rawStart;\n }\n }\n return resolvedOffset;\n}\n\n/**\n * Maps an offset in raw text to the corresponding offset in resolved text.\n */\nexport function mapRawOffsetToResolved(\n rawOffset: number,\n map: SourceMapSegment[],\n): number {\n for (let i = 0; i < map.length; i++) {\n const seg = map[i];\n const isLast = i === map.length - 1;\n const inRange = isLast\n ? rawOffset >= seg.rawStart && rawOffset <= seg.rawEnd\n : rawOffset >= seg.rawStart && rawOffset < seg.rawEnd;\n\n if (inRange) {\n if (seg.source === \"raw\") {\n return seg.resolvedStart + (rawOffset - seg.rawStart);\n }\n if (rawOffset === seg.rawEnd) {\n return seg.resolvedEnd;\n }\n return seg.resolvedStart;\n }\n }\n return rawOffset;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,260 +1,9 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
19
2
 
20
- // src/history/index.ts
21
- var history_exports = {};
22
- __export(history_exports, {
23
- HistoryManager: () => HistoryManager,
24
- createHistoryManager: () => createHistoryManager
25
- });
26
- module.exports = __toCommonJS(history_exports);
27
3
 
28
- // src/history/HistoryManager.ts
29
- var HistoryManager = class {
30
- undoStack = [];
31
- redoStack = [];
32
- maxDepth;
33
- isApplying = false;
34
- batchDepth = 0;
35
- currentBatch = null;
36
- listeners = /* @__PURE__ */ new Set();
37
- onStateChange;
38
- cachedState;
39
- constructor(options = {}) {
40
- this.maxDepth = options.maxDepth ?? 50;
41
- this.onStateChange = options.onStateChange;
42
- this.cachedState = this.computeState();
43
- }
44
- computeState() {
45
- const canUndo = this.undoStack.length > 0;
46
- const canRedo = this.redoStack.length > 0;
47
- return {
48
- canUndo,
49
- canRedo,
50
- undoName: canUndo ? this.undoStack[this.undoStack.length - 1].name : "",
51
- redoName: canRedo ? this.redoStack[this.redoStack.length - 1].name : "",
52
- undoCount: this.undoStack.length,
53
- redoCount: this.redoStack.length
54
- };
55
- }
56
- /**
57
- * Returns a snapshot of the current history state.
58
- * Cached to maintain referential equality across renders for useSyncExternalStore.
59
- */
60
- getState() {
61
- return this.cachedState;
62
- }
63
- notify() {
64
- this.cachedState = this.computeState();
65
- const state = this.cachedState;
66
- this.onStateChange?.(state);
67
- this.listeners.forEach((listener) => {
68
- try {
69
- listener(state);
70
- } catch (err) {
71
- console.error("[HistoryManager] Error in state listener:", err);
72
- }
73
- });
74
- }
75
- /**
76
- * Executes a command and pushes it onto the undo stack.
77
- * Clears the redo stack.
78
- */
79
- execute(command) {
80
- if (this.isApplying) {
81
- command.execute();
82
- return;
83
- }
84
- if (this.batchDepth > 0 && this.currentBatch) {
85
- command.execute();
86
- this.currentBatch.push({
87
- ...command,
88
- timestamp: command.timestamp ?? Date.now()
89
- });
90
- return;
91
- }
92
- command.execute();
93
- this.undoStack.push({
94
- ...command,
95
- timestamp: command.timestamp ?? Date.now()
96
- });
97
- if (this.undoStack.length > this.maxDepth) {
98
- this.undoStack.shift();
99
- }
100
- this.redoStack = [];
101
- this.notify();
102
- }
103
- /**
104
- * Executes a command, coalescing it with the previous command if they share
105
- * the same `tag` and occurred within `windowMs` (default: 300ms).
106
- * Useful for high-frequency interactions like slider scrubs or node drags.
107
- */
108
- executeMerged(command, options = {}) {
109
- const windowMs = options.windowMs ?? 300;
110
- const now = Date.now();
111
- if (command.tag && this.undoStack.length > 0 && this.batchDepth === 0 && !this.isApplying) {
112
- const top = this.undoStack[this.undoStack.length - 1];
113
- const elapsed = top.timestamp ? now - top.timestamp : Infinity;
114
- if (top.tag === command.tag && elapsed <= windowMs) {
115
- command.execute();
116
- const initialUndo = top.undo;
117
- this.undoStack[this.undoStack.length - 1] = {
118
- name: command.name,
119
- tag: command.tag,
120
- timestamp: now,
121
- execute: command.execute,
122
- undo: initialUndo,
123
- redo: command.redo ?? command.execute
124
- };
125
- this.redoStack = [];
126
- this.notify();
127
- return;
128
- }
129
- }
130
- this.execute({ ...command, timestamp: now });
131
- }
132
- /**
133
- * Batches multiple commands executed within `fn` into a single atomic undo entry.
134
- */
135
- batch(name, fn) {
136
- if (this.isApplying) {
137
- fn();
138
- return;
139
- }
140
- if (this.batchDepth > 0) {
141
- fn();
142
- return;
143
- }
144
- this.batchDepth++;
145
- this.currentBatch = [];
146
- try {
147
- fn();
148
- } finally {
149
- this.batchDepth--;
150
- const batchCommands = this.currentBatch;
151
- this.currentBatch = null;
152
- if (batchCommands && batchCommands.length > 0) {
153
- const compoundCommand = {
154
- name,
155
- timestamp: Date.now(),
156
- execute: () => {
157
- for (let i = 0; i < batchCommands.length; i++) {
158
- (batchCommands[i].redo ?? batchCommands[i].execute)();
159
- }
160
- },
161
- undo: () => {
162
- for (let i = batchCommands.length - 1; i >= 0; i--) {
163
- batchCommands[i].undo();
164
- }
165
- },
166
- redo: () => {
167
- for (let i = 0; i < batchCommands.length; i++) {
168
- (batchCommands[i].redo ?? batchCommands[i].execute)();
169
- }
170
- }
171
- };
172
- this.undoStack.push(compoundCommand);
173
- if (this.undoStack.length > this.maxDepth) {
174
- this.undoStack.shift();
175
- }
176
- this.redoStack = [];
177
- this.notify();
178
- }
179
- }
180
- }
181
- /**
182
- * Reverts the most recent command on the undo stack.
183
- * Returns true if a command was undone, false otherwise.
184
- */
185
- undo() {
186
- if (this.undoStack.length === 0 || this.isApplying || this.batchDepth > 0) {
187
- return false;
188
- }
189
- this.isApplying = true;
190
- try {
191
- const command = this.undoStack.pop();
192
- command.undo();
193
- this.redoStack.push(command);
194
- return true;
195
- } finally {
196
- this.isApplying = false;
197
- this.notify();
198
- }
199
- }
200
- /**
201
- * Re-applies the most recent undone command on the redo stack.
202
- * Returns true if a command was redone, false otherwise.
203
- */
204
- redo() {
205
- if (this.redoStack.length === 0 || this.isApplying || this.batchDepth > 0) {
206
- return false;
207
- }
208
- this.isApplying = true;
209
- try {
210
- const command = this.redoStack.pop();
211
- (command.redo ?? command.execute)();
212
- this.undoStack.push(command);
213
- return true;
214
- } finally {
215
- this.isApplying = false;
216
- this.notify();
217
- }
218
- }
219
- /**
220
- * Clears both undo and redo stacks.
221
- */
222
- clear() {
223
- this.undoStack = [];
224
- this.redoStack = [];
225
- this.notify();
226
- }
227
- /**
228
- * Subscribes to history state changes.
229
- * The listener is immediately invoked with the current state.
230
- * Returns an unsubscribe function.
231
- */
232
- subscribe(listener) {
233
- this.listeners.add(listener);
234
- listener(this.getState());
235
- return () => {
236
- this.listeners.delete(listener);
237
- };
238
- }
239
- /**
240
- * Utility helper to create a Command from before/after state snapshots.
241
- */
242
- static createSnapshotCommand(options) {
243
- return {
244
- name: options.name,
245
- tag: options.tag,
246
- execute: () => options.apply(options.after),
247
- undo: () => options.apply(options.before),
248
- redo: () => options.apply(options.after)
249
- };
250
- }
251
- };
252
- function createHistoryManager(options = {}) {
253
- return new HistoryManager(options);
254
- }
255
- // Annotate the CommonJS export names for ESM import in node:
256
- 0 && (module.exports = {
257
- HistoryManager,
258
- createHistoryManager
259
- });
4
+ var _chunk33UVEDOScjs = require('../chunk-33UVEDOS.cjs');
5
+
6
+
7
+
8
+ exports.HistoryManager = _chunk33UVEDOScjs.HistoryManager; exports.createHistoryManager = _chunk33UVEDOScjs.createHistoryManager;
260
9
  //# sourceMappingURL=index.cjs.map