@lokascript/framework 4.8.0 → 5.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 (79) hide show
  1. package/CHANGELOG.md +70 -1
  2. package/dist/api/create-dsl.d.ts +9 -10
  3. package/dist/api/create-dsl.d.ts.map +1 -1
  4. package/dist/api/index.js +835 -1670
  5. package/dist/api/index.js.map +1 -1
  6. package/dist/core/index.d.ts +0 -1
  7. package/dist/core/index.d.ts.map +1 -1
  8. package/dist/core/index.js +549 -1132
  9. package/dist/core/index.js.map +1 -1
  10. package/dist/core/matching/index.d.ts +2 -0
  11. package/dist/core/matching/index.d.ts.map +1 -1
  12. package/dist/core/matching/possessive-keywords.d.ts.map +1 -0
  13. package/dist/core/matching/stock-confidence.d.ts +3 -4
  14. package/dist/core/matching/stock-confidence.d.ts.map +1 -1
  15. package/dist/core/matching/stock-reading.d.ts +4 -4
  16. package/dist/core/{pattern-matching/utils → matching}/type-validation.d.ts +1 -1
  17. package/dist/core/matching/type-validation.d.ts.map +1 -0
  18. package/dist/generation/index.d.ts +1 -1
  19. package/dist/generation/index.d.ts.map +1 -1
  20. package/dist/generation/index.js +20 -169
  21. package/dist/generation/index.js.map +1 -1
  22. package/dist/generation/profile.d.ts +30 -0
  23. package/dist/generation/profile.d.ts.map +1 -0
  24. package/dist/generation/renderer.d.ts +1 -1
  25. package/dist/generation/renderer.d.ts.map +1 -1
  26. package/dist/generation/schema-patterns.d.ts +3 -3
  27. package/dist/index.cjs +929 -1674
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.js +929 -1668
  30. package/dist/index.js.map +1 -1
  31. package/dist/multilingual/builders.d.ts +3 -3
  32. package/dist/multilingual/builders.d.ts.map +1 -1
  33. package/dist/multilingual/index.js.map +1 -1
  34. package/dist/parsing/index.d.ts +0 -1
  35. package/dist/parsing/index.d.ts.map +1 -1
  36. package/dist/parsing/index.js +0 -1145
  37. package/dist/parsing/index.js.map +1 -1
  38. package/dist/testing/gate/lint/types.d.ts +1 -1
  39. package/dist/testing/gate/lint/types.d.ts.map +1 -1
  40. package/package.json +3 -8
  41. package/src/__test__/test-utils.ts +1 -1
  42. package/src/api/create-dsl-engine.test.ts +60 -35
  43. package/src/api/create-dsl.ts +24 -35
  44. package/src/core/index.ts +0 -1
  45. package/src/core/matching/index.ts +2 -0
  46. package/src/core/matching/stock-confidence.ts +3 -4
  47. package/src/core/matching/stock-reading.ts +6 -6
  48. package/src/core/{pattern-matching/utils → matching}/type-validation.test.ts +2 -2
  49. package/src/core/{pattern-matching/utils → matching}/type-validation.ts +1 -1
  50. package/src/generation/domain-renderer.test.ts +1 -1
  51. package/src/generation/index.ts +1 -1
  52. package/src/generation/profile.ts +41 -0
  53. package/src/generation/renderer.test.ts +1 -1
  54. package/src/generation/renderer.ts +1 -1
  55. package/src/generation/schema-patterns.ts +3 -3
  56. package/src/multilingual/bridge.test.ts +31 -23
  57. package/src/multilingual/builders.ts +3 -3
  58. package/src/parsing/index.ts +0 -1
  59. package/src/testing/gate/lint/types.ts +1 -1
  60. package/dist/core/pattern-matching/index.d.ts +0 -6
  61. package/dist/core/pattern-matching/index.d.ts.map +0 -1
  62. package/dist/core/pattern-matching/index.js +0 -1211
  63. package/dist/core/pattern-matching/index.js.map +0 -1
  64. package/dist/core/pattern-matching/pattern-matcher.d.ts +0 -122
  65. package/dist/core/pattern-matching/pattern-matcher.d.ts.map +0 -1
  66. package/dist/core/pattern-matching/utils/index.d.ts +0 -6
  67. package/dist/core/pattern-matching/utils/index.d.ts.map +0 -1
  68. package/dist/core/pattern-matching/utils/possessive-keywords.d.ts.map +0 -1
  69. package/dist/core/pattern-matching/utils/type-validation.d.ts.map +0 -1
  70. package/dist/generation/pattern-generator.d.ts +0 -55
  71. package/dist/generation/pattern-generator.d.ts.map +0 -1
  72. package/src/core/pattern-matching/index.ts +0 -6
  73. package/src/core/pattern-matching/pattern-matcher.test.ts +0 -1031
  74. package/src/core/pattern-matching/pattern-matcher.ts +0 -765
  75. package/src/core/pattern-matching/utils/index.ts +0 -6
  76. package/src/generation/pattern-generator.test.ts +0 -532
  77. package/src/generation/pattern-generator.ts +0 -327
  78. /package/dist/core/{pattern-matching/utils → matching}/possessive-keywords.d.ts +0 -0
  79. /package/src/core/{pattern-matching/utils → matching}/possessive-keywords.ts +0 -0
