@mmapp/player-core 0.1.0-alpha.1

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 (63) hide show
  1. package/dist/index.d.mts +1436 -0
  2. package/dist/index.d.ts +1436 -0
  3. package/dist/index.js +4828 -0
  4. package/dist/index.mjs +4762 -0
  5. package/package.json +35 -0
  6. package/package.json.backup +35 -0
  7. package/src/__tests__/actions.test.ts +187 -0
  8. package/src/__tests__/blueprint-e2e.test.ts +706 -0
  9. package/src/__tests__/blueprint-test-runner.test.ts +680 -0
  10. package/src/__tests__/core-functions.test.ts +78 -0
  11. package/src/__tests__/dsl-compiler.test.ts +1382 -0
  12. package/src/__tests__/dsl-grammar.test.ts +1682 -0
  13. package/src/__tests__/events.test.ts +200 -0
  14. package/src/__tests__/expression.test.ts +296 -0
  15. package/src/__tests__/failure-policies.test.ts +110 -0
  16. package/src/__tests__/frontend-context.test.ts +182 -0
  17. package/src/__tests__/integration.test.ts +256 -0
  18. package/src/__tests__/security.test.ts +190 -0
  19. package/src/__tests__/state-machine.test.ts +450 -0
  20. package/src/__tests__/testing-engine.test.ts +671 -0
  21. package/src/actions/dispatcher.ts +80 -0
  22. package/src/actions/index.ts +7 -0
  23. package/src/actions/types.ts +25 -0
  24. package/src/dsl/compiler/component-mapper.ts +289 -0
  25. package/src/dsl/compiler/field-mapper.ts +187 -0
  26. package/src/dsl/compiler/index.ts +82 -0
  27. package/src/dsl/compiler/manifest-compiler.ts +76 -0
  28. package/src/dsl/compiler/symbol-table.ts +214 -0
  29. package/src/dsl/compiler/utils.ts +48 -0
  30. package/src/dsl/compiler/view-compiler.ts +286 -0
  31. package/src/dsl/compiler/workflow-compiler.ts +600 -0
  32. package/src/dsl/index.ts +66 -0
  33. package/src/dsl/ir-migration.ts +221 -0
  34. package/src/dsl/ir-types.ts +416 -0
  35. package/src/dsl/lexer.ts +579 -0
  36. package/src/dsl/parser.ts +115 -0
  37. package/src/dsl/types.ts +256 -0
  38. package/src/events/event-bus.ts +68 -0
  39. package/src/events/index.ts +9 -0
  40. package/src/events/pattern-matcher.ts +61 -0
  41. package/src/events/types.ts +27 -0
  42. package/src/expression/evaluator.ts +676 -0
  43. package/src/expression/functions.ts +214 -0
  44. package/src/expression/index.ts +13 -0
  45. package/src/expression/types.ts +64 -0
  46. package/src/index.ts +61 -0
  47. package/src/state-machine/index.ts +16 -0
  48. package/src/state-machine/interpreter.ts +319 -0
  49. package/src/state-machine/types.ts +89 -0
  50. package/src/testing/action-trace.ts +209 -0
  51. package/src/testing/blueprint-test-runner.ts +214 -0
  52. package/src/testing/graph-walker.ts +249 -0
  53. package/src/testing/index.ts +69 -0
  54. package/src/testing/nrt-comparator.ts +199 -0
  55. package/src/testing/nrt-types.ts +230 -0
  56. package/src/testing/test-actions.ts +645 -0
  57. package/src/testing/test-compiler.ts +278 -0
  58. package/src/testing/test-runner.ts +444 -0
  59. package/src/testing/types.ts +231 -0
  60. package/src/validation/definition-validator.ts +812 -0
  61. package/src/validation/index.ts +13 -0
  62. package/tsconfig.json +26 -0
  63. package/vitest.config.ts +8 -0
