@lokascript/domain-flow 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Pipeline Parser
3
+ *
4
+ * Wraps the framework's single-command DSL parser to handle multi-step
5
+ * data flow pipelines. Splits input on arrow delimiters (→ / ->), parses
6
+ * each step individually, and assembles a PipelineParseResult.
7
+ */
8
+
9
+ import type { MultilingualDSL, SemanticNode } from '@lokascript/framework';
10
+ import { renderFlow } from '../generators/flow-renderer.js';
11
+
12
+ // =============================================================================
13
+ // Types
14
+ // =============================================================================
15
+
16
+ export interface PipelineStep {
17
+ /** The semantic node from parsing a single command */
18
+ node: SemanticNode;
19
+ }
20
+
21
+ export interface PipelineParseResult {
22
+ /** Ordered pipeline steps */
23
+ steps: PipelineStep[];
24
+ /** Parse errors for any failed steps */
25
+ errors: string[];
26
+ }
27
+
28
+ // =============================================================================
29
+ // Arrow Delimiter
30
+ // =============================================================================
31
+
32
+ /** Splits on → (Unicode) or -> (ASCII arrow), with optional surrounding whitespace */
33
+ const ARROW_DELIMITER = /\s*(?:→|->)\s*/;
34
+
35
+ // =============================================================================
36
+ // Pipeline Parser
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Parse a multi-step FlowScript pipeline into ordered steps.
41
+ *
42
+ * Splits input on arrow delimiters (→ / ->), parses each segment
43
+ * via the DSL, and returns the steps in order.
44
+ *
45
+ * @example
46
+ * ```
47
+ * // Single-line arrow chain
48
+ * parseFlowPipeline(dsl, 'fetch /api/users as json → transform data with uppercase → into #list', 'en')
49
+ *
50
+ * // Multi-line (newline-separated, each line is a step)
51
+ * parseFlowPipeline(dsl, 'fetch /api/users as json\ntransform data with uppercase', 'en')
52
+ * ```
53
+ */
54
+ export function parseFlowPipeline(
55
+ dsl: MultilingualDSL,
56
+ input: string,
57
+ language: string
58
+ ): PipelineParseResult {
59
+ const steps: PipelineStep[] = [];
60
+ const errors: string[] = [];
61
+
62
+ // Split on arrows first, then on newlines for any remaining multi-line segments
63
+ const arrowParts = input.split(ARROW_DELIMITER);
64
+
65
+ const segments: string[] = [];
66
+ for (const part of arrowParts) {
67
+ // Further split on newlines within each arrow-delimited part
68
+ const lines = part
69
+ .split(/\n/)
70
+ .map(l => l.trim())
71
+ .filter(Boolean);
72
+ segments.push(...lines);
73
+ }
74
+
75
+ // Filter out comments (lines starting with --)
76
+ const commands = segments.filter(s => !s.startsWith('--'));
77
+
78
+ for (const segment of commands) {
79
+ try {
80
+ const node = dsl.parse(segment, language);
81
+ steps.push({ node });
82
+ } catch (err) {
83
+ errors.push(
84
+ `Failed to parse step: "${segment}" - ${err instanceof Error ? err.message : String(err)}`
85
+ );
86
+ }
87
+ }
88
+
89
+ return { steps, errors };
90
+ }
91
+
92
+ /**
93
+ * Compile a pipeline to a single JS code block.
94
+ *
95
+ * For linear pipelines (no branching), each step's output feeds into the next
96
+ * via Promise chaining. The first step must be a source (fetch/poll/stream),
97
+ * middle steps can be transforms, and the last step can include a destination.
98
+ */
99
+ export function compilePipeline(
100
+ dsl: MultilingualDSL,
101
+ input: string,
102
+ language: string
103
+ ): { ok: boolean; code?: string; errors: string[] } {
104
+ const { steps, errors } = parseFlowPipeline(dsl, input, language);
105
+
106
+ if (errors.length > 0) {
107
+ return { ok: false, errors };
108
+ }
109
+
110
+ if (steps.length === 0) {
111
+ return { ok: false, errors: ['Empty pipeline'] };
112
+ }
113
+
114
+ // Single step: just compile it directly
115
+ if (steps.length === 1) {
116
+ const result = dsl.compile(input.replace(/→|->/g, '').trim(), language);
117
+ return {
118
+ ok: result.ok,
119
+ code: result.code ?? undefined,
120
+ errors: result.ok ? [] : ['Compilation failed'],
121
+ };
122
+ }
123
+
124
+ // Multi-step: compose into Promise chain
125
+ const compileErrors: string[] = [];
126
+ const codes: string[] = [];
127
+ for (const step of steps) {
128
+ const result = dsl.compile(renderStepBack(step.node, language), language);
129
+ if (result.ok && result.code) {
130
+ codes.push(result.code);
131
+ } else {
132
+ compileErrors.push(`Failed to compile step: ${step.node.action}`);
133
+ }
134
+ }
135
+
136
+ if (compileErrors.length > 0) {
137
+ return { ok: false, errors: compileErrors };
138
+ }
139
+
140
+ // Join with comment separators
141
+ const combined = codes.join('\n\n// --- next step ---\n\n');
142
+ return { ok: true, code: combined, errors: [] };
143
+ }
144
+
145
+ /**
146
+ * Reconstruct a parse-able string from a SemanticNode for re-compilation.
147
+ * Uses the natural language renderer to produce correct output with markers.
148
+ */
149
+ function renderStepBack(node: SemanticNode, language: string): string {
150
+ return renderFlow(node, language);
151
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * FlowScript Language Profiles
3
+ *
4
+ * Pattern generation profiles for 8 supported languages.
5
+ * Covers SVO (EN, ES, ZH, FR), SOV (JA, KO, TR), and VSO (AR) word orders.
6
+ *
7
+ * Role markers are specified via markerOverride on each schema role.
8
+ * Profile roleMarkers are used only when positional defaults need overriding.
9
+ */
10
+
11
+ import type { PatternGenLanguageProfile } from '@lokascript/framework';
12
+
13
+ // =============================================================================
14
+ // English (SVO)
15
+ // =============================================================================
16
+
17
+ export const englishProfile: PatternGenLanguageProfile = {
18
+ code: 'en',
19
+ wordOrder: 'SVO',
20
+ keywords: {
21
+ fetch: { primary: 'fetch' },
22
+ poll: { primary: 'poll' },
23
+ stream: { primary: 'stream' },
24
+ submit: { primary: 'submit' },
25
+ transform: { primary: 'transform' },
26
+ enter: { primary: 'enter' },
27
+ follow: { primary: 'follow' },
28
+ perform: { primary: 'perform' },
29
+ capture: { primary: 'capture' },
30
+ },
31
+ };
32
+
33
+ // =============================================================================
34
+ // Spanish (SVO)
35
+ // =============================================================================
36
+
37
+ export const spanishProfile: PatternGenLanguageProfile = {
38
+ code: 'es',
39
+ wordOrder: 'SVO',
40
+ keywords: {
41
+ fetch: { primary: 'obtener' },
42
+ poll: { primary: 'sondear' },
43
+ stream: { primary: 'transmitir' },
44
+ submit: { primary: 'enviar' },
45
+ transform: { primary: 'transformar' },
46
+ enter: { primary: 'entrar' },
47
+ follow: { primary: 'seguir' },
48
+ perform: { primary: 'ejecutar' },
49
+ capture: { primary: 'capturar' },
50
+ },
51
+ };
52
+
53
+ // =============================================================================
54
+ // Japanese (SOV)
55
+ // =============================================================================
56
+
57
+ export const japaneseProfile: PatternGenLanguageProfile = {
58
+ code: 'ja',
59
+ wordOrder: 'SOV',
60
+ keywords: {
61
+ fetch: { primary: '取得' },
62
+ poll: { primary: 'ポーリング' },
63
+ stream: { primary: 'ストリーム' },
64
+ submit: { primary: '送信' },
65
+ transform: { primary: '変換' },
66
+ enter: { primary: '入る' },
67
+ follow: { primary: '辿る' },
68
+ perform: { primary: '実行' },
69
+ capture: { primary: '取得変数' },
70
+ },
71
+ };
72
+
73
+ // =============================================================================
74
+ // Arabic (VSO)
75
+ // =============================================================================
76
+
77
+ export const arabicProfile: PatternGenLanguageProfile = {
78
+ code: 'ar',
79
+ wordOrder: 'VSO',
80
+ keywords: {
81
+ fetch: { primary: 'جلب' },
82
+ poll: { primary: 'استطلع' },
83
+ stream: { primary: 'بث' },
84
+ submit: { primary: 'أرسل' },
85
+ transform: { primary: 'حوّل' },
86
+ enter: { primary: 'ادخل' },
87
+ follow: { primary: 'اتبع' },
88
+ perform: { primary: 'نفّذ' },
89
+ capture: { primary: 'التقط' },
90
+ },
91
+ };
92
+
93
+ // =============================================================================
94
+ // Korean (SOV)
95
+ // =============================================================================
96
+
97
+ export const koreanProfile: PatternGenLanguageProfile = {
98
+ code: 'ko',
99
+ wordOrder: 'SOV',
100
+ keywords: {
101
+ fetch: { primary: '가져오기' },
102
+ poll: { primary: '폴링' },
103
+ stream: { primary: '스트리밍' },
104
+ submit: { primary: '제출' },
105
+ transform: { primary: '변환' },
106
+ enter: { primary: '진입' },
107
+ follow: { primary: '따라가기' },
108
+ perform: { primary: '실행' },
109
+ capture: { primary: '캡처' },
110
+ },
111
+ };
112
+
113
+ // =============================================================================
114
+ // Chinese (SVO)
115
+ // =============================================================================
116
+
117
+ export const chineseProfile: PatternGenLanguageProfile = {
118
+ code: 'zh',
119
+ wordOrder: 'SVO',
120
+ keywords: {
121
+ fetch: { primary: '获取' },
122
+ poll: { primary: '轮询' },
123
+ stream: { primary: '流式' },
124
+ submit: { primary: '提交' },
125
+ transform: { primary: '转换' },
126
+ enter: { primary: '进入' },
127
+ follow: { primary: '跟随' },
128
+ perform: { primary: '执行' },
129
+ capture: { primary: '捕获' },
130
+ },
131
+ };
132
+
133
+ // =============================================================================
134
+ // Turkish (SOV)
135
+ // =============================================================================
136
+
137
+ export const turkishProfile: PatternGenLanguageProfile = {
138
+ code: 'tr',
139
+ wordOrder: 'SOV',
140
+ keywords: {
141
+ fetch: { primary: 'getir' },
142
+ poll: { primary: 'yokla' },
143
+ stream: { primary: 'aktar' },
144
+ submit: { primary: 'gönder' },
145
+ transform: { primary: 'dönüştür' },
146
+ enter: { primary: 'gir' },
147
+ follow: { primary: 'izle' },
148
+ perform: { primary: 'yürüt' },
149
+ capture: { primary: 'yakala' },
150
+ },
151
+ };
152
+
153
+ // =============================================================================
154
+ // French (SVO)
155
+ // =============================================================================
156
+
157
+ export const frenchProfile: PatternGenLanguageProfile = {
158
+ code: 'fr',
159
+ wordOrder: 'SVO',
160
+ keywords: {
161
+ fetch: { primary: 'récupérer' },
162
+ poll: { primary: 'interroger' },
163
+ stream: { primary: 'diffuser' },
164
+ submit: { primary: 'soumettre' },
165
+ transform: { primary: 'transformer' },
166
+ enter: { primary: 'entrer' },
167
+ follow: { primary: 'suivre' },
168
+ perform: { primary: 'exécuter' },
169
+ capture: { primary: 'capturer' },
170
+ },
171
+ };
172
+
173
+ // =============================================================================
174
+ // All Profiles
175
+ // =============================================================================
176
+
177
+ export const allProfiles = [
178
+ englishProfile,
179
+ spanishProfile,
180
+ japaneseProfile,
181
+ arabicProfile,
182
+ koreanProfile,
183
+ chineseProfile,
184
+ turkishProfile,
185
+ frenchProfile,
186
+ ];