@orcalang/orca-lang 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.
Files changed (183) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +128 -0
  3. package/dist/auth/index.d.ts +6 -0
  4. package/dist/auth/index.d.ts.map +1 -0
  5. package/dist/auth/index.js +6 -0
  6. package/dist/auth/index.js.map +1 -0
  7. package/dist/auth/lock.d.ts +2 -0
  8. package/dist/auth/lock.d.ts.map +1 -0
  9. package/dist/auth/lock.js +59 -0
  10. package/dist/auth/lock.js.map +1 -0
  11. package/dist/auth/providers/anthropic.d.ts +14 -0
  12. package/dist/auth/providers/anthropic.d.ts.map +1 -0
  13. package/dist/auth/providers/anthropic.js +145 -0
  14. package/dist/auth/providers/anthropic.js.map +1 -0
  15. package/dist/auth/providers/index.d.ts +3 -0
  16. package/dist/auth/providers/index.d.ts.map +1 -0
  17. package/dist/auth/providers/index.js +3 -0
  18. package/dist/auth/providers/index.js.map +1 -0
  19. package/dist/auth/providers/minimax.d.ts +6 -0
  20. package/dist/auth/providers/minimax.d.ts.map +1 -0
  21. package/dist/auth/providers/minimax.js +65 -0
  22. package/dist/auth/providers/minimax.js.map +1 -0
  23. package/dist/auth/refresh.d.ts +8 -0
  24. package/dist/auth/refresh.d.ts.map +1 -0
  25. package/dist/auth/refresh.js +104 -0
  26. package/dist/auth/refresh.js.map +1 -0
  27. package/dist/auth/store.d.ts +11 -0
  28. package/dist/auth/store.d.ts.map +1 -0
  29. package/dist/auth/store.js +63 -0
  30. package/dist/auth/store.js.map +1 -0
  31. package/dist/auth/types.d.ts +51 -0
  32. package/dist/auth/types.d.ts.map +1 -0
  33. package/dist/auth/types.js +2 -0
  34. package/dist/auth/types.js.map +1 -0
  35. package/dist/compiler/mermaid.d.ts +3 -0
  36. package/dist/compiler/mermaid.d.ts.map +1 -0
  37. package/dist/compiler/mermaid.js +86 -0
  38. package/dist/compiler/mermaid.js.map +1 -0
  39. package/dist/compiler/xstate.d.ts +15 -0
  40. package/dist/compiler/xstate.d.ts.map +1 -0
  41. package/dist/compiler/xstate.js +542 -0
  42. package/dist/compiler/xstate.js.map +1 -0
  43. package/dist/config/index.d.ts +3 -0
  44. package/dist/config/index.d.ts.map +1 -0
  45. package/dist/config/index.js +3 -0
  46. package/dist/config/index.js.map +1 -0
  47. package/dist/config/loader.d.ts +4 -0
  48. package/dist/config/loader.d.ts.map +1 -0
  49. package/dist/config/loader.js +109 -0
  50. package/dist/config/loader.js.map +1 -0
  51. package/dist/config/types.d.ts +13 -0
  52. package/dist/config/types.d.ts.map +1 -0
  53. package/dist/config/types.js +8 -0
  54. package/dist/config/types.js.map +1 -0
  55. package/dist/generators/index.d.ts +5 -0
  56. package/dist/generators/index.d.ts.map +1 -0
  57. package/dist/generators/index.js +5 -0
  58. package/dist/generators/index.js.map +1 -0
  59. package/dist/generators/registry.d.ts +12 -0
  60. package/dist/generators/registry.d.ts.map +1 -0
  61. package/dist/generators/registry.js +15 -0
  62. package/dist/generators/registry.js.map +1 -0
  63. package/dist/generators/typescript.d.ts +9 -0
  64. package/dist/generators/typescript.d.ts.map +1 -0
  65. package/dist/generators/typescript.js +55 -0
  66. package/dist/generators/typescript.js.map +1 -0
  67. package/dist/index.d.ts +10 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +630 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/llm/anthropic.d.ts +14 -0
  72. package/dist/llm/anthropic.d.ts.map +1 -0
  73. package/dist/llm/anthropic.js +87 -0
  74. package/dist/llm/anthropic.js.map +1 -0
  75. package/dist/llm/grok.d.ts +13 -0
  76. package/dist/llm/grok.d.ts.map +1 -0
  77. package/dist/llm/grok.js +60 -0
  78. package/dist/llm/grok.js.map +1 -0
  79. package/dist/llm/index.d.ts +11 -0
  80. package/dist/llm/index.d.ts.map +1 -0
  81. package/dist/llm/index.js +23 -0
  82. package/dist/llm/index.js.map +1 -0
  83. package/dist/llm/ollama.d.ts +11 -0
  84. package/dist/llm/ollama.d.ts.map +1 -0
  85. package/dist/llm/ollama.js +51 -0
  86. package/dist/llm/ollama.js.map +1 -0
  87. package/dist/llm/openai.d.ts +13 -0
  88. package/dist/llm/openai.d.ts.map +1 -0
  89. package/dist/llm/openai.js +61 -0
  90. package/dist/llm/openai.js.map +1 -0
  91. package/dist/llm/provider.d.ts +32 -0
  92. package/dist/llm/provider.d.ts.map +1 -0
  93. package/dist/llm/provider.js +2 -0
  94. package/dist/llm/provider.js.map +1 -0
  95. package/dist/parser/ast-to-markdown.d.ts +3 -0
  96. package/dist/parser/ast-to-markdown.d.ts.map +1 -0
  97. package/dist/parser/ast-to-markdown.js +209 -0
  98. package/dist/parser/ast-to-markdown.js.map +1 -0
  99. package/dist/parser/ast.d.ts +183 -0
  100. package/dist/parser/ast.d.ts.map +1 -0
  101. package/dist/parser/ast.js +3 -0
  102. package/dist/parser/ast.js.map +1 -0
  103. package/dist/parser/markdown-parser.d.ts +8 -0
  104. package/dist/parser/markdown-parser.d.ts.map +1 -0
  105. package/dist/parser/markdown-parser.js +838 -0
  106. package/dist/parser/markdown-parser.js.map +1 -0
  107. package/dist/runtime/effects.d.ts +17 -0
  108. package/dist/runtime/effects.d.ts.map +1 -0
  109. package/dist/runtime/effects.js +28 -0
  110. package/dist/runtime/effects.js.map +1 -0
  111. package/dist/runtime/machine.d.ts +8 -0
  112. package/dist/runtime/machine.d.ts.map +1 -0
  113. package/dist/runtime/machine.js +158 -0
  114. package/dist/runtime/machine.js.map +1 -0
  115. package/dist/runtime/types.d.ts +37 -0
  116. package/dist/runtime/types.d.ts.map +1 -0
  117. package/dist/runtime/types.js +3 -0
  118. package/dist/runtime/types.js.map +1 -0
  119. package/dist/skills.d.ts +114 -0
  120. package/dist/skills.d.ts.map +1 -0
  121. package/dist/skills.js +1103 -0
  122. package/dist/skills.js.map +1 -0
  123. package/dist/tools.d.ts +18 -0
  124. package/dist/tools.d.ts.map +1 -0
  125. package/dist/tools.js +124 -0
  126. package/dist/tools.js.map +1 -0
  127. package/dist/verifier/completeness.d.ts +4 -0
  128. package/dist/verifier/completeness.d.ts.map +1 -0
  129. package/dist/verifier/completeness.js +82 -0
  130. package/dist/verifier/completeness.js.map +1 -0
  131. package/dist/verifier/determinism.d.ts +17 -0
  132. package/dist/verifier/determinism.d.ts.map +1 -0
  133. package/dist/verifier/determinism.js +301 -0
  134. package/dist/verifier/determinism.js.map +1 -0
  135. package/dist/verifier/properties.d.ts +6 -0
  136. package/dist/verifier/properties.d.ts.map +1 -0
  137. package/dist/verifier/properties.js +404 -0
  138. package/dist/verifier/properties.js.map +1 -0
  139. package/dist/verifier/structural.d.ts +50 -0
  140. package/dist/verifier/structural.d.ts.map +1 -0
  141. package/dist/verifier/structural.js +692 -0
  142. package/dist/verifier/structural.js.map +1 -0
  143. package/dist/verifier/types.d.ts +40 -0
  144. package/dist/verifier/types.d.ts.map +1 -0
  145. package/dist/verifier/types.js +2 -0
  146. package/dist/verifier/types.js.map +1 -0
  147. package/package.json +49 -0
  148. package/src/auth/index.ts +5 -0
  149. package/src/auth/lock.ts +71 -0
  150. package/src/auth/providers/anthropic.ts +192 -0
  151. package/src/auth/providers/index.ts +17 -0
  152. package/src/auth/providers/minimax.ts +100 -0
  153. package/src/auth/refresh.ts +138 -0
  154. package/src/auth/store.ts +75 -0
  155. package/src/auth/types.ts +62 -0
  156. package/src/compiler/mermaid.ts +109 -0
  157. package/src/compiler/xstate.ts +615 -0
  158. package/src/config/index.ts +2 -0
  159. package/src/config/loader.ts +122 -0
  160. package/src/config/types.ts +21 -0
  161. package/src/generators/index.ts +6 -0
  162. package/src/generators/registry.ts +27 -0
  163. package/src/generators/typescript.ts +67 -0
  164. package/src/index.ts +671 -0
  165. package/src/llm/anthropic.ts +102 -0
  166. package/src/llm/grok.ts +73 -0
  167. package/src/llm/index.ts +29 -0
  168. package/src/llm/ollama.ts +62 -0
  169. package/src/llm/openai.ts +74 -0
  170. package/src/llm/provider.ts +35 -0
  171. package/src/parser/ast-to-markdown.ts +220 -0
  172. package/src/parser/ast.ts +236 -0
  173. package/src/parser/markdown-parser.ts +844 -0
  174. package/src/runtime/effects.ts +48 -0
  175. package/src/runtime/machine.ts +201 -0
  176. package/src/runtime/types.ts +44 -0
  177. package/src/skills.ts +1339 -0
  178. package/src/tools.ts +144 -0
  179. package/src/verifier/completeness.ts +89 -0
  180. package/src/verifier/determinism.ts +328 -0
  181. package/src/verifier/properties.ts +507 -0
  182. package/src/verifier/structural.ts +803 -0
  183. package/src/verifier/types.ts +45 -0