@@ -0,0 +1,600 @@
1
+ /**
2
+ * Workflow Compiler — Pass 2 of compilation.
3
+ *
4
+ * Transforms ThingSymbol → IRWorkflowDefinition.
5
+ * Handles states, transitions, fields, roles, events, and expressions.
6
+ */
7
+
8
+ import type { ASTNode } from '../types';
9
+ import type {
10
+ IRWorkflowDefinition,
11
+ IRStateDefinition,
12
+ IRTransitionDefinition,
13
+ IRFieldDefinition,
14
+ IRActionDefinition,
15
+ IRConditionDefinition,
16
+ IROnEventSubscription,
17
+ IROnEventAction,
18
+ IRRoleDefinition,
19
+ IRStateType,
20
+ CompilerError,
21
+ } from '../ir-types';
22
+ import type { SymbolTable, ThingSymbol } from './symbol-table';
23
+ import { mapField } from './field-mapper';
24
+ import { slugify, snakeCase, generateActionId } from './utils';
25
+
26
+ // =============================================================================
27
+ // Public API
28
+ // =============================================================================
29
+
30
+ export function compileWorkflows(
31
+ symbols: SymbolTable,
32
+ ): { workflows: IRWorkflowDefinition[]; errors: CompilerError[] } {
33
+ const workflows: IRWorkflowDefinition[] = [];
34
+ const errors: CompilerError[] = [];
35
+
36
+ for (const [, thing] of symbols.things) {
37
+ const { workflow, errors: wfErrors } = compileThing(thing);
38
+ workflows.push(workflow);
39
+ errors.push(...wfErrors);
40
+ }
41
+
42
+ return { workflows, errors };
43
+ }
44
+
45
+ // =============================================================================
46
+ // Thing → Workflow
47
+ // =============================================================================
48
+
49
+ function compileThing(
50
+ thing: ThingSymbol,
51
+ ): { workflow: IRWorkflowDefinition; errors: CompilerError[] } {
52
+ const errors: CompilerError[] = [];
53
+ const slug = slugify(thing.name);
54
+
55
+ // Collect field names for expression resolution
56
+ const fieldNames = new Set(
57
+ thing.fields.map(f => {
58
+ const fd = f.token.data;
59
+ return fd.type === 'field_def' ? fd.name : '';
60
+ }).filter(Boolean),
61
+ );
62
+
63
+ // Compile fields
64
+ const fields = compileFields(thing.fields);
65
+
66
+ // Compile states
67
+ const stateNames = new Set(
68
+ thing.states.map(s => {
69
+ const sd = s.token.data;
70
+ return sd.type === 'state_decl' ? sd.name : '';
71
+ }).filter(Boolean),
72
+ );
73
+
74
+ const states = compileStates(thing, fieldNames);
75
+
76
+ // Compile transitions
77
+ const transitions = compileTransitions(thing, fieldNames, stateNames, errors);
78
+
79
+ // Collect roles from transition guards
80
+ const roles = collectRoles(thing);
81
+
82
+ // Validate starts_at
83
+ if (!thing.startsAt) {
84
+ errors.push({
85
+ code: 'MISSING_STARTS_AT',
86
+ message: `Workflow "${thing.name}" has no starts_at declaration`,
87
+ lineNumber: thing.node.token.lineNumber,
88
+ severity: 'error',
89
+ });
90
+ }
91
+
92
+ // Tags
93
+ const tags = thing.tags.length > 0
94
+ ? thing.tags.map(t => ({ tag_name: t }))
95
+ : undefined;
96
+
97
+ // Metadata (levels)
98
+ let metadata: Record<string, unknown> | undefined;
99
+ if (thing.levels.length > 0) {
100
+ metadata = {
101
+ levels: thing.levels.map(l => {
102
+ const ld = l.token.data;
103
+ if (ld.type === 'level_def') {
104
+ return { level: ld.level, title: ld.title, fromXp: ld.fromXp };
105
+ }
106
+ return null;
107
+ }).filter(Boolean),
108
+ };
109
+ }
110
+
111
+ return {
112
+ workflow: {
113
+ slug,
114
+ name: thing.name,
115
+ version: thing.version,
116
+ category: 'blueprint',
117
+ states,
118
+ transitions,
119
+ fields,
120
+ roles,
121
+ tags,
122
+ metadata,
123
+ },
124
+ errors,
125
+ };
126
+ }
127
+
128
+ // =============================================================================
129
+ // Fields
130
+ // =============================================================================
131
+
132
+ function compileFields(fieldNodes: ASTNode[]): IRFieldDefinition[] {
133
+ return fieldNodes.map(node => {
134
+ const data = node.token.data;
135
+ if (data.type !== 'field_def') return null;
136
+ return mapField(data);
137
+ }).filter((f): f is IRFieldDefinition => f !== null);
138
+ }
139
+
140
+ // =============================================================================
141
+ // States
142
+ // =============================================================================
143
+
144
+ function compileStates(
145
+ thing: ThingSymbol,
146
+ fieldNames: Set<string>,
147
+ ): IRStateDefinition[] {
148
+ return thing.states.map(stateNode => {
149
+ const data = stateNode.token.data;
150
+ if (data.type !== 'state_decl') {
151
+ return null;
152
+ }
153
+
154
+ const stateName = data.name;
155
+ const stateType = resolveStateType(stateName, data.isFinal, thing.startsAt);
156
+
157
+ // Collect on_enter actions from "when entered" children
158
+ const onEnterActions: IRActionDefinition[] = [];
159
+ const onEventSubs: IROnEventSubscription[] = [];
160
+
161
+ for (const child of stateNode.children) {
162
+ const cd = child.token.data;
163
+ if (cd.type === 'when') {
164
+ if (cd.condition === 'entered') {
165
+ // on_enter: collect set_action/do_action children
166
+ const actions = compileWhenEnteredActions(child, stateName, fieldNames);
167
+ onEnterActions.push(...actions);
168
+ } else if (cd.condition.startsWith('receives ')) {
169
+ // on_event subscription
170
+ const sub = compileOnEvent(child, stateName, fieldNames);
171
+ if (sub) onEventSubs.push(sub);
172
+ }
173
+ }
174
+ }
175
+
176
+ const state: IRStateDefinition = {
177
+ name: stateName,
178
+ type: stateType,
179
+ on_enter: onEnterActions,
180
+ during: [],
181
+ on_exit: [],
182
+ };
183
+
184
+ if (onEventSubs.length > 0) {
185
+ state.on_event = onEventSubs;
186
+ }
187
+
188
+ return state;
189
+ }).filter((s): s is IRStateDefinition => s !== null);
190
+ }
191
+
192
+ function resolveStateType(
193
+ name: string,
194
+ isFinal: boolean,
195
+ startsAt?: string,
196
+ ): IRStateType {
197
+ if (startsAt && name === startsAt) return 'START';
198
+ if (isFinal && name.toLowerCase().includes('cancel')) return 'CANCELLED';
199
+ if (isFinal) return 'END';
200
+ return 'REGULAR';
201
+ }
202
+
203
+ // =============================================================================
204
+ // When Entered → on_enter actions
205
+ // =============================================================================
206
+
207
+ function compileWhenEnteredActions(
208
+ whenNode: ASTNode,
209
+ stateName: string,
210
+ fieldNames: Set<string>,
211
+ ): IRActionDefinition[] {
212
+ const context = `${slugify(stateName)}-on-enter`;
213
+ return whenNode.children.map((child, i) => {
214
+ const cd = child.token.data;
215
+ if (cd.type === 'set_action') {
216
+ return {
217
+ id: generateActionId(context, i),
218
+ type: 'set_field',
219
+ mode: 'auto' as const,
220
+ config: {
221
+ field: snakeCase(cd.field),
222
+ expression: transformExpression(cd.expression, fieldNames),
223
+ },
224
+ };
225
+ }
226
+ if (cd.type === 'do_action') {
227
+ return {
228
+ id: generateActionId(context, i),
229
+ type: cd.action,
230
+ mode: 'auto' as const,
231
+ config: {},
232
+ };
233
+ }
234
+ return null;
235
+ }).filter((a): a is IRActionDefinition => a !== null);
236
+ }
237
+
238
+ // =============================================================================
239
+ // When Receives → on_event subscription
240
+ // =============================================================================
241
+
242
+ function compileOnEvent(
243
+ whenNode: ASTNode,
244
+ stateName: string,
245
+ fieldNames: Set<string>,
246
+ ): IROnEventSubscription | null {
247
+ const cd = whenNode.token.data;
248
+ if (cd.type !== 'when') return null;
249
+
250
+ // Parse: receives "event name" from source
251
+ const match = cd.condition.match(/^receives\s+"([^"]+)"\s+from\s+(\S+)$/);
252
+ if (!match) return null;
253
+
254
+ const eventName = match[1];
255
+ const sourceSlug = slugify(match[2]);
256
+
257
+ // Build topic pattern: *:{{ entity_id }}:<source-slug>:instance.<event-slug>
258
+ const eventSlug = eventName.replace(/\s+/g, '.');
259
+ const topicPattern = `*:{{ entity_id }}:${sourceSlug}:instance.${eventSlug}`;
260
+
261
+ // Compile child set_actions into on_event actions
262
+ const actions: IROnEventAction[] = whenNode.children.map(child => {
263
+ const acd = child.token.data;
264
+ if (acd.type === 'set_action') {
265
+ return {
266
+ type: 'set_field' as const,
267
+ field: snakeCase(acd.field),
268
+ expression: transformExpression(acd.expression, fieldNames),
269
+ };
270
+ }
271
+ return null;
272
+ }).filter((a): a is IROnEventAction => a !== null);
273
+
274
+ return {
275
+ match: topicPattern,
276
+ description: `On ${eventName} from ${match[2]}`,
277
+ actions,
278
+ };
279
+ }
280
+
281
+ // =============================================================================
282
+ // Transitions
283
+ // =============================================================================
284
+
285
+ function compileTransitions(
286
+ thing: ThingSymbol,
287
+ fieldNames: Set<string>,
288
+ stateNames: Set<string>,
289
+ errors: CompilerError[],
290
+ ): IRTransitionDefinition[] {
291
+ const transitions: IRTransitionDefinition[] = [];
292
+
293
+ for (const stateNode of thing.states) {
294
+ const stateData = stateNode.token.data;
295
+ if (stateData.type !== 'state_decl') continue;
296
+ const fromState = stateData.name;
297
+
298
+ for (const child of stateNode.children) {
299
+ const cd = child.token.data;
300
+ if (cd.type !== 'transition') continue;
301
+
302
+ const isAuto = cd.verb.startsWith('auto ');
303
+ const transitionName = slugify(cd.verb);
304
+
305
+ // Validate target state
306
+ if (!stateNames.has(cd.target)) {
307
+ errors.push({
308
+ code: 'UNKNOWN_TARGET_STATE',
309
+ message: `Transition "${cd.verb}" targets unknown state "${cd.target}"`,
310
+ lineNumber: child.token.lineNumber,
311
+ severity: 'warning',
312
+ });
313
+ }
314
+
315
+ // Parse guard → roles
316
+ let roles: string[] | undefined;
317
+ if (cd.guard) {
318
+ roles = parseGuard(cd.guard);
319
+ }
320
+
321
+ // Compile conditions from nested `when` children
322
+ const conditions = compileTransitionConditions(child, fieldNames);
323
+
324
+ // Compile actions from nested `set_action`/`do_action` children
325
+ const actions = compileTransitionActions(child, transitionName, fieldNames);
326
+
327
+ const transition: IRTransitionDefinition = {
328
+ name: transitionName,
329
+ from: [fromState],
330
+ to: cd.target,
331
+ actions,
332
+ };
333
+
334
+ if (isAuto) transition.auto = true;
335
+ if (roles && roles.length > 0) transition.roles = roles;
336
+ if (conditions && conditions.length > 0) transition.conditions = conditions;
337
+
338
+ transitions.push(transition);
339
+ }
340
+ }
341
+
342
+ return transitions;
343
+ }
344
+
345
+ function parseGuard(guard: string): string[] {
346
+ // "admin only" → ['admin']
347
+ // "owner only" → ['owner']
348
+ // "admin and owner" → ['admin', 'owner']
349
+ const cleaned = guard.replace(/\s+only$/, '');
350
+ return cleaned.split(/\s+and\s+/).map(r => r.trim());
351
+ }
352
+
353
+ function compileTransitionConditions(
354
+ transitionNode: ASTNode,
355
+ fieldNames: Set<string>,
356
+ ): IRConditionDefinition[] | undefined {
357
+ const conditions: IRConditionDefinition[] = [];
358
+
359
+ for (const child of transitionNode.children) {
360
+ const cd = child.token.data;
361
+ if (cd.type === 'when') {
362
+ const parsed = parseConditionExpression(cd.condition, fieldNames);
363
+ if (parsed) conditions.push(parsed);
364
+ }
365
+ }
366
+
367
+ return conditions.length > 0 ? conditions : undefined;
368
+ }
369
+
370
+ function compileTransitionActions(
371
+ transitionNode: ASTNode,
372
+ transitionName: string,
373
+ fieldNames: Set<string>,
374
+ ): IRActionDefinition[] {
375
+ const actions: IRActionDefinition[] = [];
376
+ const context = `${transitionName}-action`;
377
+
378
+ for (const child of transitionNode.children) {
379
+ const cd = child.token.data;
380
+ if (cd.type === 'set_action') {
381
+ actions.push({
382
+ id: generateActionId(context, actions.length),
383
+ type: 'set_field',
384
+ mode: 'auto',
385
+ config: {
386
+ field: snakeCase(cd.field),
387
+ expression: transformExpression(cd.expression, fieldNames),
388
+ },
389
+ });
390
+ } else if (cd.type === 'do_action') {
391
+ actions.push({
392
+ id: generateActionId(context, actions.length),
393
+ type: cd.action,
394
+ mode: 'auto',
395
+ config: {},
396
+ });
397
+ }
398
+ }
399
+
400
+ return actions;
401
+ }
402
+
403
+ // =============================================================================
404
+ // Condition Expression Parsing
405
+ // =============================================================================
406
+
407
+ function parseConditionExpression(
408
+ condition: string,
409
+ fieldNames: Set<string>,
410
+ ): IRConditionDefinition | null {
411
+ // Handle compound "and" conditions
412
+ if (condition.includes(' and ')) {
413
+ const parts = condition.split(/\s+and\s+/);
414
+ const subConditions = parts
415
+ .map(p => parseSingleCondition(p.trim(), fieldNames))
416
+ .filter((c): c is IRConditionDefinition => c !== null);
417
+
418
+ if (subConditions.length > 1) {
419
+ return { AND: subConditions };
420
+ }
421
+ if (subConditions.length === 1) {
422
+ return subConditions[0];
423
+ }
424
+ return null;
425
+ }
426
+
427
+ return parseSingleCondition(condition, fieldNames);
428
+ }
429
+
430
+ function parseSingleCondition(
431
+ expr: string,
432
+ fieldNames: Set<string>,
433
+ ): IRConditionDefinition | null {
434
+ // Pattern: left operator right
435
+ const opMatch = expr.match(/^(.+?)\s*(>=|<=|>|<|==|!=)\s*(.+)$/);
436
+ if (!opMatch) return null;
437
+
438
+ const left = opMatch[1].trim();
439
+ const op = opMatch[2];
440
+ const right = opMatch[3].trim();
441
+
442
+ const operatorMap: Record<string, IRConditionDefinition['operator']> = {
443
+ '>=': 'gte',
444
+ '<=': 'lte',
445
+ '>': 'gt',
446
+ '<': 'lt',
447
+ '==': 'eq',
448
+ '!=': 'ne',
449
+ };
450
+
451
+ const operator = operatorMap[op];
452
+ if (!operator) return null;
453
+
454
+ const leftField = resolveFieldRef(left, fieldNames);
455
+ const rightValue = resolveConditionValue(right, fieldNames);
456
+
457
+ const condition: IRConditionDefinition = {
458
+ field: leftField,
459
+ operator,
460
+ };
461
+
462
+ if (typeof rightValue === 'number') {
463
+ condition.value = rightValue;
464
+ } else {
465
+ condition.expression = rightValue;
466
+ }
467
+
468
+ return condition;
469
+ }
470
+
471
+ function resolveFieldRef(name: string, fieldNames: Set<string>): string {
472
+ // Check if name matches a known field
473
+ if (fieldNames.has(name)) {
474
+ return `state_data.${snakeCase(name)}`;
475
+ }
476
+ // Try to find by partial match
477
+ for (const fn of fieldNames) {
478
+ if (fn === name) return `state_data.${snakeCase(fn)}`;
479
+ }
480
+ return `state_data.${snakeCase(name)}`;
481
+ }
482
+
483
+ function resolveConditionValue(
484
+ value: string,
485
+ fieldNames: Set<string>,
486
+ ): number | string {
487
+ // Numeric literal
488
+ const num = Number(value);
489
+ if (!isNaN(num)) return num;
490
+
491
+ // Field reference
492
+ if (fieldNames.has(value)) {
493
+ return `state_data.${snakeCase(value)}`;
494
+ }
495
+
496
+ return `state_data.${snakeCase(value)}`;
497
+ }
498
+
499
+ // =============================================================================
500
+ // Expression Transformation
501
+ // =============================================================================
502
+
503
+ /**
504
+ * Transform a DSL expression into an IR expression.
505
+ *
506
+ * Rules:
507
+ * 1. String literals (quoted) → passthrough
508
+ * 2. now() → passthrough
509
+ * 3. "the event's X" → $event.state_data.<snake_case_X>
510
+ * 4. Known field names → state_data.<snake_case>
511
+ * 5. A + B → add(resolved_A, resolved_B)
512
+ * 6. A - B → subtract(resolved_A, resolved_B)
513
+ * 7. Numeric literals → passthrough
514
+ */
515
+ export function transformExpression(
516
+ expression: string,
517
+ fieldNames: Set<string>,
518
+ ): string {
519
+ const trimmed = expression.trim();
520
+
521
+ // String literal: "value"
522
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
523
+ return trimmed;
524
+ }
525
+
526
+ // now() passthrough
527
+ if (trimmed === 'now()') return 'now()';
528
+
529
+ // Arithmetic: A + B or A - B
530
+ const addMatch = trimmed.match(/^(.+?)\s*\+\s*(.+)$/);
531
+ if (addMatch) {
532
+ const left = resolveExpressionPart(addMatch[1].trim(), fieldNames);
533
+ const right = resolveExpressionPart(addMatch[2].trim(), fieldNames);
534
+ return `add(${left}, ${right})`;
535
+ }
536
+
537
+ const subMatch = trimmed.match(/^(.+?)\s*-\s*(.+)$/);
538
+ if (subMatch) {
539
+ const left = resolveExpressionPart(subMatch[1].trim(), fieldNames);
540
+ const right = resolveExpressionPart(subMatch[2].trim(), fieldNames);
541
+ return `subtract(${left}, ${right})`;
542
+ }
543
+
544
+ // Single value
545
+ return resolveExpressionPart(trimmed, fieldNames);
546
+ }
547
+
548
+ function resolveExpressionPart(
549
+ part: string,
550
+ fieldNames: Set<string>,
551
+ ): string {
552
+ const trimmed = part.trim();
553
+
554
+ // Numeric literal
555
+ const num = Number(trimmed);
556
+ if (!isNaN(num) && trimmed !== '') return String(num);
557
+
558
+ // String literal
559
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) return trimmed;
560
+
561
+ // "the event's X" → $event.state_data.<snake>
562
+ const eventMatch = trimmed.match(/^the event's\s+(.+)$/);
563
+ if (eventMatch) {
564
+ return `$event.state_data.${snakeCase(eventMatch[1])}`;
565
+ }
566
+
567
+ // now() passthrough
568
+ if (trimmed === 'now()') return 'now()';
569
+
570
+ // Known field name → state_data.<snake>
571
+ if (fieldNames.has(trimmed)) {
572
+ return `state_data.${snakeCase(trimmed)}`;
573
+ }
574
+
575
+ // Default: treat as field reference
576
+ return `state_data.${snakeCase(trimmed)}`;
577
+ }
578
+
579
+ // =============================================================================
580
+ // Role Collection
581
+ // =============================================================================
582
+
583
+ function collectRoles(thing: ThingSymbol): IRRoleDefinition[] {
584
+ const roleNames = new Set<string>();
585
+
586
+ for (const stateNode of thing.states) {
587
+ for (const child of stateNode.children) {
588
+ const cd = child.token.data;
589
+ if (cd.type === 'transition' && cd.guard) {
590
+ const roles = parseGuard(cd.guard);
591
+ for (const r of roles) roleNames.add(r);
592
+ }
593
+ }
594
+ }
595
+
596
+ return Array.from(roleNames).map(name => ({
597
+ name,
598
+ permissions: [`transition:${name}`],
599
+ }));
600
+ }
@@ -0,0 +1,66 @@
1
+ export { tokenize, tokenizeLine } from './lexer';
2
+ export { parse, walkTree, findByType } from './parser';
3
+ export type {
4
+ LineType,
5
+ LineToken,
6
+ LineData,
7
+ ASTNode,
8
+ ParseResult,
9
+ ParseError,
10
+ Emphasis,
11
+ Constraint,
12
+ SpaceDeclData,
13
+ ThingDeclData,
14
+ ThingRefData,
15
+ FragmentDefData,
16
+ FieldDefData,
17
+ StateDeclData,
18
+ StartsAtData,
19
+ TransitionData,
20
+ WhenData,
21
+ SetActionData,
22
+ DoActionData,
23
+ GoActionData,
24
+ TellActionData,
25
+ ShowActionData,
26
+ DataSourceData,
27
+ IterationData,
28
+ GroupingData,
29
+ ContentData,
30
+ StringLiteralData,
31
+ SearchData,
32
+ QualifierData,
33
+ NavigationData,
34
+ PathMappingData,
35
+ SectionData,
36
+ TaggedData,
37
+ LevelDefData,
38
+ } from './types';
39
+
40
+ export { compile, compileAST } from './compiler';
41
+ export type {
42
+ CompilationResult,
43
+ CompilerError,
44
+ CompilerErrorCode,
45
+ IRWorkflowDefinition,
46
+ IRStateDefinition,
47
+ IRTransitionDefinition,
48
+ IRFieldDefinition,
49
+ IRFieldValidation,
50
+ IRActionDefinition,
51
+ IRConditionDefinition,
52
+ IRExperienceNode,
53
+ IRDataSource,
54
+ IRWorkflowDataSource,
55
+ IRExperienceDefinition,
56
+ IRBlueprintManifest,
57
+ IROnEventSubscription,
58
+ IROnEventAction,
59
+ IRRoleDefinition,
60
+ IRStateType,
61
+ IRActionMode,
62
+ IRWorkflowFieldType,
63
+ PureFormWorkflow,
64
+ CompiledOutput,
65
+ } from './ir-types';
66
+ export { normalizeCategory } from './ir-types';