@elixpo/lixsketch 5.4.7 → 5.5.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 (218) hide show
  1. package/dist/react/AIRenderer-M4LMJ66J.js +1105 -0
  2. package/dist/react/AIRenderer-M4LMJ66J.js.map +7 -0
  3. package/dist/react/Arrow-BJDAXPMH.js +8 -0
  4. package/dist/react/Arrow-BJDAXPMH.js.map +7 -0
  5. package/dist/react/Circle-KPG7TKIX.js +8 -0
  6. package/dist/react/Circle-KPG7TKIX.js.map +7 -0
  7. package/dist/react/CodeShape-K4DIZAIV.js +8 -0
  8. package/dist/react/CodeShape-K4DIZAIV.js.map +7 -0
  9. package/dist/react/CopyPaste-4CKJRHJ3.js +569 -0
  10. package/dist/react/CopyPaste-4CKJRHJ3.js.map +7 -0
  11. package/dist/react/EraserTrail-PA6IQLQN.js +20 -0
  12. package/dist/react/EraserTrail-PA6IQLQN.js.map +7 -0
  13. package/dist/react/EventDispatcher-SRFH6LQZ.js +463 -0
  14. package/dist/react/EventDispatcher-SRFH6LQZ.js.map +7 -0
  15. package/dist/react/Frame-6UR5XPAX.js +10 -0
  16. package/dist/react/Frame-6UR5XPAX.js.map +7 -0
  17. package/dist/react/FreehandStroke-CK24NUT3.js +8 -0
  18. package/dist/react/FreehandStroke-CK24NUT3.js.map +7 -0
  19. package/dist/react/GraphEngine-QE5B2PMR.js +340 -0
  20. package/dist/react/GraphEngine-QE5B2PMR.js.map +7 -0
  21. package/dist/react/GraphMathParser-2WMTY4IE.js +10 -0
  22. package/dist/react/GraphMathParser-2WMTY4IE.js.map +7 -0
  23. package/dist/react/IconShape-KMIA6T2H.js +10 -0
  24. package/dist/react/IconShape-KMIA6T2H.js.map +7 -0
  25. package/dist/react/ImageShape-CHHGBXUQ.js +10 -0
  26. package/dist/react/ImageShape-CHHGBXUQ.js.map +7 -0
  27. package/dist/react/LayerOrder-XCHF4MSS.js +66 -0
  28. package/dist/react/LayerOrder-XCHF4MSS.js.map +7 -0
  29. package/dist/react/Line-2KOQEEGA.js +10 -0
  30. package/dist/react/Line-2KOQEEGA.js.map +7 -0
  31. package/dist/react/LixScriptParser-JYWJX375.js +1033 -0
  32. package/dist/react/LixScriptParser-JYWJX375.js.map +7 -0
  33. package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js +412 -0
  34. package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +7 -0
  35. package/dist/react/MermaidSequenceParser-UKG2NSZY.js +8 -0
  36. package/dist/react/MermaidSequenceParser-UKG2NSZY.js.map +7 -0
  37. package/dist/react/MermaidSequenceRenderer-HPLHY5II.js +387 -0
  38. package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +7 -0
  39. package/dist/react/Rectangle-6FE7RN6W.js +8 -0
  40. package/dist/react/Rectangle-6FE7RN6W.js.map +7 -0
  41. package/dist/react/ResizeCode-WAMDTKSW.js +2 -0
  42. package/dist/react/ResizeCode-WAMDTKSW.js.map +7 -0
  43. package/dist/react/ResizeShapes-LKEQTITP.js +250 -0
  44. package/dist/react/ResizeShapes-LKEQTITP.js.map +7 -0
  45. package/dist/react/SceneSerializer-4U4B24JM.js +739 -0
  46. package/dist/react/SceneSerializer-4U4B24JM.js.map +7 -0
  47. package/dist/react/Selection-VVUHY5YJ.js +34 -0
  48. package/dist/react/Selection-VVUHY5YJ.js.map +7 -0
  49. package/dist/react/SketchEngine-YA4RG3KX.js +413 -0
  50. package/dist/react/SketchEngine-YA4RG3KX.js.map +7 -0
  51. package/dist/react/TextShape-54ZJ66E3.js +8 -0
  52. package/dist/react/TextShape-54ZJ66E3.js.map +7 -0
  53. package/dist/react/UndoRedo-M2JZUBKN.js +30 -0
  54. package/dist/react/UndoRedo-M2JZUBKN.js.map +7 -0
  55. package/dist/react/ZoomPan-U3TXC5AJ.js +186 -0
  56. package/dist/react/ZoomPan-U3TXC5AJ.js.map +7 -0
  57. package/dist/react/arrowTool-CWEMIRXK.js +17 -0
  58. package/dist/react/arrowTool-CWEMIRXK.js.map +7 -0
  59. package/dist/react/boxicons-5JNJQPUP.woff +0 -0
  60. package/dist/react/boxicons-6NVWQSCQ.eot +0 -0
  61. package/dist/react/boxicons-AQ5N6WP7.woff2 +0 -0
  62. package/dist/react/boxicons-GDR4JU3X.ttf +0 -0
  63. package/dist/react/boxicons-NNFHLMOR.svg +1660 -0
  64. package/dist/react/chunk-2OQXI7QB.js +564 -0
  65. package/dist/react/chunk-2OQXI7QB.js.map +7 -0
  66. package/dist/react/chunk-5OUBTHHO.js +187 -0
  67. package/dist/react/chunk-5OUBTHHO.js.map +7 -0
  68. package/dist/react/chunk-6PFXZKL2.js +628 -0
  69. package/dist/react/chunk-6PFXZKL2.js.map +7 -0
  70. package/dist/react/chunk-6SFNWGGZ.js +453 -0
  71. package/dist/react/chunk-6SFNWGGZ.js.map +7 -0
  72. package/dist/react/chunk-7TZSIR6V.js +210 -0
  73. package/dist/react/chunk-7TZSIR6V.js.map +7 -0
  74. package/dist/react/chunk-AJAZC37E.js +662 -0
  75. package/dist/react/chunk-AJAZC37E.js.map +7 -0
  76. package/dist/react/chunk-BU4D2WYQ.js +1213 -0
  77. package/dist/react/chunk-BU4D2WYQ.js.map +7 -0
  78. package/dist/react/chunk-BZE4CEBG.js +747 -0
  79. package/dist/react/chunk-BZE4CEBG.js.map +7 -0
  80. package/dist/react/chunk-CB2RANCB.js +212 -0
  81. package/dist/react/chunk-CB2RANCB.js.map +7 -0
  82. package/dist/react/chunk-DNAG7ML6.js +128 -0
  83. package/dist/react/chunk-DNAG7ML6.js.map +7 -0
  84. package/dist/react/chunk-HZWLPXFN.js +198 -0
  85. package/dist/react/chunk-HZWLPXFN.js.map +7 -0
  86. package/dist/react/chunk-I6HCCIXB.js +572 -0
  87. package/dist/react/chunk-I6HCCIXB.js.map +7 -0
  88. package/dist/react/chunk-IZ5OGWGW.js +235 -0
  89. package/dist/react/chunk-IZ5OGWGW.js.map +7 -0
  90. package/dist/react/chunk-JJCJNLNN.js +1490 -0
  91. package/dist/react/chunk-JJCJNLNN.js.map +7 -0
  92. package/dist/react/chunk-JQ3IRFDP.js +222 -0
  93. package/dist/react/chunk-JQ3IRFDP.js.map +7 -0
  94. package/dist/react/chunk-L5OARZJ7.js +1134 -0
  95. package/dist/react/chunk-L5OARZJ7.js.map +7 -0
  96. package/dist/react/chunk-LHRTXNVE.js +1600 -0
  97. package/dist/react/chunk-LHRTXNVE.js.map +7 -0
  98. package/dist/react/chunk-Q2GA4MBZ.js +1653 -0
  99. package/dist/react/chunk-Q2GA4MBZ.js.map +7 -0
  100. package/dist/react/chunk-QNSE5BAY.js +519 -0
  101. package/dist/react/chunk-QNSE5BAY.js.map +7 -0
  102. package/dist/react/chunk-QXFBG7OM.js +191 -0
  103. package/dist/react/chunk-QXFBG7OM.js.map +7 -0
  104. package/dist/react/chunk-T6ZVV5ZO.js +714 -0
  105. package/dist/react/chunk-T6ZVV5ZO.js.map +7 -0
  106. package/dist/react/chunk-URB6MY46.js +974 -0
  107. package/dist/react/chunk-URB6MY46.js.map +7 -0
  108. package/dist/react/chunk-VN62KLOC.js +931 -0
  109. package/dist/react/chunk-VN62KLOC.js.map +7 -0
  110. package/dist/react/chunk-VQVEPJSA.js +158 -0
  111. package/dist/react/chunk-VQVEPJSA.js.map +7 -0
  112. package/dist/react/chunk-XISEAGBV.js +1632 -0
  113. package/dist/react/chunk-XISEAGBV.js.map +7 -0
  114. package/dist/react/chunk-YKJUBFHE.js +575 -0
  115. package/dist/react/chunk-YKJUBFHE.js.map +7 -0
  116. package/dist/react/circleTool-NUATSEI2.js +14 -0
  117. package/dist/react/circleTool-NUATSEI2.js.map +7 -0
  118. package/dist/react/codeTool-MHCB2FNB.js +38 -0
  119. package/dist/react/codeTool-MHCB2FNB.js.map +7 -0
  120. package/dist/react/eraserTool-2GS2LQCS.js +103 -0
  121. package/dist/react/eraserTool-2GS2LQCS.js.map +7 -0
  122. package/dist/react/frameTool-PWVKKXSP.js +14 -0
  123. package/dist/react/frameTool-PWVKKXSP.js.map +7 -0
  124. package/dist/react/freehandTool-SLYGASVP.js +14 -0
  125. package/dist/react/freehandTool-SLYGASVP.js.map +7 -0
  126. package/dist/react/iconTool-GPZ7O7NH.js +18 -0
  127. package/dist/react/iconTool-GPZ7O7NH.js.map +7 -0
  128. package/dist/react/imageTool-D5R4XGEU.js +15 -0
  129. package/dist/react/imageTool-D5R4XGEU.js.map +7 -0
  130. package/dist/react/index.js +5342 -0
  131. package/dist/react/index.js.map +7 -0
  132. package/dist/react/laserTool-XVMV63AV.js +239 -0
  133. package/dist/react/laserTool-XVMV63AV.js.map +7 -0
  134. package/dist/react/lineTool-WNI5EMZ5.js +14 -0
  135. package/dist/react/lineTool-WNI5EMZ5.js.map +7 -0
  136. package/dist/react/lixCode-OJMVUXXI.ttf +0 -0
  137. package/dist/react/lixDefault-JEAPAUJL.ttf +0 -0
  138. package/dist/react/lixFancy-BPXYM5CQ.ttf +0 -0
  139. package/dist/react/lixFont-CPKEUDVM.woff2 +0 -0
  140. package/dist/react/rectangleTool-U7DZ6ZTA.js +14 -0
  141. package/dist/react/rectangleTool-U7DZ6ZTA.js.map +7 -0
  142. package/dist/react/styles.css +6627 -0
  143. package/dist/react/textTool-M7S6F3VC.js +21 -0
  144. package/dist/react/textTool-M7S6F3VC.js.map +7 -0
  145. package/package.json +39 -5
  146. package/src/EngineShortcuts.js +83 -27
  147. package/src/core/AIRenderer.js +30 -18
  148. package/src/core/GraphEngine.js +64 -41
  149. package/src/core/MermaidFlowchartRenderer.js +153 -88
  150. package/src/core/MermaidSequenceRenderer.js +168 -93
  151. package/src/core/SceneSerializer.js +86 -2
  152. package/src/core/Selection.js +119 -19
  153. package/src/core/UndoRedo.js +82 -15
  154. package/src/core/ZoomPan.js +15 -5
  155. package/src/index.js +14 -1
  156. package/src/react/LixSketchCanvas.jsx +347 -0
  157. package/src/react/components/AppMenu.jsx +475 -0
  158. package/src/react/components/Footer.jsx +85 -0
  159. package/src/react/components/Toolbar.jsx +140 -0
  160. package/src/react/components/canvas/CanvasLoadingOverlay.jsx +76 -0
  161. package/src/react/components/canvas/ContextMenu.jsx +466 -0
  162. package/src/react/components/canvas/FindBar.jsx +177 -0
  163. package/src/react/components/canvas/ImageSourcePicker.jsx +133 -0
  164. package/src/react/components/canvas/MultiSelectActions.jsx +120 -0
  165. package/src/react/components/canvas/SVGCanvas.jsx +145 -0
  166. package/src/react/components/canvas/SaveStatusIndicator.jsx +29 -0
  167. package/src/react/components/modals/CanvasPropertiesModal.jsx +358 -0
  168. package/src/react/components/modals/CommandPalette.jsx +307 -0
  169. package/src/react/components/modals/ExportImageModal.jsx +287 -0
  170. package/src/react/components/modals/GraphModal.jsx +174 -0
  171. package/src/react/components/modals/HelpModal.jsx +208 -0
  172. package/src/react/components/modals/LixScriptModal.jsx +130 -0
  173. package/src/react/components/modals/ShortcutsModal.jsx +125 -0
  174. package/src/react/components/sidebars/ArrowSidebar.jsx +173 -0
  175. package/src/react/components/sidebars/CircleSidebar.jsx +134 -0
  176. package/src/react/components/sidebars/FrameSidebar.jsx +263 -0
  177. package/src/react/components/sidebars/IconSidebar.jsx +279 -0
  178. package/src/react/components/sidebars/ImageSidebar.jsx +69 -0
  179. package/src/react/components/sidebars/LineSidebar.jsx +109 -0
  180. package/src/react/components/sidebars/PaintbrushSidebar.jsx +119 -0
  181. package/src/react/components/sidebars/RectangleSidebar.jsx +165 -0
  182. package/src/react/components/sidebars/ShapeSidebar.jsx +130 -0
  183. package/src/react/components/sidebars/TextSidebar.jsx +174 -0
  184. package/src/react/hooks/inertStores.js +58 -0
  185. package/src/react/hooks/useSketchEngine.js +76 -0
  186. package/src/react/hooks/useTranslation.js +92 -0
  187. package/src/react/index.js +41 -0
  188. package/src/react/store/useSketchStore.js +234 -0
  189. package/src/react/store/useUIStore.js +196 -0
  190. package/src/react/styles/arrowSidebar.css +263 -0
  191. package/src/react/styles/canvasStroke.css +47 -0
  192. package/src/react/styles/canvasTools.css +769 -0
  193. package/src/react/styles/circleSidebar.css +206 -0
  194. package/src/react/styles/fonts/fonts.css +29 -0
  195. package/src/react/styles/fonts/lixCode.ttf +0 -0
  196. package/src/react/styles/fonts/lixDefault.ttf +0 -0
  197. package/src/react/styles/fonts/lixDocs.ttf +0 -0
  198. package/src/react/styles/fonts/lixFancy.ttf +0 -0
  199. package/src/react/styles/fonts/lixFont.woff2 +0 -0
  200. package/src/react/styles/lineSidebar.css +207 -0
  201. package/src/react/styles/paintbrushSidebar.css +247 -0
  202. package/src/react/styles/squareSidebar.css +206 -0
  203. package/src/react/styles/writeText.css +149 -0
  204. package/src/react/styles.css +175 -0
  205. package/src/react/toolsEnum.js +20 -0
  206. package/src/react/utils/toast.js +18 -0
  207. package/src/shapes/Frame.js +7 -1
  208. package/src/shapes/Line.js +11 -5
  209. package/src/tools/arrowTool.js +30 -4
  210. package/src/tools/circleTool.js +33 -9
  211. package/src/tools/codeTool.js +5 -3
  212. package/src/tools/frameTool.js +47 -7
  213. package/src/tools/freehandTool.js +12 -4
  214. package/src/tools/iconTool.js +7 -1
  215. package/src/tools/imageTool.js +7 -1
  216. package/src/tools/lineTool.js +27 -3
  217. package/src/tools/rectangleTool.js +45 -8
  218. package/src/tools/textTool.js +23 -6