@@ -0,0 +1,838 @@
1
+ // Markdown Parser for Orca (.orca.md files)
2
+ // Two-phase parser: structural markdown → semantic AST
3
+ // Produces identical MachineDef AST as the DSL parser
4
+ function parseMarkdownStructure(source) {
5
+ const lines = source.split('\n');
6
+ const elements = [];
7
+ let i = 0;
8
+ while (i < lines.length) {
9
+ const trimmed = lines[i].trim();
10
+ if (trimmed === '') {
11
+ i++;
12
+ continue;
13
+ }
14
+ // Skip fenced code blocks
15
+ if (trimmed.startsWith('```')) {
16
+ i++;
17
+ while (i < lines.length && !lines[i].trim().startsWith('```'))
18
+ i++;
19
+ if (i < lines.length)
20
+ i++;
21
+ continue;
22
+ }
23
+ // Horizontal rule separator (--- between machines)
24
+ if (trimmed === '---') {
25
+ elements.push({ kind: 'separator', line: i + 1 });
26
+ i++;
27
+ continue;
28
+ }
29
+ // Heading
30
+ const headingMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
31
+ if (headingMatch) {
32
+ elements.push({ kind: 'heading', level: headingMatch[1].length, text: headingMatch[2].trim(), line: i + 1 });
33
+ i++;
34
+ continue;
35
+ }
36
+ // Blockquote
37
+ if (trimmed.startsWith('>')) {
38
+ const quoteLines = [];
39
+ const startLine = i + 1;
40
+ while (i < lines.length && lines[i].trim().startsWith('>')) {
41
+ quoteLines.push(lines[i].trim().replace(/^>\s*/, ''));
42
+ i++;
43
+ }
44
+ elements.push({ kind: 'blockquote', text: quoteLines.join('\n'), line: startLine });
45
+ continue;
46
+ }
47
+ // Table
48
+ if (trimmed.startsWith('|')) {
49
+ const tableLines = [];
50
+ const startLine = i + 1;
51
+ while (i < lines.length && lines[i].trim().startsWith('|')) {
52
+ tableLines.push(lines[i].trim());
53
+ i++;
54
+ }
55
+ if (tableLines.length >= 2) {
56
+ const headers = parseTableRow(tableLines[0]);
57
+ const isSeparator = /^\|[\s\-:|]+\|$/.test(tableLines[1]);
58
+ const dataStart = isSeparator ? 2 : 1;
59
+ const rows = [];
60
+ for (let j = dataStart; j < tableLines.length; j++) {
61
+ rows.push(parseTableRow(tableLines[j]));
62
+ }
63
+ elements.push({ kind: 'table', headers, rows, line: startLine });
64
+ }
65
+ continue;
66
+ }
67
+ // Bullet list
68
+ if (trimmed.startsWith('- ')) {
69
+ const items = [];
70
+ const startLine = i + 1;
71
+ while (i < lines.length && lines[i].trim().startsWith('- ')) {
72
+ items.push(lines[i].trim().substring(2).trim());
73
+ i++;
74
+ }
75
+ elements.push({ kind: 'bullets', items, line: startLine });
76
+ continue;
77
+ }
78
+ // Paragraph (any other text)
79
+ const paraLines = [];
80
+ const startLine = i + 1;
81
+ while (i < lines.length && lines[i].trim() !== '' &&
82
+ !lines[i].trim().startsWith('#') &&
83
+ !lines[i].trim().startsWith('|') &&
84
+ !lines[i].trim().startsWith('>') &&
85
+ !lines[i].trim().startsWith('- ') &&
86
+ !lines[i].trim().startsWith('```')) {
87
+ paraLines.push(lines[i].trim());
88
+ i++;
89
+ }
90
+ if (paraLines.length > 0) {
91
+ elements.push({ kind: 'paragraph', text: paraLines.join('\n'), line: startLine });
92
+ }
93
+ }
94
+ return elements;
95
+ }
96
+ function parseTableRow(line) {
97
+ const cells = line.split('|').map(c => c.trim());
98
+ if (cells.length > 0 && cells[0] === '')
99
+ cells.shift();
100
+ if (cells.length > 0 && cells[cells.length - 1] === '')
101
+ cells.pop();
102
+ return cells;
103
+ }
104
+ // ============================================================
105
+ // Micro-Parsers
106
+ // ============================================================
107
+ function stripBackticks(text) {
108
+ if (text.startsWith('`') && text.endsWith('`'))
109
+ return text.slice(1, -1);
110
+ return text;
111
+ }
112
+ function findColumnIndex(headers, name) {
113
+ return headers.findIndex(h => h.toLowerCase() === name.toLowerCase());
114
+ }
115
+ // --- Type Micro-Parser ---
116
+ function parseTypeString(text) {
117
+ text = text.trim();
118
+ if (text.endsWith('?')) {
119
+ return { kind: 'optional', innerType: text.slice(0, -1) };
120
+ }
121
+ if (text.endsWith('[]')) {
122
+ return { kind: 'array', elementType: text.slice(0, -2) };
123
+ }
124
+ const mapMatch = text.match(/^map<\s*(\w+)\s*,\s*(\w+)\s*>$/);
125
+ if (mapMatch) {
126
+ return { kind: 'map', keyType: mapMatch[1], valueType: mapMatch[2] };
127
+ }
128
+ switch (text) {
129
+ case 'string': return { kind: 'string' };
130
+ case 'int': return { kind: 'int' };
131
+ case 'decimal': return { kind: 'decimal' };
132
+ case 'bool': return { kind: 'bool' };
133
+ default: return { kind: 'custom', name: text };
134
+ }
135
+ }
136
+ function tokenizeExpression(text) {
137
+ const tokens = [];
138
+ let i = 0;
139
+ while (i < text.length) {
140
+ if (/\s/.test(text[i])) {
141
+ i++;
142
+ continue;
143
+ }
144
+ // Two-char operators
145
+ if (i + 1 < text.length) {
146
+ const two = text.slice(i, i + 2);
147
+ if (two === '==') {
148
+ tokens.push({ type: 'EQ', value: '==' });
149
+ i += 2;
150
+ continue;
151
+ }
152
+ if (two === '!=') {
153
+ tokens.push({ type: 'NE', value: '!=' });
154
+ i += 2;
155
+ continue;
156
+ }
157
+ if (two === '<=') {
158
+ tokens.push({ type: 'LE', value: '<=' });
159
+ i += 2;
160
+ continue;
161
+ }
162
+ if (two === '>=') {
163
+ tokens.push({ type: 'GE', value: '>=' });
164
+ i += 2;
165
+ continue;
166
+ }
167
+ if (two === '&&') {
168
+ tokens.push({ type: 'AND', value: '&&' });
169
+ i += 2;
170
+ continue;
171
+ }
172
+ if (two === '||') {
173
+ tokens.push({ type: 'OR', value: '||' });
174
+ i += 2;
175
+ continue;
176
+ }
177
+ }
178
+ const ch = text[i];
179
+ if (ch === '<') {
180
+ tokens.push({ type: 'LT', value: '<' });
181
+ i++;
182
+ continue;
183
+ }
184
+ if (ch === '>') {
185
+ tokens.push({ type: 'GT', value: '>' });
186
+ i++;
187
+ continue;
188
+ }
189
+ if (ch === '!') {
190
+ tokens.push({ type: 'NOT', value: '!' });
191
+ i++;
192
+ continue;
193
+ }
194
+ if (ch === '=') {
195
+ tokens.push({ type: 'EQ', value: '=' });
196
+ i++;
197
+ continue;
198
+ }
199
+ if (ch === '.') {
200
+ tokens.push({ type: 'DOT', value: '.' });
201
+ i++;
202
+ continue;
203
+ }
204
+ if (ch === '(') {
205
+ tokens.push({ type: 'LPAREN', value: '(' });
206
+ i++;
207
+ continue;
208
+ }
209
+ if (ch === ')') {
210
+ tokens.push({ type: 'RPAREN', value: ')' });
211
+ i++;
212
+ continue;
213
+ }
214
+ if (/[0-9]/.test(ch)) {
215
+ let num = '';
216
+ while (i < text.length && /[0-9.]/.test(text[i]))
217
+ num += text[i++];
218
+ tokens.push({ type: 'NUMBER', value: num });
219
+ continue;
220
+ }
221
+ if (ch === '"' || ch === "'") {
222
+ const quote = ch;
223
+ i++;
224
+ let str = '';
225
+ while (i < text.length && text[i] !== quote) {
226
+ if (text[i] === '\\')
227
+ i++;
228
+ str += text[i++];
229
+ }
230
+ if (i < text.length)
231
+ i++;
232
+ tokens.push({ type: 'STRING', value: str });
233
+ continue;
234
+ }
235
+ if (/[a-zA-Z_]/.test(ch)) {
236
+ let ident = '';
237
+ while (i < text.length && /[a-zA-Z0-9_]/.test(text[i]))
238
+ ident += text[i++];
239
+ tokens.push({ type: 'IDENT', value: ident });
240
+ continue;
241
+ }
242
+ i++; // skip unknown
243
+ }
244
+ tokens.push({ type: 'EOF', value: '' });
245
+ return tokens;
246
+ }
247
+ class ExpressionParser {
248
+ tokens;
249
+ pos = 0;
250
+ constructor(tokens) { this.tokens = tokens; }
251
+ peek() { return this.tokens[this.pos] || { type: 'EOF', value: '' }; }
252
+ advance() { return this.tokens[this.pos++] || { type: 'EOF', value: '' }; }
253
+ match(type) {
254
+ if (this.peek().type === type) {
255
+ this.advance();
256
+ return true;
257
+ }
258
+ return false;
259
+ }
260
+ expect(type) {
261
+ const tok = this.advance();
262
+ if (tok.type !== type)
263
+ throw new Error(`Expected ${type}, got ${tok.type} "${tok.value}"`);
264
+ return tok;
265
+ }
266
+ parse() { return this.parseOr(); }
267
+ parseOr() {
268
+ let left = this.parseAnd();
269
+ while (this.peek().type === 'OR' || (this.peek().type === 'IDENT' && this.peek().value === 'or')) {
270
+ this.advance();
271
+ left = { kind: 'or', left, right: this.parseAnd() };
272
+ }
273
+ return left;
274
+ }
275
+ parseAnd() {
276
+ let left = this.parseNot();
277
+ while (this.peek().type === 'AND' || (this.peek().type === 'IDENT' && this.peek().value === 'and')) {
278
+ this.advance();
279
+ left = { kind: 'and', left, right: this.parseNot() };
280
+ }
281
+ return left;
282
+ }
283
+ parseNot() {
284
+ if (this.peek().type === 'NOT' || (this.peek().type === 'IDENT' && this.peek().value === 'not')) {
285
+ this.advance();
286
+ return { kind: 'not', expr: this.parsePrimary() };
287
+ }
288
+ return this.parsePrimary();
289
+ }
290
+ parsePrimary() {
291
+ if (this.match('LPAREN')) {
292
+ const expr = this.parseOr();
293
+ this.expect('RPAREN');
294
+ return expr;
295
+ }
296
+ if (this.peek().type === 'IDENT' && this.peek().value === 'true') {
297
+ this.advance();
298
+ return { kind: 'true' };
299
+ }
300
+ if (this.peek().type === 'IDENT' && this.peek().value === 'false') {
301
+ this.advance();
302
+ return { kind: 'false' };
303
+ }
304
+ const varPath = this.parseVariablePath();
305
+ const op = this.peek().type;
306
+ if (['EQ', 'NE', 'LT', 'GT', 'LE', 'GE'].includes(op)) {
307
+ const opTok = this.advance();
308
+ const cmpOp = { EQ: 'eq', NE: 'ne', LT: 'lt', GT: 'gt', LE: 'le', GE: 'ge' }[opTok.type];
309
+ return { kind: 'compare', op: cmpOp, left: varPath, right: this.parseValue() };
310
+ }
311
+ return { kind: 'nullcheck', expr: varPath, isNull: false };
312
+ }
313
+ parseVariablePath() {
314
+ const parts = [this.expect('IDENT').value];
315
+ while (this.peek().type === 'DOT') {
316
+ this.advance();
317
+ parts.push(this.expect('IDENT').value);
318
+ }
319
+ return { kind: 'variable', path: parts };
320
+ }
321
+ parseValue() {
322
+ const tok = this.peek();
323
+ if (tok.type === 'NUMBER') {
324
+ this.advance();
325
+ return { kind: 'value', type: 'number', value: parseFloat(tok.value) };
326
+ }
327
+ if (tok.type === 'STRING') {
328
+ this.advance();
329
+ return { kind: 'value', type: 'string', value: tok.value };
330
+ }
331
+ if (tok.type === 'IDENT') {
332
+ this.advance();
333
+ if (tok.value === 'null')
334
+ return { kind: 'value', type: 'null', value: null };
335
+ if (tok.value === 'true')
336
+ return { kind: 'value', type: 'boolean', value: true };
337
+ if (tok.value === 'false')
338
+ return { kind: 'value', type: 'boolean', value: false };
339
+ return { kind: 'value', type: 'null', value: tok.value };
340
+ }
341
+ return { kind: 'value', type: 'null', value: null };
342
+ }
343
+ }
344
+ function parseGuardExpressionFromString(text) {
345
+ return new ExpressionParser(tokenizeExpression(text)).parse();
346
+ }
347
+ // --- Action Signature Micro-Parser ---
348
+ function parseActionSignatureFromString(name, text) {
349
+ text = text.trim();
350
+ const parenStart = text.indexOf('(');
351
+ const parenEnd = text.indexOf(')');
352
+ const paramsStr = text.slice(parenStart + 1, parenEnd).trim();
353
+ const parameters = [];
354
+ if (paramsStr) {
355
+ for (const param of paramsStr.split(',')) {
356
+ const paramName = param.trim().split(':')[0].trim();
357
+ if (paramName)
358
+ parameters.push(paramName);
359
+ }
360
+ }
361
+ const afterParen = text.slice(parenEnd + 1).trim();
362
+ const arrowIdx = afterParen.indexOf('->');
363
+ const returnPart = afterParen.slice(arrowIdx + 2).trim();
364
+ let returnType = 'Context';
365
+ let hasEffect = false;
366
+ let effectType;
367
+ const plusIdx = returnPart.indexOf('+');
368
+ if (plusIdx !== -1) {
369
+ returnType = returnPart.slice(0, plusIdx).trim();
370
+ const effectMatch = returnPart.slice(plusIdx + 1).trim().match(/Effect<(\w+)>/);
371
+ if (effectMatch) {
372
+ hasEffect = true;
373
+ effectType = effectMatch[1];
374
+ }
375
+ }
376
+ else {
377
+ returnType = returnPart;
378
+ }
379
+ return { name, parameters, returnType, hasEffect, effectType };
380
+ }
381
+ function parseAnnotations(text) {
382
+ let isInitial = false, isFinal = false, isParallel = false;
383
+ let syncStrategy;
384
+ const bracketMatch = text.match(/\[(.+)\]/);
385
+ if (bracketMatch) {
386
+ for (const part of bracketMatch[1].split(',').map(p => p.trim())) {
387
+ if (part === 'initial')
388
+ isInitial = true;
389
+ else if (part === 'final')
390
+ isFinal = true;
391
+ else if (part === 'parallel')
392
+ isParallel = true;
393
+ else if (part.startsWith('sync:')) {
394
+ const v = part.slice(5).trim();
395
+ if (v === 'all-final' || v === 'all_final')
396
+ syncStrategy = 'all-final';
397
+ else if (v === 'any-final' || v === 'any_final')
398
+ syncStrategy = 'any-final';
399
+ else if (v === 'custom')
400
+ syncStrategy = 'custom';
401
+ }
402
+ }
403
+ }
404
+ return { isInitial, isFinal, isParallel, syncStrategy };
405
+ }
406
+ function parseStateBullet(entry, text) {
407
+ if (text.startsWith('on_entry:')) {
408
+ let val = text.slice(9).trim();
409
+ if (val.startsWith('->'))
410
+ val = val.slice(2).trim();
411
+ entry.onEntry = val;
412
+ }
413
+ else if (text.startsWith('on_exit:')) {
414
+ let val = text.slice(8).trim();
415
+ if (val.startsWith('->'))
416
+ val = val.slice(2).trim();
417
+ entry.onExit = val;
418
+ }
419
+ else if (text.startsWith('timeout:')) {
420
+ const rest = text.slice(8).trim();
421
+ const arrowIdx = rest.indexOf('->');
422
+ if (arrowIdx !== -1) {
423
+ entry.timeout = { duration: rest.slice(0, arrowIdx).trim(), target: rest.slice(arrowIdx + 2).trim() };
424
+ }
425
+ }
426
+ else if (text.startsWith('ignore:')) {
427
+ const names = text.slice(7).trim().split(',').map(e => e.trim()).filter(Boolean);
428
+ if (!entry.ignoredEvents)
429
+ entry.ignoredEvents = [];
430
+ entry.ignoredEvents.push(...names);
431
+ }
432
+ else if (text.startsWith('on_done:')) {
433
+ let val = text.slice(8).trim();
434
+ if (val.startsWith('->'))
435
+ val = val.slice(2).trim();
436
+ if (entry.invoke) {
437
+ entry.invoke.onDone = val;
438
+ }
439
+ // Also set entry.onDone for non-invoke states (like parallel sync on_done)
440
+ entry.onDone = val;
441
+ }
442
+ else if (text.startsWith('on_error:')) {
443
+ let val = text.slice(9).trim();
444
+ if (val.startsWith('->'))
445
+ val = val.slice(2).trim();
446
+ if (entry.invoke) {
447
+ entry.invoke.onError = val;
448
+ }
449
+ else {
450
+ entry._pendingOnError = val;
451
+ }
452
+ }
453
+ else if (text.startsWith('invoke:')) {
454
+ const rest = text.slice(7).trim();
455
+ // Format: "MachineName" or "MachineName input: { field: ctx.field }"
456
+ const inputMatch = rest.match(/^(\w+)\s+input:\s*\{(.+)\}$/);
457
+ const pendingOnError = entry._pendingOnError;
458
+ delete entry._pendingOnError;
459
+ if (inputMatch) {
460
+ const machineName = inputMatch[1];
461
+ const inputStr = inputMatch[2];
462
+ const input = {};
463
+ // Parse { field: ctx.field } into { field: "ctx.field" }
464
+ const pairs = inputStr.split(',').map(p => p.trim());
465
+ for (const pair of pairs) {
466
+ const colonIdx = pair.indexOf(':');
467
+ if (colonIdx !== -1) {
468
+ const key = pair.slice(0, colonIdx).trim();
469
+ const val = pair.slice(colonIdx + 1).trim();
470
+ input[key] = val;
471
+ }
472
+ }
473
+ entry.invoke = { machine: machineName, input, onError: pendingOnError };
474
+ }
475
+ else {
476
+ entry.invoke = { machine: rest, onError: pendingOnError };
477
+ }
478
+ }
479
+ }
480
+ function parsePropertyFromBullet(text) {
481
+ text = text.trim();
482
+ if (text === 'live')
483
+ return { kind: 'live' };
484
+ if (text.startsWith('reachable:') || text.startsWith('unreachable:')) {
485
+ const kind = text.startsWith('reachable:') ? 'reachable' : 'unreachable';
486
+ const rest = text.slice(text.indexOf(':') + 1).trim();
487
+ const parts = rest.split(/\s+from\s+/);
488
+ // Match DSL parser property order: kind, from, to
489
+ return { kind, from: parts[1].trim(), to: parts[0].trim() };
490
+ }
491
+ if (text.startsWith('passes_through:')) {
492
+ const rest = text.slice(15).trim();
493
+ const forParts = rest.split(/\s+for\s+/);
494
+ const through = forParts[0].trim();
495
+ const arrowParts = forParts[1].split(/\s*->\s*/);
496
+ // Match DSL parser property order: from, to, through
497
+ return { kind: 'passes_through', from: arrowParts[0].trim(), to: arrowParts[1].trim(), through };
498
+ }
499
+ if (text.startsWith('responds:')) {
500
+ const rest = text.slice(9).trim();
501
+ const parts = rest.split(/\s+from\s+/);
502
+ const to = parts[0].trim();
503
+ const withinParts = parts[1].split(/\s+within\s+/);
504
+ const from = withinParts[0].trim();
505
+ const within = parseInt(withinParts[1].trim(), 10);
506
+ // Match DSL parser property order: kind, from, to, within
507
+ return { kind: 'responds', from, to, within };
508
+ }
509
+ if (text.startsWith('invariant:')) {
510
+ const rest = text.slice(10).trim();
511
+ const backtickMatch = rest.match(/`([^`]+)`(\s+in\s+(\S+))?/);
512
+ if (backtickMatch) {
513
+ const prop = { kind: 'invariant', expression: parseGuardExpressionFromString(backtickMatch[1]) };
514
+ if (backtickMatch[3])
515
+ prop.inState = backtickMatch[3];
516
+ return prop;
517
+ }
518
+ }
519
+ throw new Error(`Unknown property: ${text}`);
520
+ }
521
+ // --- Context / Events / Transitions / Guards / Actions table parsers ---
522
+ function parseContextTable(table) {
523
+ const fi = findColumnIndex(table.headers, 'field');
524
+ const ti = findColumnIndex(table.headers, 'type');
525
+ const di = findColumnIndex(table.headers, 'default');
526
+ return table.rows.map(row => {
527
+ const field = {
528
+ name: row[fi]?.trim() || '',
529
+ type: parseTypeString(row[ti]?.trim() || 'string'),
530
+ };
531
+ const def = di >= 0 ? row[di]?.trim() : '';
532
+ if (def)
533
+ field.defaultValue = def;
534
+ return field;
535
+ });
536
+ }
537
+ function parseEventsList(list) {
538
+ const events = [];
539
+ for (const item of list.items) {
540
+ for (const name of item.split(',').map(n => n.trim()).filter(Boolean)) {
541
+ events.push({ name });
542
+ }
543
+ }
544
+ return events;
545
+ }
546
+ function parseTransitionsTable(table) {
547
+ const si = findColumnIndex(table.headers, 'source');
548
+ const ei = findColumnIndex(table.headers, 'event');
549
+ const gi = findColumnIndex(table.headers, 'guard');
550
+ const ti = findColumnIndex(table.headers, 'target');
551
+ const ai = findColumnIndex(table.headers, 'action');
552
+ return table.rows.map(row => {
553
+ const source = row[si]?.trim() || '';
554
+ const event = row[ei]?.trim() || '';
555
+ const guardStr = row[gi]?.trim() || '';
556
+ const target = row[ti]?.trim() || '';
557
+ const actionStr = row[ai]?.trim() || '';
558
+ // Build transition with same property order as DSL parser
559
+ const t = { source, event, target };
560
+ if (guardStr) {
561
+ // Insert guard before target to match DSL property order
562
+ const guard = guardStr.startsWith('!')
563
+ ? { name: guardStr.slice(1), negated: true }
564
+ : { name: guardStr, negated: false };
565
+ return { source, event, guard, target, ...(actionStr && actionStr !== '_' ? { action: actionStr } : {}) };
566
+ }
567
+ if (actionStr && actionStr !== '_')
568
+ t.action = actionStr;
569
+ return t;
570
+ });
571
+ }
572
+ function parseGuardsTable(table) {
573
+ const ni = findColumnIndex(table.headers, 'name');
574
+ const ei = findColumnIndex(table.headers, 'expression');
575
+ return table.rows.map(row => ({
576
+ name: row[ni]?.trim() || '',
577
+ expression: parseGuardExpressionFromString(stripBackticks(row[ei]?.trim() || '')),
578
+ }));
579
+ }
580
+ function parseActionsTable(table) {
581
+ const ni = findColumnIndex(table.headers, 'name');
582
+ const si = findColumnIndex(table.headers, 'signature');
583
+ const ei = findColumnIndex(table.headers, 'effect'); // optional separate column
584
+ return table.rows.map(row => {
585
+ const action = parseActionSignatureFromString(row[ni]?.trim() || '', stripBackticks(row[si]?.trim() || ''));
586
+ // If a separate Effect column exists and signature didn't already embed an effect
587
+ if (ei >= 0 && !action.hasEffect) {
588
+ const effectName = row[ei]?.trim() || '';
589
+ if (effectName) {
590
+ action.hasEffect = true;
591
+ action.effectType = effectName;
592
+ }
593
+ }
594
+ return action;
595
+ });
596
+ }
597
+ // --- State Hierarchy Builder ---
598
+ function buildStatesAtLevel(entries, startIdx, level, parentName) {
599
+ const states = [];
600
+ let i = startIdx;
601
+ while (i < entries.length) {
602
+ const entry = entries[i];
603
+ if (entry.level < level)
604
+ break;
605
+ if (entry.type === 'region')
606
+ break;
607
+ if (entry.level > level) {
608
+ i++;
609
+ continue;
610
+ }
611
+ // Build state with same property order as DSL parser:
612
+ // { name, isInitial, isFinal, parent?, description?, onEntry?, onExit?, ... }
613
+ const state = { name: entry.name, isInitial: entry.isInitial, isFinal: entry.isFinal };
614
+ if (parentName)
615
+ state.parent = parentName;
616
+ if (entry.description)
617
+ state.description = entry.description;
618
+ if (entry.onEntry)
619
+ state.onEntry = entry.onEntry;
620
+ if (entry.onExit)
621
+ state.onExit = entry.onExit;
622
+ if (entry.onDone)
623
+ state.onDone = entry.onDone;
624
+ if (entry.timeout)
625
+ state.timeout = entry.timeout;
626
+ if (entry.ignoredEvents?.length)
627
+ state.ignoredEvents = entry.ignoredEvents;
628
+ if (entry.invoke)
629
+ state.invoke = entry.invoke;
630
+ i++;
631
+ if (entry.isParallel) {
632
+ const result = buildParallelRegions(entries, i, level + 1, entry.name, entry.syncStrategy);
633
+ state.parallel = result.parallelDef;
634
+ i = result.nextIdx;
635
+ }
636
+ else if (i < entries.length && entries[i].level === level + 1 && entries[i].type === 'state') {
637
+ const result = buildStatesAtLevel(entries, i, level + 1, entry.name);
638
+ state.contains = result.states;
639
+ i = result.nextIdx;
640
+ }
641
+ states.push(state);
642
+ }
643
+ return { states, nextIdx: i };
644
+ }
645
+ function buildParallelRegions(entries, startIdx, regionLevel, parentName, syncStrategy) {
646
+ const regions = [];
647
+ let i = startIdx;
648
+ while (i < entries.length && entries[i].level >= regionLevel) {
649
+ if (entries[i].type !== 'region' || entries[i].level !== regionLevel)
650
+ break;
651
+ const regionName = entries[i].name;
652
+ i++;
653
+ const regionStates = [];
654
+ while (i < entries.length && entries[i].level > regionLevel) {
655
+ if (entries[i].type === 'state' && entries[i].level === regionLevel + 1) {
656
+ const e = entries[i];
657
+ // Match DSL parser property order: name, isInitial, isFinal, parent, then body props
658
+ const s = {
659
+ name: e.name, isInitial: e.isInitial, isFinal: e.isFinal,
660
+ parent: `${parentName}.${regionName}`,
661
+ };
662
+ if (e.description)
663
+ s.description = e.description;
664
+ if (e.onEntry)
665
+ s.onEntry = e.onEntry;
666
+ if (e.onExit)
667
+ s.onExit = e.onExit;
668
+ if (e.onDone)
669
+ s.onDone = e.onDone;
670
+ if (e.timeout)
671
+ s.timeout = e.timeout;
672
+ if (e.ignoredEvents?.length)
673
+ s.ignoredEvents = e.ignoredEvents;
674
+ if (e.invoke)
675
+ s.invoke = e.invoke;
676
+ regionStates.push(s);
677
+ i++;
678
+ }
679
+ else {
680
+ break;
681
+ }
682
+ }
683
+ regions.push({ name: regionName, states: regionStates });
684
+ }
685
+ return { parallelDef: { regions, sync: syncStrategy }, nextIdx: i };
686
+ }
687
+ // --- Main Semantic Parser ---
688
+ function parseMachineFromElements(elements) {
689
+ let machineName = '';
690
+ let context = [];
691
+ let events = [];
692
+ let transitions = [];
693
+ let guards = [];
694
+ let actions = [];
695
+ let effects;
696
+ let properties;
697
+ const stateEntries = [];
698
+ let currentStateEntry = null;
699
+ for (let i = 0; i < elements.length; i++) {
700
+ const el = elements[i];
701
+ if (el.kind === 'heading') {
702
+ // Machine heading
703
+ if (el.level === 1 && el.text.startsWith('machine ')) {
704
+ machineName = el.text.slice(8).trim();
705
+ currentStateEntry = null;
706
+ continue;
707
+ }
708
+ // Non-state section headings
709
+ const sectionName = el.text.toLowerCase();
710
+ if (['context', 'events', 'transitions', 'guards', 'actions', 'effects', 'properties'].includes(sectionName)) {
711
+ currentStateEntry = null;
712
+ const nextEl = elements[i + 1];
713
+ if (sectionName === 'context' && nextEl?.kind === 'table') {
714
+ context = parseContextTable(nextEl);
715
+ i++;
716
+ }
717
+ else if (sectionName === 'events' && nextEl?.kind === 'bullets') {
718
+ events = parseEventsList(nextEl);
719
+ i++;
720
+ }
721
+ else if (sectionName === 'transitions' && nextEl?.kind === 'table') {
722
+ transitions = parseTransitionsTable(nextEl);
723
+ i++;
724
+ }
725
+ else if (sectionName === 'guards' && nextEl?.kind === 'table') {
726
+ guards = parseGuardsTable(nextEl);
727
+ i++;
728
+ }
729
+ else if (sectionName === 'actions' && nextEl?.kind === 'table') {
730
+ actions = parseActionsTable(nextEl);
731
+ i++;
732
+ }
733
+ else if (sectionName === 'effects' && nextEl?.kind === 'table') {
734
+ effects = parseEffectsTable(nextEl);
735
+ i++;
736
+ }
737
+ else if (sectionName === 'properties' && nextEl?.kind === 'bullets') {
738
+ properties = parsePropertiesList(nextEl);
739
+ i++;
740
+ }
741
+ continue;
742
+ }
743
+ // State heading
744
+ const stateMatch = el.text.match(/^state\s+(\w+)(.*)$/);
745
+ if (stateMatch) {
746
+ currentStateEntry = {
747
+ type: 'state', level: el.level, name: stateMatch[1], line: el.line,
748
+ ...parseAnnotations(stateMatch[2]?.trim() || ''),
749
+ };
750
+ stateEntries.push(currentStateEntry);
751
+ continue;
752
+ }
753
+ // Region heading
754
+ const regionMatch = el.text.match(/^region\s+(\w+)$/);
755
+ if (regionMatch) {
756
+ currentStateEntry = null;
757
+ stateEntries.push({
758
+ type: 'region', level: el.level, name: regionMatch[1], line: el.line,
759
+ isInitial: false, isFinal: false, isParallel: false,
760
+ });
761
+ continue;
762
+ }
763
+ // Unknown heading — close current state
764
+ currentStateEntry = null;
765
+ continue;
766
+ }
767
+ // Content belonging to current state
768
+ if (currentStateEntry) {
769
+ if (el.kind === 'blockquote') {
770
+ currentStateEntry.description = el.text;
771
+ }
772
+ else if (el.kind === 'bullets') {
773
+ for (const item of el.items)
774
+ parseStateBullet(currentStateEntry, item);
775
+ }
776
+ }
777
+ }
778
+ // Build state hierarchy from flat entries
779
+ const baseLevel = stateEntries.length > 0 ? stateEntries[0].level : 2;
780
+ const states = buildStatesAtLevel(stateEntries, 0, baseLevel).states;
781
+ const machine = { name: machineName, context, events, states, transitions, guards, actions };
782
+ if (effects !== undefined)
783
+ machine.effects = effects;
784
+ if (properties && properties.length > 0)
785
+ machine.properties = properties;
786
+ return machine;
787
+ }
788
+ function parseMarkdownSemantic(elements) {
789
+ // Split elements by --- separators for multi-machine files
790
+ const chunks = [];
791
+ let currentChunk = [];
792
+ for (const el of elements) {
793
+ if (el.kind === 'separator') {
794
+ if (currentChunk.length > 0) {
795
+ chunks.push(currentChunk);
796
+ currentChunk = [];
797
+ }
798
+ }
799
+ else {
800
+ currentChunk.push(el);
801
+ }
802
+ }
803
+ if (currentChunk.length > 0) {
804
+ chunks.push(currentChunk);
805
+ }
806
+ // Parse each chunk as a separate machine
807
+ return chunks.map(chunk => parseMachineFromElements(chunk));
808
+ }
809
+ function parseEffectsTable(table) {
810
+ const ni = findColumnIndex(table.headers, 'name');
811
+ const ii = findColumnIndex(table.headers, 'input');
812
+ const oi = findColumnIndex(table.headers, 'output');
813
+ return table.rows.map(row => ({
814
+ name: stripBackticks((ni >= 0 ? row[ni] : '') || '').trim(),
815
+ input: ((ii >= 0 ? row[ii] : '') || '').trim(),
816
+ output: ((oi >= 0 ? row[oi] : '') || '').trim(),
817
+ })).filter(e => e.name !== '');
818
+ }
819
+ function parsePropertiesList(list) {
820
+ return list.items.map(parsePropertyFromBullet);
821
+ }
822
+ // ============================================================
823
+ // Public API
824
+ // ============================================================
825
+ export function parseMarkdown(source) {
826
+ const elements = parseMarkdownStructure(source);
827
+ const machines = parseMarkdownSemantic(elements);
828
+ return { file: { machines }, tokens: [] };
829
+ }
830
+ /**
831
+ * Parse a single-machine markdown source. For multi-machine files, returns the first machine.
832
+ * @deprecated Use parseMarkdown() and access result.file.machines[0] for explicit handling
833
+ */
834
+ export function parseMachine(source) {
835
+ const { file } = parseMarkdown(source);
836
+ return file.machines[0];
837
+ }
838
+ //# sourceMappingURL=markdown-parser.js.map