@pixerate/editor 0.18.0 → 0.20.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 (118) hide show
  1. package/README.md +91 -2
  2. package/dist/agent/index.cjs +625 -2
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +286 -2
  5. package/dist/agent/index.d.ts +286 -2
  6. package/dist/agent/index.js +624 -1
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/canvas/index.cjs +1240 -22
  9. package/dist/canvas/index.cjs.map +1 -1
  10. package/dist/canvas/index.d.cts +515 -3
  11. package/dist/canvas/index.d.ts +515 -3
  12. package/dist/canvas/index.js +1219 -1
  13. package/dist/canvas/index.js.map +1 -1
  14. package/dist/chunk-3TYMNULT.js +1367 -0
  15. package/dist/chunk-3TYMNULT.js.map +1 -0
  16. package/dist/chunk-4QPLEUL2.cjs +4480 -0
  17. package/dist/chunk-4QPLEUL2.cjs.map +1 -0
  18. package/dist/chunk-4SUNJZWB.cjs +553 -0
  19. package/dist/chunk-4SUNJZWB.cjs.map +1 -0
  20. package/dist/chunk-A7DKIA72.js +2657 -0
  21. package/dist/chunk-A7DKIA72.js.map +1 -0
  22. package/dist/chunk-AXV2ZW34.cjs +118 -0
  23. package/dist/chunk-AXV2ZW34.cjs.map +1 -0
  24. package/dist/chunk-B2ZRLN4S.js +118 -0
  25. package/dist/chunk-B2ZRLN4S.js.map +1 -0
  26. package/dist/chunk-CYFJCKC4.js +4480 -0
  27. package/dist/chunk-CYFJCKC4.js.map +1 -0
  28. package/dist/chunk-GVW4P7BG.js +2706 -0
  29. package/dist/chunk-GVW4P7BG.js.map +1 -0
  30. package/dist/chunk-JACER6TE.cjs +1 -0
  31. package/dist/chunk-JACER6TE.cjs.map +1 -0
  32. package/dist/chunk-JYRIOFEN.cjs +2657 -0
  33. package/dist/chunk-JYRIOFEN.cjs.map +1 -0
  34. package/dist/chunk-KYRZDWM4.js +299 -0
  35. package/dist/chunk-KYRZDWM4.js.map +1 -0
  36. package/dist/chunk-LA7PEGU3.cjs +299 -0
  37. package/dist/chunk-LA7PEGU3.cjs.map +1 -0
  38. package/dist/chunk-N7FG6CBO.js +1 -0
  39. package/dist/chunk-N7FG6CBO.js.map +1 -0
  40. package/dist/chunk-OYXSKQFR.js +553 -0
  41. package/dist/chunk-OYXSKQFR.js.map +1 -0
  42. package/dist/chunk-TVRC4KVT.cjs +1367 -0
  43. package/dist/chunk-TVRC4KVT.cjs.map +1 -0
  44. package/dist/chunk-U6NDQFOK.cjs +2706 -0
  45. package/dist/chunk-U6NDQFOK.cjs.map +1 -0
  46. package/dist/controller-OUdxPY-X.d.cts +754 -0
  47. package/dist/controller-OUdxPY-X.d.ts +754 -0
  48. package/dist/extensions/index.cjs +144 -3
  49. package/dist/extensions/index.cjs.map +1 -1
  50. package/dist/extensions/index.d.cts +9 -144
  51. package/dist/extensions/index.d.ts +9 -144
  52. package/dist/extensions/index.js +145 -4
  53. package/dist/grammar/index.cjs +31 -3
  54. package/dist/grammar/index.cjs.map +1 -1
  55. package/dist/grammar/index.d.cts +239 -19
  56. package/dist/grammar/index.d.ts +239 -19
  57. package/dist/grammar/index.js +31 -3
  58. package/dist/history/index.d.cts +2 -41
  59. package/dist/history/index.d.ts +2 -41
  60. package/dist/image-editor/index.cjs +732 -497
  61. package/dist/image-editor/index.cjs.map +1 -1
  62. package/dist/image-editor/index.d.cts +105 -9
  63. package/dist/image-editor/index.d.ts +105 -9
  64. package/dist/image-editor/index.js +721 -486
  65. package/dist/image-editor/index.js.map +1 -1
  66. package/dist/index-Ng1pG7JE.d.ts +899 -0
  67. package/dist/index-k3mFbPx_.d.cts +899 -0
  68. package/dist/index.cjs +457 -20
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.d.cts +99 -12
  71. package/dist/index.d.ts +99 -12
  72. package/dist/index.js +457 -20
  73. package/dist/index.js.map +1 -1
  74. package/dist/registry-iAHbqkYt.d.cts +128 -0
  75. package/dist/registry-iAHbqkYt.d.ts +128 -0
  76. package/dist/serializers/index.cjs +26 -3
  77. package/dist/serializers/index.cjs.map +1 -1
  78. package/dist/serializers/index.d.cts +119 -6
  79. package/dist/serializers/index.d.ts +119 -6
  80. package/dist/serializers/index.js +24 -1
  81. package/dist/spreadsheet/index.cjs +122 -2
  82. package/dist/spreadsheet/index.cjs.map +1 -1
  83. package/dist/spreadsheet/index.d.cts +371 -313
  84. package/dist/spreadsheet/index.d.ts +371 -313
  85. package/dist/spreadsheet/index.js +127 -7
  86. package/dist/tokens-CyLZmIei.d.cts +76 -0
  87. package/dist/tokens-CyLZmIei.d.ts +76 -0
  88. package/dist/track-changes-G8JcWB8b.d.cts +306 -0
  89. package/dist/track-changes-G8JcWB8b.d.ts +306 -0
  90. package/dist/types-BZgcDsC5.d.cts +42 -0
  91. package/dist/types-BZgcDsC5.d.ts +42 -0
  92. package/dist/{types-JV3S8VeR.d.cts → types-DMe0vFB1.d.cts} +1 -1
  93. package/dist/{types-JV3S8VeR.d.ts → types-DMe0vFB1.d.ts} +1 -1
  94. package/package.json +1 -1
  95. package/dist/chunk-7FWEWE6T.js +0 -1888
  96. package/dist/chunk-7FWEWE6T.js.map +0 -1
  97. package/dist/chunk-AIZUKWTL.js +0 -1715
  98. package/dist/chunk-AIZUKWTL.js.map +0 -1
  99. package/dist/chunk-GLSIZKOX.js +0 -17
  100. package/dist/chunk-GLSIZKOX.js.map +0 -1
  101. package/dist/chunk-LDES3EOS.cjs +0 -1888
  102. package/dist/chunk-LDES3EOS.cjs.map +0 -1
  103. package/dist/chunk-LLUAKTLW.cjs +0 -532
  104. package/dist/chunk-LLUAKTLW.cjs.map +0 -1
  105. package/dist/chunk-MPPXH7U5.cjs +0 -336
  106. package/dist/chunk-MPPXH7U5.cjs.map +0 -1
  107. package/dist/chunk-O7LOPQMH.js +0 -336
  108. package/dist/chunk-O7LOPQMH.js.map +0 -1
  109. package/dist/chunk-QGVMBCT5.js +0 -532
  110. package/dist/chunk-QGVMBCT5.js.map +0 -1
  111. package/dist/chunk-SEDR75VH.cjs +0 -17
  112. package/dist/chunk-SEDR75VH.cjs.map +0 -1
  113. package/dist/chunk-YQCI4CCN.cjs +0 -1715
  114. package/dist/chunk-YQCI4CCN.cjs.map +0 -1
  115. package/dist/mention-Dcevh3ff.d.cts +0 -32
  116. package/dist/mention-Dcevh3ff.d.ts +0 -32
  117. package/dist/tokens-7kRTEtPb.d.cts +0 -39
  118. package/dist/tokens-7kRTEtPb.d.ts +0 -39
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-AXV2ZW34.cjs","../src/grammar/tokens.ts","../src/grammar/variables.ts"],"names":[],"mappings":"AAAA;ACGO,IAAM,eAAA,EAAiB,qBAAA;AAOvB,IAAM,eAAA,EACX,oDAAA;AACK,IAAM,kBAAA,EAAoB,YAAA;AAG1B,IAAM,cAAA,EAAgB,cAAA;AACtB,IAAM,cAAA,EAAgB,cAAA;AACtB,IAAM,iBAAA,EAAmB,iBAAA;ADVhC;AACA;AEQA,IAAM,qBAAA,EAAwD;AAAA,EAC5D,GAAA,EAAK,IAAA;AAAA,EACL,GAAA,EAAK,QAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAMO,SAAS,oBAAA,CAAqB,IAAA,EAAsB;AACzD,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,IAAI,CAAA;AAC1C;AAKO,SAAS,kBAAA,CAAmB,IAAA,EAAsB;AACvD,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,CAAC,EAAA,EAAA,GAAO,CAAA,EAAA,EAAK,EAAE,CAAA,CAAA;AACjD;AAGoE;AACzC,EAAA;AACX,EAAA;AACwB,EAAA;AACnB,IAAA;AACuB,IAAA;AACZ,MAAA;AAC1B,MAAA;AACA,MAAA;AACF,IAAA;AAC4C,IAAA;AACxB,MAAA;AACR,MAAA;AACV,MAAA;AACF,IAAA;AACW,IAAA;AACb,EAAA;AACkB,EAAA;AACX,EAAA;AACT;AAWqE;AACvB,EAAA;AAChC,EAAA;AACuB,IAAA;AACA,IAAA;AACY,MAAA;AAC7C,IAAA;AACF,EAAA;AAE8C,EAAA;AACX,EAAA;AAC3B,IAAA;AACmC,IAAA;AAC3C,EAAA;AAC8B,EAAA;AACe,IAAA;AAC7C,EAAA;AACkC,EAAA;AACU,IAAA;AAC5C,EAAA;AACO,EAAA;AACT;AAM8D;AACf,EAAA;AACb,EAAA;AAClC;AAUsB;AACsB,EAAA;AACjB,EAAA;AACyB,EAAA;AAC/B,EAAA;AACrB;AAME;AAEyC,EAAA;AACJ,EAAA;AACvC;AAuByB;AAC+C,EAAA;AAC7C,EAAA;AAEI,EAAA;AACI,IAAA;AACb,MAAA;AAChB,MAAA;AACF,IAAA;AAC2B,IAAA;AACa,IAAA;AACzB,IAAA;AACS,MAAA;AACtB,MAAA;AACF,IAAA;AAE4C,IAAA;AAClB,MAAA;AAC1B,IAAA;AACuB,IAAA;AACA,IAAA;AACC,IAAA;AACzB,EAAA;AAEyB,EAAA;AACH,IAAA;AACvB,EAAA;AACO,EAAA;AACT;AFzEkD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-AXV2ZW34.cjs","sourcesContent":[null,"/**\n * Canonical regex patterns for prompt editing tokens.\n */\nexport const TEMPLATE_REGEX = /{{\\s*([^}]+?)\\s*}}/g;\n/**\n * `{name}`, `{name|default}`, `{name|default|description}` and the conditional\n * section tags `{?name}`, `{!name}` and `{/name}`. A backslash escapes the next\n * character, so `\\}`, `\\{` and `\\|` can appear inside defaults and descriptions.\n * Without backslashes this matches exactly what the original `[^{}]+` pattern did.\n */\nexport const VARIABLE_REGEX =\n /(?<!\\{)\\{(?!\\})((?:\\\\[\\s\\S]|[^{}\\\\])*\\\\?)\\}(?!\\})/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 =\n | \"template\"\n | \"variable\"\n | \"instruction\"\n | \"conditional\"\n | \"text\";\n\n/**\n * Kind of a conditional section tag: `{?name}` opens a section kept when\n * `name` has a value, `{!name}` opens one kept when it has none, and\n * `{/name}` closes either.\n */\nexport type ConditionalKind = \"if\" | \"unless\" | \"end\";\n\nexport interface Token {\n type: TokenType;\n raw: string;\n /** Trimmed name for templates, variables and conditional tags; content otherwise. */\n value: string;\n start: number;\n end: number;\n /** Variables only: unescaped text after the first `|` (may be empty). */\n defaultValue?: string;\n /** Variables only: unescaped text after the second `|` (fill-in prompt). */\n description?: string;\n /** Conditional tags only. */\n conditional?: ConditionalKind;\n}\n\n/** Values supplied for `{variable}` slots and `{?variable}` conditions. */\nexport type PromptValue = string | number | boolean | null | undefined;\nexport type PromptValues = Record<string, PromptValue>;\n\nexport type PromptDiagnosticCode = \"unclosed-section\" | \"unexpected-close\";\n\n/**\n * A recoverable grammar problem. The offending tag is treated as literal text.\n * Offsets are relative to the text that contained the tag: the input prompt,\n * or the body of `templateName` when set.\n */\nexport interface PromptDiagnostic {\n code: PromptDiagnosticCode;\n message: string;\n /** Variable named by the tag. */\n name: string;\n start: number;\n end: number;\n templateName?: string;\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 type { ConditionalKind, PromptValue, PromptValues } from \"./tokens\";\n\n/** Result of classifying the text between the braces of a `{…}` token. */\nexport type ParsedVariableBody =\n | {\n kind: \"variable\";\n name: string;\n defaultValue?: string;\n description?: string;\n }\n | {\n kind: \"conditional\";\n conditional: ConditionalKind;\n name: string;\n };\n\nconst CONDITIONAL_PREFIXES: Record<string, ConditionalKind> = {\n \"?\": \"if\",\n \"!\": \"unless\",\n \"/\": \"end\",\n};\n\n/**\n * Removes grammar escapes: `\\|`, `\\{`, `\\}` and `\\\\` become the bare character.\n * Any other backslash is kept, so Windows paths and regex-like text survive.\n */\nexport function unescapeVariableText(text: string): string {\n return text.replace(/\\\\([\\\\{}|])/g, \"$1\");\n}\n\n/**\n * Escapes text so it can be embedded as a variable default or description.\n */\nexport function escapeVariableText(text: string): string {\n return text.replace(/[\\\\{}|]/g, (ch) => `\\\\${ch}`);\n}\n\n/** Splits on `|` characters that are not escaped with a backslash. */\nfunction splitUnescapedPipes(body: string, limit: number): string[] {\n const parts: string[] = [];\n let current = \"\";\n for (let i = 0; i < body.length; i++) {\n const ch = body[i];\n if (ch === \"\\\\\" && i + 1 < body.length) {\n current += ch + body[i + 1];\n i++;\n continue;\n }\n if (ch === \"|\" && parts.length < limit - 1) {\n parts.push(current);\n current = \"\";\n continue;\n }\n current += ch;\n }\n parts.push(current);\n return parts;\n}\n\n/**\n * Classifies the inner text of a `{…}` token.\n *\n * - `{?name}`, `{!name}`, `{/name}` are conditional section tags. The name may\n * not contain `|`; otherwise the token is an ordinary variable.\n * - `{name|default|description}` is a variable. Each part is trimmed and\n * unescaped. A default is present whenever a `|` is (it may be empty), and\n * anything after the second unescaped `|` belongs to the description.\n */\nexport function parseVariableBody(inner: string): ParsedVariableBody {\n const prefix = CONDITIONAL_PREFIXES[inner[0]];\n if (prefix) {\n const name = inner.slice(1).trim();\n if (name && !/[|\\\\]/.test(name)) {\n return { kind: \"conditional\", conditional: prefix, name };\n }\n }\n\n const [rawName, rawDefault, rawDescription] = splitUnescapedPipes(inner, 3);\n const parsed: ParsedVariableBody = {\n kind: \"variable\",\n name: unescapeVariableText(rawName.trim()),\n };\n if (rawDefault !== undefined) {\n parsed.defaultValue = unescapeVariableText(rawDefault.trim());\n }\n if (rawDescription !== undefined) {\n parsed.description = unescapeVariableText(rawDescription.trim());\n }\n return parsed;\n}\n\n/**\n * Whether a supplied value counts as \"set\" for a `{?name}` condition:\n * not `null`/`undefined`/`false`, and not blank once stringified.\n */\nexport function isPromptValueSet(value: PromptValue): boolean {\n if (value === null || value === undefined || value === false) return false;\n return String(value).trim() !== \"\";\n}\n\n/**\n * Returns the text a supplied value substitutes, or `undefined` when the\n * variable should fall back to its default. An explicit empty string is a\n * value (it renders as nothing); `null`/`undefined` are not.\n */\nexport function getSuppliedValue(\n values: PromptValues,\n name: string,\n): string | undefined {\n if (!Object.prototype.hasOwnProperty.call(values, name)) return undefined;\n const value = values[name];\n if (value === null || value === undefined) return undefined;\n return String(value);\n}\n\n/** Whether a section opened by `{?name}` / `{!name}` keeps its body. */\nexport function evaluateCondition(\n conditional: Exclude<ConditionalKind, \"end\">,\n name: string,\n values: PromptValues,\n): boolean {\n const set = isPromptValueSet(values[name]);\n return conditional === \"if\" ? set : !set;\n}\n\nexport interface ConditionalTagLike {\n conditional: ConditionalKind;\n name: string;\n}\n\nexport interface ConditionalTagMatch {\n /** Index of the partner tag, or -1 when the tag is unbalanced. */\n partner: number;\n /** Set when unbalanced. */\n error?: \"unclosed-section\" | \"unexpected-close\";\n}\n\n/**\n * Pairs conditional tags given in document order. A close tag pairs with the\n * nearest open tag of the same name; open tags skipped over are reported as\n * unclosed, and a close tag with no open partner as unexpected. Unbalanced tags\n * never throw: callers treat them as literal text. The surviving pairs are\n * always properly nested.\n */\nexport function matchConditionalTags(\n tags: ConditionalTagLike[],\n): ConditionalTagMatch[] {\n const result: ConditionalTagMatch[] = tags.map(() => ({ partner: -1 }));\n const stack: number[] = [];\n\n tags.forEach((tag, index) => {\n if (tag.conditional !== \"end\") {\n stack.push(index);\n return;\n }\n let depth = stack.length - 1;\n while (depth >= 0 && tags[stack[depth]].name !== tag.name) depth--;\n if (depth < 0) {\n result[index].error = \"unexpected-close\";\n return;\n }\n // Everything opened after the partner was never closed.\n for (const skipped of stack.splice(depth + 1)) {\n result[skipped].error = \"unclosed-section\";\n }\n const open = stack.pop()!;\n result[open].partner = index;\n result[index].partner = open;\n });\n\n for (const open of stack) {\n result[open].error = \"unclosed-section\";\n }\n return result;\n}\n"]}
@@ -0,0 +1,118 @@
1
+ // src/grammar/tokens.ts
2
+ var TEMPLATE_REGEX = /{{\s*([^}]+?)\s*}}/g;
3
+ var VARIABLE_REGEX = /(?<!\{)\{(?!\})((?:\\[\s\S]|[^{}\\])*\\?)\}(?!\})/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/variables.ts
10
+ var CONDITIONAL_PREFIXES = {
11
+ "?": "if",
12
+ "!": "unless",
13
+ "/": "end"
14
+ };
15
+ function unescapeVariableText(text) {
16
+ return text.replace(/\\([\\{}|])/g, "$1");
17
+ }
18
+ function escapeVariableText(text) {
19
+ return text.replace(/[\\{}|]/g, (ch) => `\\${ch}`);
20
+ }
21
+ function splitUnescapedPipes(body, limit) {
22
+ const parts = [];
23
+ let current = "";
24
+ for (let i = 0; i < body.length; i++) {
25
+ const ch = body[i];
26
+ if (ch === "\\" && i + 1 < body.length) {
27
+ current += ch + body[i + 1];
28
+ i++;
29
+ continue;
30
+ }
31
+ if (ch === "|" && parts.length < limit - 1) {
32
+ parts.push(current);
33
+ current = "";
34
+ continue;
35
+ }
36
+ current += ch;
37
+ }
38
+ parts.push(current);
39
+ return parts;
40
+ }
41
+ function parseVariableBody(inner) {
42
+ const prefix = CONDITIONAL_PREFIXES[inner[0]];
43
+ if (prefix) {
44
+ const name = inner.slice(1).trim();
45
+ if (name && !/[|\\]/.test(name)) {
46
+ return { kind: "conditional", conditional: prefix, name };
47
+ }
48
+ }
49
+ const [rawName, rawDefault, rawDescription] = splitUnescapedPipes(inner, 3);
50
+ const parsed = {
51
+ kind: "variable",
52
+ name: unescapeVariableText(rawName.trim())
53
+ };
54
+ if (rawDefault !== void 0) {
55
+ parsed.defaultValue = unescapeVariableText(rawDefault.trim());
56
+ }
57
+ if (rawDescription !== void 0) {
58
+ parsed.description = unescapeVariableText(rawDescription.trim());
59
+ }
60
+ return parsed;
61
+ }
62
+ function isPromptValueSet(value) {
63
+ if (value === null || value === void 0 || value === false) return false;
64
+ return String(value).trim() !== "";
65
+ }
66
+ function getSuppliedValue(values, name) {
67
+ if (!Object.prototype.hasOwnProperty.call(values, name)) return void 0;
68
+ const value = values[name];
69
+ if (value === null || value === void 0) return void 0;
70
+ return String(value);
71
+ }
72
+ function evaluateCondition(conditional, name, values) {
73
+ const set = isPromptValueSet(values[name]);
74
+ return conditional === "if" ? set : !set;
75
+ }
76
+ function matchConditionalTags(tags) {
77
+ const result = tags.map(() => ({ partner: -1 }));
78
+ const stack = [];
79
+ tags.forEach((tag, index) => {
80
+ if (tag.conditional !== "end") {
81
+ stack.push(index);
82
+ return;
83
+ }
84
+ let depth = stack.length - 1;
85
+ while (depth >= 0 && tags[stack[depth]].name !== tag.name) depth--;
86
+ if (depth < 0) {
87
+ result[index].error = "unexpected-close";
88
+ return;
89
+ }
90
+ for (const skipped of stack.splice(depth + 1)) {
91
+ result[skipped].error = "unclosed-section";
92
+ }
93
+ const open = stack.pop();
94
+ result[open].partner = index;
95
+ result[index].partner = open;
96
+ });
97
+ for (const open of stack) {
98
+ result[open].error = "unclosed-section";
99
+ }
100
+ return result;
101
+ }
102
+
103
+ export {
104
+ TEMPLATE_REGEX,
105
+ VARIABLE_REGEX,
106
+ INSTRUCTION_REGEX,
107
+ templateRegex,
108
+ variableRegex,
109
+ instructionRegex,
110
+ unescapeVariableText,
111
+ escapeVariableText,
112
+ parseVariableBody,
113
+ isPromptValueSet,
114
+ getSuppliedValue,
115
+ evaluateCondition,
116
+ matchConditionalTags
117
+ };
118
+ //# sourceMappingURL=chunk-B2ZRLN4S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/grammar/tokens.ts","../src/grammar/variables.ts"],"sourcesContent":["/**\n * Canonical regex patterns for prompt editing tokens.\n */\nexport const TEMPLATE_REGEX = /{{\\s*([^}]+?)\\s*}}/g;\n/**\n * `{name}`, `{name|default}`, `{name|default|description}` and the conditional\n * section tags `{?name}`, `{!name}` and `{/name}`. A backslash escapes the next\n * character, so `\\}`, `\\{` and `\\|` can appear inside defaults and descriptions.\n * Without backslashes this matches exactly what the original `[^{}]+` pattern did.\n */\nexport const VARIABLE_REGEX =\n /(?<!\\{)\\{(?!\\})((?:\\\\[\\s\\S]|[^{}\\\\])*\\\\?)\\}(?!\\})/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 =\n | \"template\"\n | \"variable\"\n | \"instruction\"\n | \"conditional\"\n | \"text\";\n\n/**\n * Kind of a conditional section tag: `{?name}` opens a section kept when\n * `name` has a value, `{!name}` opens one kept when it has none, and\n * `{/name}` closes either.\n */\nexport type ConditionalKind = \"if\" | \"unless\" | \"end\";\n\nexport interface Token {\n type: TokenType;\n raw: string;\n /** Trimmed name for templates, variables and conditional tags; content otherwise. */\n value: string;\n start: number;\n end: number;\n /** Variables only: unescaped text after the first `|` (may be empty). */\n defaultValue?: string;\n /** Variables only: unescaped text after the second `|` (fill-in prompt). */\n description?: string;\n /** Conditional tags only. */\n conditional?: ConditionalKind;\n}\n\n/** Values supplied for `{variable}` slots and `{?variable}` conditions. */\nexport type PromptValue = string | number | boolean | null | undefined;\nexport type PromptValues = Record<string, PromptValue>;\n\nexport type PromptDiagnosticCode = \"unclosed-section\" | \"unexpected-close\";\n\n/**\n * A recoverable grammar problem. The offending tag is treated as literal text.\n * Offsets are relative to the text that contained the tag: the input prompt,\n * or the body of `templateName` when set.\n */\nexport interface PromptDiagnostic {\n code: PromptDiagnosticCode;\n message: string;\n /** Variable named by the tag. */\n name: string;\n start: number;\n end: number;\n templateName?: string;\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 type { ConditionalKind, PromptValue, PromptValues } from \"./tokens\";\n\n/** Result of classifying the text between the braces of a `{…}` token. */\nexport type ParsedVariableBody =\n | {\n kind: \"variable\";\n name: string;\n defaultValue?: string;\n description?: string;\n }\n | {\n kind: \"conditional\";\n conditional: ConditionalKind;\n name: string;\n };\n\nconst CONDITIONAL_PREFIXES: Record<string, ConditionalKind> = {\n \"?\": \"if\",\n \"!\": \"unless\",\n \"/\": \"end\",\n};\n\n/**\n * Removes grammar escapes: `\\|`, `\\{`, `\\}` and `\\\\` become the bare character.\n * Any other backslash is kept, so Windows paths and regex-like text survive.\n */\nexport function unescapeVariableText(text: string): string {\n return text.replace(/\\\\([\\\\{}|])/g, \"$1\");\n}\n\n/**\n * Escapes text so it can be embedded as a variable default or description.\n */\nexport function escapeVariableText(text: string): string {\n return text.replace(/[\\\\{}|]/g, (ch) => `\\\\${ch}`);\n}\n\n/** Splits on `|` characters that are not escaped with a backslash. */\nfunction splitUnescapedPipes(body: string, limit: number): string[] {\n const parts: string[] = [];\n let current = \"\";\n for (let i = 0; i < body.length; i++) {\n const ch = body[i];\n if (ch === \"\\\\\" && i + 1 < body.length) {\n current += ch + body[i + 1];\n i++;\n continue;\n }\n if (ch === \"|\" && parts.length < limit - 1) {\n parts.push(current);\n current = \"\";\n continue;\n }\n current += ch;\n }\n parts.push(current);\n return parts;\n}\n\n/**\n * Classifies the inner text of a `{…}` token.\n *\n * - `{?name}`, `{!name}`, `{/name}` are conditional section tags. The name may\n * not contain `|`; otherwise the token is an ordinary variable.\n * - `{name|default|description}` is a variable. Each part is trimmed and\n * unescaped. A default is present whenever a `|` is (it may be empty), and\n * anything after the second unescaped `|` belongs to the description.\n */\nexport function parseVariableBody(inner: string): ParsedVariableBody {\n const prefix = CONDITIONAL_PREFIXES[inner[0]];\n if (prefix) {\n const name = inner.slice(1).trim();\n if (name && !/[|\\\\]/.test(name)) {\n return { kind: \"conditional\", conditional: prefix, name };\n }\n }\n\n const [rawName, rawDefault, rawDescription] = splitUnescapedPipes(inner, 3);\n const parsed: ParsedVariableBody = {\n kind: \"variable\",\n name: unescapeVariableText(rawName.trim()),\n };\n if (rawDefault !== undefined) {\n parsed.defaultValue = unescapeVariableText(rawDefault.trim());\n }\n if (rawDescription !== undefined) {\n parsed.description = unescapeVariableText(rawDescription.trim());\n }\n return parsed;\n}\n\n/**\n * Whether a supplied value counts as \"set\" for a `{?name}` condition:\n * not `null`/`undefined`/`false`, and not blank once stringified.\n */\nexport function isPromptValueSet(value: PromptValue): boolean {\n if (value === null || value === undefined || value === false) return false;\n return String(value).trim() !== \"\";\n}\n\n/**\n * Returns the text a supplied value substitutes, or `undefined` when the\n * variable should fall back to its default. An explicit empty string is a\n * value (it renders as nothing); `null`/`undefined` are not.\n */\nexport function getSuppliedValue(\n values: PromptValues,\n name: string,\n): string | undefined {\n if (!Object.prototype.hasOwnProperty.call(values, name)) return undefined;\n const value = values[name];\n if (value === null || value === undefined) return undefined;\n return String(value);\n}\n\n/** Whether a section opened by `{?name}` / `{!name}` keeps its body. */\nexport function evaluateCondition(\n conditional: Exclude<ConditionalKind, \"end\">,\n name: string,\n values: PromptValues,\n): boolean {\n const set = isPromptValueSet(values[name]);\n return conditional === \"if\" ? set : !set;\n}\n\nexport interface ConditionalTagLike {\n conditional: ConditionalKind;\n name: string;\n}\n\nexport interface ConditionalTagMatch {\n /** Index of the partner tag, or -1 when the tag is unbalanced. */\n partner: number;\n /** Set when unbalanced. */\n error?: \"unclosed-section\" | \"unexpected-close\";\n}\n\n/**\n * Pairs conditional tags given in document order. A close tag pairs with the\n * nearest open tag of the same name; open tags skipped over are reported as\n * unclosed, and a close tag with no open partner as unexpected. Unbalanced tags\n * never throw: callers treat them as literal text. The surviving pairs are\n * always properly nested.\n */\nexport function matchConditionalTags(\n tags: ConditionalTagLike[],\n): ConditionalTagMatch[] {\n const result: ConditionalTagMatch[] = tags.map(() => ({ partner: -1 }));\n const stack: number[] = [];\n\n tags.forEach((tag, index) => {\n if (tag.conditional !== \"end\") {\n stack.push(index);\n return;\n }\n let depth = stack.length - 1;\n while (depth >= 0 && tags[stack[depth]].name !== tag.name) depth--;\n if (depth < 0) {\n result[index].error = \"unexpected-close\";\n return;\n }\n // Everything opened after the partner was never closed.\n for (const skipped of stack.splice(depth + 1)) {\n result[skipped].error = \"unclosed-section\";\n }\n const open = stack.pop()!;\n result[open].partner = index;\n result[index].partner = open;\n });\n\n for (const open of stack) {\n result[open].error = \"unclosed-section\";\n }\n return result;\n}\n"],"mappings":"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","names":[]}