@lokascript/framework 4.8.0 → 5.0.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.
- package/CHANGELOG.md +42 -1
- package/dist/api/create-dsl.d.ts +9 -10
- package/dist/api/create-dsl.d.ts.map +1 -1
- package/dist/api/index.js +835 -1670
- package/dist/api/index.js.map +1 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +549 -1132
- package/dist/core/index.js.map +1 -1
- package/dist/core/matching/index.d.ts +2 -0
- package/dist/core/matching/index.d.ts.map +1 -1
- package/dist/core/matching/possessive-keywords.d.ts.map +1 -0
- package/dist/core/matching/stock-confidence.d.ts +3 -4
- package/dist/core/matching/stock-confidence.d.ts.map +1 -1
- package/dist/core/matching/stock-reading.d.ts +4 -4
- package/dist/core/{pattern-matching/utils → matching}/type-validation.d.ts +1 -1
- package/dist/core/matching/type-validation.d.ts.map +1 -0
- package/dist/generation/index.d.ts +1 -1
- package/dist/generation/index.d.ts.map +1 -1
- package/dist/generation/index.js +20 -169
- package/dist/generation/index.js.map +1 -1
- package/dist/generation/profile.d.ts +30 -0
- package/dist/generation/profile.d.ts.map +1 -0
- package/dist/generation/renderer.d.ts +1 -1
- package/dist/generation/renderer.d.ts.map +1 -1
- package/dist/generation/schema-patterns.d.ts +3 -3
- package/dist/index.cjs +929 -1674
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +929 -1668
- package/dist/index.js.map +1 -1
- package/dist/multilingual/builders.d.ts +3 -3
- package/dist/multilingual/builders.d.ts.map +1 -1
- package/dist/multilingual/index.js.map +1 -1
- package/dist/parsing/index.d.ts +0 -1
- package/dist/parsing/index.d.ts.map +1 -1
- package/dist/parsing/index.js +0 -1145
- package/dist/parsing/index.js.map +1 -1
- package/dist/testing/gate/lint/types.d.ts +1 -1
- package/dist/testing/gate/lint/types.d.ts.map +1 -1
- package/package.json +2 -7
- package/src/__test__/test-utils.ts +1 -1
- package/src/api/create-dsl-engine.test.ts +60 -35
- package/src/api/create-dsl.ts +24 -35
- package/src/core/index.ts +0 -1
- package/src/core/matching/index.ts +2 -0
- package/src/core/matching/stock-confidence.ts +3 -4
- package/src/core/matching/stock-reading.ts +6 -6
- package/src/core/{pattern-matching/utils → matching}/type-validation.test.ts +2 -2
- package/src/core/{pattern-matching/utils → matching}/type-validation.ts +1 -1
- package/src/generation/domain-renderer.test.ts +1 -1
- package/src/generation/index.ts +1 -1
- package/src/generation/profile.ts +41 -0
- package/src/generation/renderer.test.ts +1 -1
- package/src/generation/renderer.ts +1 -1
- package/src/generation/schema-patterns.ts +3 -3
- package/src/multilingual/bridge.test.ts +31 -23
- package/src/multilingual/builders.ts +3 -3
- package/src/parsing/index.ts +0 -1
- package/src/testing/gate/lint/types.ts +1 -1
- package/dist/core/pattern-matching/index.d.ts +0 -6
- package/dist/core/pattern-matching/index.d.ts.map +0 -1
- package/dist/core/pattern-matching/index.js +0 -1211
- package/dist/core/pattern-matching/index.js.map +0 -1
- package/dist/core/pattern-matching/pattern-matcher.d.ts +0 -122
- package/dist/core/pattern-matching/pattern-matcher.d.ts.map +0 -1
- package/dist/core/pattern-matching/utils/index.d.ts +0 -6
- package/dist/core/pattern-matching/utils/index.d.ts.map +0 -1
- package/dist/core/pattern-matching/utils/possessive-keywords.d.ts.map +0 -1
- package/dist/core/pattern-matching/utils/type-validation.d.ts.map +0 -1
- package/dist/generation/pattern-generator.d.ts +0 -55
- package/dist/generation/pattern-generator.d.ts.map +0 -1
- package/src/core/pattern-matching/index.ts +0 -6
- package/src/core/pattern-matching/pattern-matcher.test.ts +0 -1031
- package/src/core/pattern-matching/pattern-matcher.ts +0 -765
- package/src/core/pattern-matching/utils/index.ts +0 -6
- package/src/generation/pattern-generator.test.ts +0 -532
- package/src/generation/pattern-generator.ts +0 -327
- /package/dist/core/{pattern-matching/utils → matching}/possessive-keywords.d.ts +0 -0
- /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
|
-
}
|
|
File without changes
|
|
File without changes
|