@@ -1,327 +0,0 @@
1
- /**
2
- * Pattern Generator
3
- *
4
- * Generates LanguagePattern objects from CommandSchema + LanguageProfile.
5
- * This solves the pattern explosion problem by deriving patterns from
6
- * high-level schema definitions rather than hand-writing each one.
7
- */
8
-
9
- import type { LanguagePattern, PatternToken, ExtractionRule } from '../core/types';
10
- import type { CommandSchema, RoleSpec } from '../schema';
11
-
12
- /**
13
- * Minimal language profile interface for pattern generation.
14
- */
15
- export interface PatternGenLanguageProfile {
16
- readonly code: string;
17
- readonly wordOrder: 'SVO' | 'SOV' | 'VSO' | 'VOS' | 'OSV' | 'OVS' | 'free';
18
- readonly keywords: Record<string, { primary: string; alternatives?: string[] }>;
19
- readonly roleMarkers?: Record<
20
- string,
21
- { primary: string; alternatives?: string[]; position?: 'before' | 'after' }
22
- >;
23
- }
24
-
25
- /**
26
- * Configuration for pattern generation.
27
- */
28
- export interface GeneratorConfig {
29
- /** Base priority for generated patterns (default: 100) */
30
- readonly basePriority?: number;
31
- /** Include optional role variants (default: true) */
32
- readonly includeOptionalVariants?: boolean;
33
- }
34
-
35
- const defaultConfig: GeneratorConfig = {
36
- basePriority: 100,
37
- includeOptionalVariants: true,
38
- };
39
-
40
- /**
41
- * Generate a language pattern from a command schema and language profile.
42
- *
43
- * @param schema - Command schema defining the command structure
44
- * @param profile - Language profile with word order and keywords
45
- * @param config - Optional configuration
46
- * @returns Generated language pattern
47
- */
48
- export function generatePattern(
49
- schema: CommandSchema,
50
- profile: PatternGenLanguageProfile,
51
- config: GeneratorConfig = defaultConfig
52
- ): LanguagePattern {
53
- const id = `${schema.action}-${profile.code}-generated`;
54
- const priority = config.basePriority ?? 100;
55
-
56
- // Get keyword translation
57
- const keyword = profile.keywords[schema.action];
58
- if (!keyword) {
59
- throw new Error(`No keyword translation for '${schema.action}' in ${profile.code}`);
60
- }
61
-
62
- // Build tokens based on word order
63
- const tokens = buildTokens(schema, profile, keyword.primary, keyword.alternatives);
64
-
65
- // Build extraction rules
66
- const extraction = buildExtractionRules(schema, profile);
67
-
68
- // Build format string for documentation
69
- const format = buildFormatString(schema, profile, keyword.primary);
70
-
71
- return {
72
- id,
73
- language: profile.code,
74
- command: schema.action,
75
- priority,
76
- template: {
77
- format,
78
- tokens,
79
- },
80
- extraction,
81
- };
82
- }
83
-
84
- /**
85
- * Build pattern tokens based on word order and role markers.
86
- */
87
- function buildTokens(
88
- schema: CommandSchema,
89
- profile: PatternGenLanguageProfile,
90
- keyword: string,
91
- alternatives?: string[]
92
- ): PatternToken[] {
93
- const tokens: PatternToken[] = [];
94
- const keywordToken: PatternToken = {
95
- type: 'literal',
96
- value: keyword,
97
- ...(alternatives?.length && { alternatives }),
98
- };
99
-
100
- // Sort roles by word order
101
- const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);
102
-
103
- // For SVO: [action, patient, destination, source, ...]
104
- if (profile.wordOrder === 'SVO') {
105
- // Add keyword first
106
- tokens.push(keywordToken);
107
-
108
- // Add roles with markers
109
- for (const role of sortedRoles) {
110
- addRoleWithMarker(tokens, role, profile);
111
- }
112
- }
113
- // For SOV: [patient, destination, source, ..., action, postVerb roles...]
114
- else if (profile.wordOrder === 'SOV') {
115
- // `sovSlot: 'postVerb'` moves a role AFTER the verb, which is what the
116
- // renderer does (`renderer.ts` buckets by the same field). Generation has
117
- // to mirror it: a role the renderer writes post-verb but the pattern
118
- // expects pre-verb produces a faithful surface its own parser drops the
119
- // argument from — voice's `戻る 2` re-parsing as a bare `back`.
120
- const preVerb: PatternToken[] = [];
121
- const postVerb: PatternToken[] = [];
122
-
123
- for (const role of sortedRoles) {
124
- addRoleWithMarker(role.sovSlot === 'postVerb' ? postVerb : preVerb, role, profile);
125
- }
126
-
127
- tokens.push(...preVerb, keywordToken, ...postVerb);
128
- }
129
- // For VSO: [action, destination, patient, source, ...]
130
- else if (profile.wordOrder === 'VSO') {
131
- // Add keyword first
132
- tokens.push(keywordToken);
133
-
134
- // Add roles with markers
135
- for (const role of sortedRoles) {
136
- addRoleWithMarker(tokens, role, profile);
137
- }
138
- }
139
- // Other word orders can be added as needed
140
- else {
141
- // Fallback to SVO-style ordering
142
- tokens.push(keywordToken);
143
- for (const role of sortedRoles) {
144
- addRoleWithMarker(tokens, role, profile);
145
- }
146
- }
147
-
148
- return tokens;
149
- }
150
-
151
- /**
152
- * Add a role token with its grammatical marker if needed.
153
- * For optional roles, wraps the role + marker in a group.
154
- */
155
- function addRoleWithMarker(
156
- tokens: PatternToken[],
157
- roleSpec: RoleSpec,
158
- profile: PatternGenLanguageProfile
159
- ): void {
160
- const marker = getMarkerForRole(roleSpec, profile);
161
- const isOptional = !roleSpec.required;
162
-
163
- // Build the role token
164
- const roleToken: PatternToken = {
165
- type: 'role',
166
- role: roleSpec.role,
167
- optional: isOptional,
168
- expectedTypes: roleSpec.expectedTypes,
169
- ...(roleSpec.greedy && { greedy: true }),
170
- };
171
-
172
- if (marker) {
173
- const markerInfo = profile.roleMarkers?.[roleSpec.role];
174
- // Priority: schema markerPosition → profile roleMarkers position → word-order default
175
- const defaultPosition = profile.wordOrder === 'SOV' ? 'after' : 'before';
176
- const position = roleSpec.markerPosition ?? markerInfo?.position ?? defaultPosition;
177
-
178
- if (isOptional) {
179
- // Optional role: wrap marker + role in optional group
180
- if (position === 'before') {
181
- tokens.push({
182
- type: 'group',
183
- optional: true,
184
- tokens: [{ type: 'literal', value: marker }, roleToken],
185
- });
186
- } else {
187
- tokens.push({
188
- type: 'group',
189
- optional: true,
190
- tokens: [roleToken, { type: 'literal', value: marker }],
191
- });
192
- }
193
- } else {
194
- // Required role: add marker + role separately
195
- if (position === 'before') {
196
- tokens.push({ type: 'literal', value: marker });
197
- tokens.push(roleToken);
198
- } else {
199
- tokens.push(roleToken);
200
- tokens.push({ type: 'literal', value: marker });
201
- }
202
- }
203
- } else {
204
- // No marker - just add the role
205
- tokens.push(roleToken);
206
- }
207
- }
208
-
209
- /**
210
- * Get the grammatical marker for a role from the profile.
211
- */
212
- function getMarkerForRole(
213
- roleSpec: RoleSpec,
214
- profile: PatternGenLanguageProfile
215
- ): string | undefined {
216
- // Check for role-specific override first
217
- if (roleSpec.markerOverride?.[profile.code]) {
218
- return roleSpec.markerOverride[profile.code];
219
- }
220
-
221
- // Use profile's default marker for this role
222
- return profile.roleMarkers?.[roleSpec.role]?.primary;
223
- }
224
-
225
- /**
226
- * Sort roles by word order for pattern building.
227
- *
228
- * Exported so the renderer sorts with exactly this comparator — a rendered
229
- * surface whose role order differs from the generated pattern would not re-parse.
230
- */
231
- export function sortRolesByWordOrder(roles: RoleSpec[], wordOrder: string): RoleSpec[] {
232
- const sorted = [...roles];
233
-
234
- if (wordOrder === 'SVO') {
235
- // Sort by svoPosition (higher = earlier)
236
- sorted.sort((a, b) => (b.svoPosition ?? 0) - (a.svoPosition ?? 0));
237
- } else if (wordOrder === 'SOV') {
238
- // Sort by sovPosition (higher = earlier)
239
- sorted.sort((a, b) => (b.sovPosition ?? 0) - (a.sovPosition ?? 0));
240
- }
241
- // VSO and others use SVO-style ordering
242
-
243
- return sorted;
244
- }
245
-
246
- /**
247
- * Build extraction rules for capturing role values during parsing.
248
- */
249
- function buildExtractionRules(
250
- schema: CommandSchema,
251
- profile: PatternGenLanguageProfile
252
- ): Record<string, ExtractionRule> {
253
- const rules: Record<string, ExtractionRule> = {};
254
-
255
- for (const roleSpec of schema.roles) {
256
- // Build the rule object correctly with readonly properties
257
- const marker = getMarkerForRole(roleSpec, profile);
258
-
259
- const rule: ExtractionRule = {
260
- ...(roleSpec.default !== undefined && { default: roleSpec.default }),
261
- ...(marker && { marker }),
262
- };
263
-
264
- rules[roleSpec.role] = rule;
265
- }
266
-
267
- return rules;
268
- }
269
-
270
- /**
271
- * Build a human-readable format string for the pattern.
272
- */
273
- function buildFormatString(
274
- schema: CommandSchema,
275
- profile: PatternGenLanguageProfile,
276
- keyword: string
277
- ): string {
278
- const isSOV = profile.wordOrder === 'SOV';
279
- const preVerb: string[] = [];
280
- const postVerb: string[] = [];
281
-
282
- // Order roles the same way buildTokens does (descending position). Iterating
283
- // declaration order here would disagree with the token order whenever a
284
- // schema's roles are declared in a different order than their positions imply.
285
- const sortedRoles = sortRolesByWordOrder(schema.roles, profile.wordOrder);
286
- for (const role of sortedRoles) {
287
- const marker = getMarkerForRole(role, profile);
288
- const roleName = `{${role.role}}`;
289
- // Same pre/post-verb split buildTokens applies, so the documented format
290
- // string keeps describing the tokens it is generated alongside.
291
- const bucket = isSOV && role.sovSlot === 'postVerb' ? postVerb : preVerb;
292
-
293
- if (marker) {
294
- const markerInfo = profile.roleMarkers?.[role.role];
295
- if (markerInfo?.position === 'after') {
296
- bucket.push(`${roleName} ${marker}`);
297
- } else {
298
- bucket.push(`${marker} ${roleName}`);
299
- }
300
- } else {
301
- bucket.push(roleName);
302
- }
303
- }
304
-
305
- return (isSOV ? [...preVerb, keyword, ...postVerb] : [keyword, ...preVerb, ...postVerb]).join(
306
- ' '
307
- );
308
- }
309
-
310
- /**
311
- * Generate multiple pattern variants (with and without optional roles).
312
- */
313
- export function generatePatternVariants(
314
- schema: CommandSchema,
315
- profile: PatternGenLanguageProfile,
316
- config: GeneratorConfig = defaultConfig
317
- ): LanguagePattern[] {
318
- const patterns: LanguagePattern[] = [];
319
-
320
- // Main pattern (all roles)
321
- patterns.push(generatePattern(schema, profile, config));
322
-
323
- // TODO: Generate variants with optional roles omitted
324
- // This can be added later when needed
325
-
326
- return patterns;
327
- }