@@ -0,0 +1,198 @@
1
+ "use client";
2
+
3
+ // src/core/GraphMathParser.js
4
+ var FUNCTIONS = {
5
+ sin: Math.sin,
6
+ cos: Math.cos,
7
+ tan: Math.tan,
8
+ asin: Math.asin,
9
+ acos: Math.acos,
10
+ atan: Math.atan,
11
+ sqrt: Math.sqrt,
12
+ abs: Math.abs,
13
+ log: Math.log10,
14
+ ln: Math.log,
15
+ exp: Math.exp,
16
+ floor: Math.floor,
17
+ ceil: Math.ceil
18
+ };
19
+ var CONSTANTS = { pi: Math.PI, e: Math.E };
20
+ function tokenize(expr) {
21
+ const tokens = [];
22
+ let i = 0;
23
+ while (i < expr.length) {
24
+ const ch = expr[i];
25
+ if (/\s/.test(ch)) {
26
+ i++;
27
+ continue;
28
+ }
29
+ if ("+-*/^(),".includes(ch)) {
30
+ tokens.push({ type: "op", value: ch });
31
+ i++;
32
+ continue;
33
+ }
34
+ if (/[0-9.]/.test(ch)) {
35
+ let num = "";
36
+ while (i < expr.length && /[0-9.]/.test(expr[i])) {
37
+ num += expr[i];
38
+ i++;
39
+ }
40
+ tokens.push({ type: "num", value: parseFloat(num) });
41
+ continue;
42
+ }
43
+ if (/[a-zA-Z_]/.test(ch)) {
44
+ let name = "";
45
+ while (i < expr.length && /[a-zA-Z_0-9]/.test(expr[i])) {
46
+ name += expr[i];
47
+ i++;
48
+ }
49
+ tokens.push({ type: "id", value: name });
50
+ continue;
51
+ }
52
+ i++;
53
+ }
54
+ return tokens;
55
+ }
56
+ function insertImplicitMul(tokens) {
57
+ const result = [];
58
+ for (let i = 0; i < tokens.length; i++) {
59
+ const t = tokens[i];
60
+ result.push(t);
61
+ if (i + 1 < tokens.length) {
62
+ const next = tokens[i + 1];
63
+ const needsMul = (
64
+ // num followed by id or ( → 2x, 2(x), 2sin(x)
65
+ t.type === "num" && (next.type === "id" || next.value === "(") || // ) followed by ( or id or num → (x)(y), (x)2
66
+ t.value === ")" && (next.type === "num" || next.type === "id" || next.value === "(") || // id followed by ( when id is NOT a function → x(2) means x*2
67
+ t.type === "id" && next.value === "(" && !FUNCTIONS[t.value] || // id/num followed by id → xy means x*y
68
+ t.type === "id" && !FUNCTIONS[t.value] && next.type === "id" || // num followed by num after implicit patterns (rare)
69
+ t.type === "id" && !FUNCTIONS[t.value] && next.type === "num"
70
+ );
71
+ if (needsMul) {
72
+ result.push({ type: "op", value: "*" });
73
+ }
74
+ }
75
+ }
76
+ return result;
77
+ }
78
+ function parse(tokens) {
79
+ let pos = 0;
80
+ function peek() {
81
+ return tokens[pos];
82
+ }
83
+ function consume(expected) {
84
+ const t = tokens[pos];
85
+ if (expected && (!t || t.value !== expected)) return null;
86
+ pos++;
87
+ return t;
88
+ }
89
+ function parseExpr() {
90
+ let left = parseTerm();
91
+ while (peek() && (peek().value === "+" || peek().value === "-")) {
92
+ const op = consume().value;
93
+ const right = parseTerm();
94
+ const l = left, r = right;
95
+ if (op === "+") left = (x) => l(x) + r(x);
96
+ else left = (x) => l(x) - r(x);
97
+ }
98
+ return left;
99
+ }
100
+ function parseTerm() {
101
+ let left = parsePower();
102
+ while (peek() && (peek().value === "*" || peek().value === "/")) {
103
+ const op = consume().value;
104
+ const right = parsePower();
105
+ const l = left, r = right;
106
+ if (op === "*") left = (x) => l(x) * r(x);
107
+ else left = (x) => {
108
+ const d = r(x);
109
+ return d === 0 ? NaN : l(x) / d;
110
+ };
111
+ }
112
+ return left;
113
+ }
114
+ function parsePower() {
115
+ let base = parseUnary();
116
+ if (peek() && peek().value === "^") {
117
+ consume();
118
+ const exp = parsePower();
119
+ const b = base;
120
+ base = (x) => Math.pow(b(x), exp(x));
121
+ }
122
+ return base;
123
+ }
124
+ function parseUnary() {
125
+ if (peek() && peek().value === "-") {
126
+ consume();
127
+ const val = parsePrimary();
128
+ return (x) => -val(x);
129
+ }
130
+ if (peek() && peek().value === "+") {
131
+ consume();
132
+ }
133
+ return parsePrimary();
134
+ }
135
+ function parsePrimary() {
136
+ const t = peek();
137
+ if (!t) return () => NaN;
138
+ if (t.type === "num") {
139
+ consume();
140
+ const v = t.value;
141
+ return () => v;
142
+ }
143
+ if (t.value === "(") {
144
+ consume("(");
145
+ const inner = parseExpr();
146
+ consume(")");
147
+ return inner;
148
+ }
149
+ if (t.type === "id") {
150
+ consume();
151
+ const name = t.value.toLowerCase();
152
+ if (CONSTANTS[name] !== void 0) {
153
+ const v = CONSTANTS[name];
154
+ return () => v;
155
+ }
156
+ if (FUNCTIONS[name] && peek() && peek().value === "(") {
157
+ consume("(");
158
+ const arg = parseExpr();
159
+ consume(")");
160
+ const fn2 = FUNCTIONS[name];
161
+ return (x) => fn2(arg(x));
162
+ }
163
+ if (name === "x") return (x) => x;
164
+ return (x) => x;
165
+ }
166
+ consume();
167
+ return () => NaN;
168
+ }
169
+ const fn = parseExpr();
170
+ return fn;
171
+ }
172
+ function parseExpression(input) {
173
+ if (!input || typeof input !== "string") return null;
174
+ try {
175
+ let expr = input.trim();
176
+ expr = expr.replace(/^[yf]\s*\(?\s*x?\s*\)?\s*=\s*/i, "");
177
+ if (!expr) return null;
178
+ const tokens = tokenize(expr);
179
+ if (tokens.length === 0) return null;
180
+ const withMul = insertImplicitMul(tokens);
181
+ const fn = parse(withMul);
182
+ const test1 = fn(0);
183
+ const test2 = fn(1);
184
+ if (typeof test1 !== "number" && typeof test2 !== "number") return null;
185
+ return fn;
186
+ } catch (e) {
187
+ return null;
188
+ }
189
+ }
190
+ function isValidExpression(input) {
191
+ return parseExpression(input) !== null;
192
+ }
193
+
194
+ export {
195
+ parseExpression,
196
+ isValidExpression
197
+ };
198
+ //# sourceMappingURL=chunk-HZWLPXFN.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/core/GraphMathParser.js"],
4
+ "sourcesContent": ["/* eslint-disable */\n/**\n * GraphMathParser - Parses math expressions into evaluable functions.\n * Supports: +, -, *, /, ^ (power), implicit multiplication (2x, 3sin(x))\n * Functions: sin, cos, tan, asin, acos, atan, sqrt, abs, log, ln, exp, floor, ceil\n * Constants: pi, e\n * Forms: \"y = expr\", \"f(x) = expr\", or just \"expr\"\n */\n\nconst FUNCTIONS = {\n sin: Math.sin, cos: Math.cos, tan: Math.tan,\n asin: Math.asin, acos: Math.acos, atan: Math.atan,\n sqrt: Math.sqrt, abs: Math.abs,\n log: Math.log10, ln: Math.log, exp: Math.exp,\n floor: Math.floor, ceil: Math.ceil,\n};\n\nconst CONSTANTS = { pi: Math.PI, e: Math.E };\n\n// Tokenizer\nfunction tokenize(expr) {\n const tokens = [];\n let i = 0;\n while (i < expr.length) {\n const ch = expr[i];\n if (/\\s/.test(ch)) { i++; continue; }\n if ('+-*/^(),'.includes(ch)) {\n tokens.push({ type: 'op', value: ch });\n i++;\n continue;\n }\n // Number (including decimals)\n if (/[0-9.]/.test(ch)) {\n let num = '';\n while (i < expr.length && /[0-9.]/.test(expr[i])) { num += expr[i]; i++; }\n tokens.push({ type: 'num', value: parseFloat(num) });\n continue;\n }\n // Identifier (variable, function, or constant)\n if (/[a-zA-Z_]/.test(ch)) {\n let name = '';\n while (i < expr.length && /[a-zA-Z_0-9]/.test(expr[i])) { name += expr[i]; i++; }\n tokens.push({ type: 'id', value: name });\n continue;\n }\n i++; // skip unknown chars\n }\n return tokens;\n}\n\n// Insert implicit multiplication tokens\nfunction insertImplicitMul(tokens) {\n const result = [];\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i];\n result.push(t);\n if (i + 1 < tokens.length) {\n const next = tokens[i + 1];\n const needsMul =\n // num followed by id or ( \u2192 2x, 2(x), 2sin(x)\n (t.type === 'num' && (next.type === 'id' || next.value === '(')) ||\n // ) followed by ( or id or num \u2192 (x)(y), (x)2\n (t.value === ')' && (next.type === 'num' || next.type === 'id' || next.value === '(')) ||\n // id followed by ( when id is NOT a function \u2192 x(2) means x*2\n (t.type === 'id' && next.value === '(' && !FUNCTIONS[t.value]) ||\n // id/num followed by id \u2192 xy means x*y\n (t.type === 'id' && !FUNCTIONS[t.value] && next.type === 'id') ||\n // num followed by num after implicit patterns (rare)\n (t.type === 'id' && !FUNCTIONS[t.value] && next.type === 'num');\n if (needsMul) {\n result.push({ type: 'op', value: '*' });\n }\n }\n }\n return result;\n}\n\n// Recursive descent parser \u2192 builds evaluable function tree\nfunction parse(tokens) {\n let pos = 0;\n\n function peek() { return tokens[pos]; }\n function consume(expected) {\n const t = tokens[pos];\n if (expected && (!t || t.value !== expected)) return null;\n pos++;\n return t;\n }\n\n // Expression: term ((+|-) term)*\n function parseExpr() {\n let left = parseTerm();\n while (peek() && (peek().value === '+' || peek().value === '-')) {\n const op = consume().value;\n const right = parseTerm();\n const l = left, r = right;\n if (op === '+') left = (x) => l(x) + r(x);\n else left = (x) => l(x) - r(x);\n }\n return left;\n }\n\n // Term: power ((*|/) power)*\n function parseTerm() {\n let left = parsePower();\n while (peek() && (peek().value === '*' || peek().value === '/')) {\n const op = consume().value;\n const right = parsePower();\n const l = left, r = right;\n if (op === '*') left = (x) => l(x) * r(x);\n else left = (x) => { const d = r(x); return d === 0 ? NaN : l(x) / d; };\n }\n return left;\n }\n\n // Power: unary (^ unary)* (right-associative)\n function parsePower() {\n let base = parseUnary();\n if (peek() && peek().value === '^') {\n consume();\n const exp = parsePower(); // right-associative\n const b = base;\n base = (x) => Math.pow(b(x), exp(x));\n }\n return base;\n }\n\n // Unary: (+|-) primary\n function parseUnary() {\n if (peek() && peek().value === '-') {\n consume();\n const val = parsePrimary();\n return (x) => -val(x);\n }\n if (peek() && peek().value === '+') { consume(); }\n return parsePrimary();\n }\n\n // Primary: number | variable | function(expr) | (expr)\n function parsePrimary() {\n const t = peek();\n if (!t) return () => NaN;\n\n // Number\n if (t.type === 'num') {\n consume();\n const v = t.value;\n return () => v;\n }\n\n // Parenthesized expression\n if (t.value === '(') {\n consume('(');\n const inner = parseExpr();\n consume(')');\n return inner;\n }\n\n // Identifier\n if (t.type === 'id') {\n consume();\n const name = t.value.toLowerCase();\n\n // Constant\n if (CONSTANTS[name] !== undefined) {\n const v = CONSTANTS[name];\n return () => v;\n }\n\n // Function call\n if (FUNCTIONS[name] && peek() && peek().value === '(') {\n consume('(');\n const arg = parseExpr();\n consume(')');\n const fn = FUNCTIONS[name];\n return (x) => fn(arg(x));\n }\n\n // Variable 'x'\n if (name === 'x') return (x) => x;\n\n // Unknown identifier \u2014 treat as x\n return (x) => x;\n }\n\n // Fallback\n consume();\n return () => NaN;\n }\n\n const fn = parseExpr();\n return fn;\n}\n\n/**\n * Parse a math expression string into a callable (x) => y function.\n * Returns null if parsing fails.\n */\nexport function parseExpression(input) {\n if (!input || typeof input !== 'string') return null;\n\n try {\n let expr = input.trim();\n\n // Strip \"y =\" or \"f(x) =\" prefix\n expr = expr.replace(/^[yf]\\s*\\(?\\s*x?\\s*\\)?\\s*=\\s*/i, '');\n if (!expr) return null;\n\n const tokens = tokenize(expr);\n if (tokens.length === 0) return null;\n\n const withMul = insertImplicitMul(tokens);\n const fn = parse(withMul);\n\n // Validate: test with a few x values\n const test1 = fn(0);\n const test2 = fn(1);\n if (typeof test1 !== 'number' && typeof test2 !== 'number') return null;\n\n return fn;\n } catch (e) {\n return null;\n }\n}\n\n/**\n * Validate an expression string \u2014 returns true if parseable.\n */\nexport function isValidExpression(input) {\n return parseExpression(input) !== null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fn"]
7
+ }