@pixerate/editor 0.1.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.
@@ -0,0 +1,359 @@
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
+ function resolveTemplates(text, templates = [], options) {
120
+ const templateMap = /* @__PURE__ */ new Map();
121
+ for (const t of templates) {
122
+ templateMap.set(t.name, t);
123
+ }
124
+ const maxDepth = options?.maxDepth ?? 10;
125
+ function resolveRecursive(currentText, visited, depth) {
126
+ if (depth > maxDepth) {
127
+ return "[Template max depth exceeded]";
128
+ }
129
+ let result = currentText;
130
+ const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
131
+ let match;
132
+ while ((match = regex.exec(result)) !== null) {
133
+ const [fullMatch, rawTemplateName] = match;
134
+ const templateName = rawTemplateName.trim();
135
+ if (visited.has(templateName)) {
136
+ return "[Template loop detected]";
137
+ }
138
+ const template = templateMap.get(templateName);
139
+ if (!template) {
140
+ continue;
141
+ }
142
+ let versionBody;
143
+ const boundVersionId = options?.bindings?.[templateName];
144
+ if (boundVersionId && template.versions) {
145
+ const boundVersion = template.versions.find(
146
+ (v) => v.id === boundVersionId || v.version === boundVersionId
147
+ );
148
+ versionBody = boundVersion?.body;
149
+ } else {
150
+ const latest = getLatestVersion(template);
151
+ versionBody = latest?.body ?? template.body;
152
+ }
153
+ if (versionBody === void 0) {
154
+ continue;
155
+ }
156
+ const nextVisited = new Set(visited);
157
+ nextVisited.add(templateName);
158
+ const resolvedBody = resolveRecursive(
159
+ versionBody,
160
+ nextVisited,
161
+ depth + 1
162
+ );
163
+ if (resolvedBody === "[Template loop detected]" || resolvedBody === "[Template max depth exceeded]") {
164
+ return resolvedBody;
165
+ }
166
+ result = result.replace(fullMatch, resolvedBody);
167
+ regex.lastIndex = 0;
168
+ }
169
+ return result;
170
+ }
171
+ return resolveRecursive(text, /* @__PURE__ */ new Set(), 0);
172
+ }
173
+ function resolveVariables(text, values) {
174
+ if (!text) return "";
175
+ return text.replace(
176
+ new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags),
177
+ (fullMatch, varName) => {
178
+ const key = varName.trim();
179
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
180
+ return String(values[key]);
181
+ }
182
+ return fullMatch;
183
+ }
184
+ );
185
+ }
186
+ function extractTemplateNames(text) {
187
+ if (!text) return [];
188
+ const set = /* @__PURE__ */ new Set();
189
+ const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);
190
+ let match;
191
+ while ((match = regex.exec(text)) !== null) {
192
+ set.add(match[1].trim());
193
+ }
194
+ return Array.from(set);
195
+ }
196
+ function extractVariableNames(text) {
197
+ if (!text) return [];
198
+ const set = /* @__PURE__ */ new Set();
199
+ const regex = new RegExp(VARIABLE_REGEX.source, VARIABLE_REGEX.flags);
200
+ let match;
201
+ while ((match = regex.exec(text)) !== null) {
202
+ set.add(match[1].trim());
203
+ }
204
+ return Array.from(set);
205
+ }
206
+ function extractInstructionNames(text) {
207
+ if (!text) return [];
208
+ const set = /* @__PURE__ */ new Set();
209
+ const regex = new RegExp(INSTRUCTION_REGEX.source, INSTRUCTION_REGEX.flags);
210
+ let match;
211
+ while ((match = regex.exec(text)) !== null) {
212
+ set.add(match[1].trim());
213
+ }
214
+ return Array.from(set);
215
+ }
216
+
217
+ // src/grammar/sourcemap.ts
218
+ function resolveTemplatesWithMapping(text, templates = [], templateBindings) {
219
+ if (!templates || templates.length === 0 || !text.includes("{{")) {
220
+ return {
221
+ text,
222
+ map: [
223
+ {
224
+ resolvedStart: 0,
225
+ resolvedEnd: text.length,
226
+ source: "raw",
227
+ rawStart: 0,
228
+ rawEnd: text.length
229
+ }
230
+ ]
231
+ };
232
+ }
233
+ const templateMap = new Map(templates.map((t) => [t.name, t]));
234
+ const regex = /{{\s*([^}]+?)\s*}}/g;
235
+ let match;
236
+ let lastIndex = 0;
237
+ let resolvedText = "";
238
+ const map = [];
239
+ while ((match = regex.exec(text)) !== null) {
240
+ const [fullMatch, rawTemplateName] = match;
241
+ const templateName = rawTemplateName.trim();
242
+ const matchIndex = match.index;
243
+ if (matchIndex > lastIndex) {
244
+ const rawSegment = text.substring(lastIndex, matchIndex);
245
+ map.push({
246
+ resolvedStart: resolvedText.length,
247
+ resolvedEnd: resolvedText.length + rawSegment.length,
248
+ source: "raw",
249
+ rawStart: lastIndex,
250
+ rawEnd: matchIndex
251
+ });
252
+ resolvedText += rawSegment;
253
+ }
254
+ let resolvedBody = fullMatch;
255
+ let isTemplate = false;
256
+ if (templateMap.has(templateName)) {
257
+ const template = templateMap.get(templateName);
258
+ let versionBody;
259
+ const boundVersionId = templateBindings?.[templateName];
260
+ if (boundVersionId && template.versions) {
261
+ const boundVersion = template.versions.find(
262
+ (v) => v.id === boundVersionId || v.version === boundVersionId
263
+ );
264
+ versionBody = boundVersion?.body;
265
+ } else {
266
+ const latestVersion = getLatestVersion(template);
267
+ versionBody = latestVersion?.body ?? template.body;
268
+ }
269
+ if (versionBody !== void 0) {
270
+ resolvedBody = resolveTemplates(versionBody, templates, {
271
+ bindings: templateBindings
272
+ });
273
+ isTemplate = true;
274
+ }
275
+ }
276
+ if (isTemplate) {
277
+ map.push({
278
+ resolvedStart: resolvedText.length,
279
+ resolvedEnd: resolvedText.length + resolvedBody.length,
280
+ source: "template",
281
+ rawStart: matchIndex,
282
+ rawEnd: matchIndex + fullMatch.length,
283
+ templateName
284
+ });
285
+ resolvedText += resolvedBody;
286
+ } else {
287
+ map.push({
288
+ resolvedStart: resolvedText.length,
289
+ resolvedEnd: resolvedText.length + fullMatch.length,
290
+ source: "raw",
291
+ rawStart: matchIndex,
292
+ rawEnd: matchIndex + fullMatch.length
293
+ });
294
+ resolvedText += fullMatch;
295
+ }
296
+ lastIndex = matchIndex + fullMatch.length;
297
+ }
298
+ if (lastIndex < text.length) {
299
+ const rawSegment = text.substring(lastIndex);
300
+ map.push({
301
+ resolvedStart: resolvedText.length,
302
+ resolvedEnd: resolvedText.length + rawSegment.length,
303
+ source: "raw",
304
+ rawStart: lastIndex,
305
+ rawEnd: text.length
306
+ });
307
+ resolvedText += rawSegment;
308
+ }
309
+ return { text: resolvedText, map };
310
+ }
311
+ function mapResolvedOffsetToRaw(resolvedOffset, map) {
312
+ for (let i = 0; i < map.length; i++) {
313
+ const seg = map[i];
314
+ const isLast = i === map.length - 1;
315
+ const inRange = isLast ? resolvedOffset >= seg.resolvedStart && resolvedOffset <= seg.resolvedEnd : resolvedOffset >= seg.resolvedStart && resolvedOffset < seg.resolvedEnd;
316
+ if (inRange) {
317
+ if (seg.source === "raw") {
318
+ return seg.rawStart + (resolvedOffset - seg.resolvedStart);
319
+ } else {
320
+ return seg.rawStart;
321
+ }
322
+ }
323
+ }
324
+ return resolvedOffset;
325
+ }
326
+ function mapRawOffsetToResolved(rawOffset, map) {
327
+ for (let i = 0; i < map.length; i++) {
328
+ const seg = map[i];
329
+ const isLast = i === map.length - 1;
330
+ const inRange = isLast ? rawOffset >= seg.rawStart && rawOffset <= seg.rawEnd : rawOffset >= seg.rawStart && rawOffset < seg.rawEnd;
331
+ if (inRange) {
332
+ if (seg.source === "raw") {
333
+ return seg.resolvedStart + (rawOffset - seg.rawStart);
334
+ } else {
335
+ return seg.resolvedStart;
336
+ }
337
+ }
338
+ }
339
+ return rawOffset;
340
+ }
341
+ export {
342
+ INSTRUCTION_REGEX,
343
+ TEMPLATE_REGEX,
344
+ VARIABLE_REGEX,
345
+ extractInstructionNames,
346
+ extractTemplateNames,
347
+ extractVariableNames,
348
+ getLatestVersion,
349
+ instructionRegex,
350
+ mapRawOffsetToResolved,
351
+ mapResolvedOffsetToRaw,
352
+ resolveTemplates,
353
+ resolveTemplatesWithMapping,
354
+ resolveVariables,
355
+ templateRegex,
356
+ tokenizePrompt,
357
+ variableRegex
358
+ };
359
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;\n body: string;\n createdAt?: string;\n}\n\nexport interface Template {\n id?: string;\n name: string;\n body?: string;\n latestVersion?: string;\n versions?: TemplateVersion[];\n color?: string;\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/**\n * Recursively resolves template tags `{{template_name}}` in a given text.\n * Detects circular dependencies and returns \"[Template loop detected]\".\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 if (depth > maxDepth) {\n return \"[Template max depth exceeded]\";\n }\n\n let result = currentText;\n const regex = new RegExp(TEMPLATE_REGEX.source, TEMPLATE_REGEX.flags);\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(result)) !== null) {\n const [fullMatch, rawTemplateName] = match;\n const templateName = rawTemplateName.trim();\n\n if (visited.has(templateName)) {\n return \"[Template loop detected]\";\n }\n\n const template = templateMap.get(templateName);\n if (!template) {\n continue;\n }\n\n let versionBody: string | undefined;\n const boundVersionId = options?.bindings?.[templateName];\n\n if (boundVersionId && template.versions) {\n const boundVersion = template.versions.find(\n (v) => v.id === boundVersionId || v.version === boundVersionId,\n );\n versionBody = boundVersion?.body;\n } else {\n const latest = getLatestVersion(template);\n versionBody = latest?.body ?? template.body;\n }\n\n if (versionBody === undefined) {\n continue;\n }\n\n const nextVisited = new Set(visited);\n nextVisited.add(templateName);\n\n const resolvedBody = resolveRecursive(\n versionBody,\n nextVisited,\n depth + 1,\n );\n\n if (\n resolvedBody === \"[Template loop detected]\" ||\n resolvedBody === \"[Template max depth exceeded]\"\n ) {\n return resolvedBody;\n }\n\n result = result.replace(fullMatch, resolvedBody);\n regex.lastIndex = 0;\n }\n\n return result;\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 } from \"./tokens\";\nimport { getLatestVersion, resolveTemplates } 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): { 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 = /{{\\s*([^}]+?)\\s*}}/g;\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 if (templateMap.has(templateName)) {\n const template = templateMap.get(templateName)!;\n let versionBody: string | undefined;\n const boundVersionId = templateBindings?.[templateName];\n\n if (boundVersionId && template.versions) {\n const boundVersion = template.versions.find(\n (v) => v.id === boundVersionId || v.version === boundVersionId,\n );\n versionBody = boundVersion?.body;\n } else {\n const latestVersion = getLatestVersion(template);\n versionBody = latestVersion?.body ?? template.body;\n }\n\n if (versionBody !== undefined) {\n resolvedBody = resolveTemplates(versionBody, templates, {\n bindings: templateBindings,\n });\n isTemplate = true;\n }\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 } else {\n // Pointing into a resolved template - return start of template tag\n return seg.rawStart;\n }\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 } else {\n return seg.resolvedStart;\n }\n }\n }\n return rawOffset;\n}\n"],"mappings":"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","names":[]}