@lokascript/framework 2.1.0 → 2.2.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/dist/api/index.js +111 -24
- package/dist/api/index.js.map +1 -1
- package/dist/core/index.js +133 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/pattern-matching/index.js.map +1 -1
- package/dist/core/tokenization/index.js +133 -0
- package/dist/core/tokenization/index.js.map +1 -1
- package/dist/core/tokenization/morphology/base-normalizer.d.ts +94 -0
- package/dist/core/tokenization/morphology/base-normalizer.d.ts.map +1 -0
- package/dist/core/tokenization/morphology/index.d.ts +3 -1
- package/dist/core/tokenization/morphology/index.d.ts.map +1 -1
- package/dist/core/types.d.ts +3 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/generation/index.js.map +1 -1
- package/dist/index.cjs +564 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +556 -46
- package/dist/index.js.map +1 -1
- package/dist/ir/explicit-parser.d.ts +62 -7
- package/dist/ir/explicit-parser.d.ts.map +1 -1
- package/dist/ir/explicit-renderer.d.ts +18 -1
- package/dist/ir/explicit-renderer.d.ts.map +1 -1
- package/dist/ir/index.d.ts +4 -2
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js +423 -46
- package/dist/ir/index.js.map +1 -1
- package/dist/ir/protocol-json.d.ts.map +1 -1
- package/dist/ir/to-runtime-ast.d.ts +53 -0
- package/dist/ir/to-runtime-ast.d.ts.map +1 -0
- package/dist/ir/types.d.ts +14 -4
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/parsing/index.js.map +1 -1
- package/dist/testing/index.js +8671 -8261
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/tokenization/morphology/base-normalizer.ts +249 -0
- package/src/core/tokenization/morphology/index.ts +3 -1
- package/src/core/types.ts +4 -2
- package/src/index.ts +7 -0
- package/src/ir/conformance.test.ts +120 -0
- package/src/ir/explicit-parser.test.ts +307 -1
- package/src/ir/explicit-parser.ts +403 -29
- package/src/ir/explicit-renderer.test.ts +87 -2
- package/src/ir/explicit-renderer.ts +57 -5
- package/src/ir/index.ts +13 -2
- package/src/ir/protocol-json.test.ts +4 -2
- package/src/ir/protocol-json.ts +30 -24
- package/src/ir/to-runtime-ast.ts +203 -0
- package/src/ir/types.ts +14 -4
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AOTOrchestrator: () => AOTOrchestrator,
|
|
24
|
+
BaseMorphologicalNormalizer: () => BaseMorphologicalNormalizer,
|
|
24
25
|
BaseTokenizer: () => BaseTokenizer,
|
|
25
26
|
CrossDomainDispatcher: () => CrossDomainDispatcher,
|
|
26
27
|
DEFAULT_OPERATORS: () => DEFAULT_OPERATORS,
|
|
@@ -103,8 +104,10 @@ __export(index_exports, {
|
|
|
103
104
|
isCSSPropertyRef: () => isCSSPropertyRef,
|
|
104
105
|
isCSSSelector: () => isCSSSelector,
|
|
105
106
|
isClassName: () => isClassName,
|
|
107
|
+
isCompoundSyntax: () => isCompoundSyntax,
|
|
106
108
|
isContextAwareExtractor: () => isContextAwareExtractor,
|
|
107
109
|
isDigit: () => isDigit,
|
|
110
|
+
isDocumentSyntax: () => isDocumentSyntax,
|
|
108
111
|
isEnvelope: () => isEnvelope,
|
|
109
112
|
isExplicitSyntax: () => isExplicitSyntax,
|
|
110
113
|
isIdSelector: () => isIdSelector,
|
|
@@ -128,14 +131,19 @@ __export(index_exports, {
|
|
|
128
131
|
needsDisambiguation: () => needsDisambiguation,
|
|
129
132
|
noChange: () => noChange,
|
|
130
133
|
normalized: () => normalized,
|
|
134
|
+
parseCompound: () => parseCompound,
|
|
135
|
+
parseDocument: () => parseDocument,
|
|
131
136
|
parseExplicit: () => parseExplicit,
|
|
132
137
|
parseJSONL: () => parseJSONL,
|
|
133
138
|
patternMatcher: () => patternMatcher,
|
|
134
139
|
registryToAOTBackends: () => registryToAOTBackends,
|
|
140
|
+
renderDocument: () => renderDocument,
|
|
135
141
|
renderExplicit: () => renderExplicit,
|
|
136
142
|
renderExpr: () => renderExpr,
|
|
137
143
|
reorderRoles: () => reorderRoles,
|
|
138
144
|
semanticNodeToJSON: () => semanticNodeToJSON,
|
|
145
|
+
semanticNodeToRuntimeAST: () => semanticNodeToRuntimeAST,
|
|
146
|
+
semanticValueToAST: () => semanticValueToAST,
|
|
139
147
|
synthesizeFromSchemas: () => synthesizeFromSchemas,
|
|
140
148
|
toEnvelopeJSON: () => toEnvelopeJSON,
|
|
141
149
|
toJSONL: () => toJSONL,
|
|
@@ -2198,6 +2206,8 @@ function isNestedCommand(value) {
|
|
|
2198
2206
|
}
|
|
2199
2207
|
function parseExplicit(input, options = {}) {
|
|
2200
2208
|
const trimmed = input.trim();
|
|
2209
|
+
const collect = options.collectDiagnostics === true;
|
|
2210
|
+
const diagnostics = [];
|
|
2201
2211
|
if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
|
|
2202
2212
|
throw new Error("Explicit syntax must be wrapped in brackets: [command role:value ...]");
|
|
2203
2213
|
}
|
|
@@ -2220,10 +2230,30 @@ function parseExplicit(input, options = {}) {
|
|
|
2220
2230
|
const enabled = token.startsWith("+");
|
|
2221
2231
|
const flagName = token.slice(1);
|
|
2222
2232
|
if (!flagName) {
|
|
2233
|
+
if (collect) {
|
|
2234
|
+
diagnostics.push({
|
|
2235
|
+
severity: "error",
|
|
2236
|
+
code: "EMPTY_FLAG",
|
|
2237
|
+
message: `Empty flag name: "${token}"`,
|
|
2238
|
+
source: "schema"
|
|
2239
|
+
});
|
|
2240
|
+
continue;
|
|
2241
|
+
}
|
|
2223
2242
|
throw new Error(`Empty flag name: "${token}"`);
|
|
2224
2243
|
}
|
|
2225
2244
|
if (validRoleNames && !validRoleNames.has(flagName)) {
|
|
2226
2245
|
const roleList = [...validRoleNames].join(", ");
|
|
2246
|
+
if (collect) {
|
|
2247
|
+
diagnostics.push({
|
|
2248
|
+
severity: "error",
|
|
2249
|
+
code: "UNKNOWN_FLAG",
|
|
2250
|
+
message: `Unknown flag "${flagName}" for command "${command}"`,
|
|
2251
|
+
source: "schema",
|
|
2252
|
+
suggestions: [...validRoleNames].map((r) => `+${r}`)
|
|
2253
|
+
});
|
|
2254
|
+
roles.set(flagName, createFlag(flagName, enabled));
|
|
2255
|
+
continue;
|
|
2256
|
+
}
|
|
2227
2257
|
throw new Error(
|
|
2228
2258
|
`Unknown flag "${flagName}" for command "${command}". Valid roles: ${roleList}`
|
|
2229
2259
|
);
|
|
@@ -2233,14 +2263,33 @@ function parseExplicit(input, options = {}) {
|
|
|
2233
2263
|
}
|
|
2234
2264
|
const colonIndex = token.indexOf(":");
|
|
2235
2265
|
if (colonIndex === -1) {
|
|
2266
|
+
if (collect) {
|
|
2267
|
+
diagnostics.push({
|
|
2268
|
+
severity: "error",
|
|
2269
|
+
code: "INVALID_ROLE_FORMAT",
|
|
2270
|
+
message: `Invalid role format: "${token}". Expected role:value or +flag`,
|
|
2271
|
+
source: "schema"
|
|
2272
|
+
});
|
|
2273
|
+
continue;
|
|
2274
|
+
}
|
|
2236
2275
|
throw new Error(`Invalid role format: "${token}". Expected role:value or +flag`);
|
|
2237
2276
|
}
|
|
2238
2277
|
const roleName = token.slice(0, colonIndex);
|
|
2239
2278
|
if (validRoleNames && !STRUCTURAL_ROLES.has(roleName) && !validRoleNames.has(roleName)) {
|
|
2240
2279
|
const roleList = [...validRoleNames].join(", ");
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2280
|
+
if (collect) {
|
|
2281
|
+
diagnostics.push({
|
|
2282
|
+
severity: "error",
|
|
2283
|
+
code: "UNKNOWN_ROLE",
|
|
2284
|
+
message: `Unknown role "${roleName}" for command "${command}"`,
|
|
2285
|
+
source: "schema",
|
|
2286
|
+
suggestions: [...validRoleNames]
|
|
2287
|
+
});
|
|
2288
|
+
} else {
|
|
2289
|
+
throw new Error(
|
|
2290
|
+
`Unknown role "${roleName}" for command "${command}". Valid roles: ${roleList}`
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2244
2293
|
}
|
|
2245
2294
|
const role = roleName;
|
|
2246
2295
|
const valueStr = token.slice(colonIndex + 1);
|
|
@@ -2256,37 +2305,67 @@ function parseExplicit(input, options = {}) {
|
|
|
2256
2305
|
if (schema && command !== "on") {
|
|
2257
2306
|
for (const roleSpec of schema.roles) {
|
|
2258
2307
|
if (roleSpec.required && !roles.has(roleSpec.role) && !roleSpec.default) {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2308
|
+
if (collect) {
|
|
2309
|
+
diagnostics.push({
|
|
2310
|
+
severity: "error",
|
|
2311
|
+
code: "MISSING_REQUIRED_ROLE",
|
|
2312
|
+
message: `Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`,
|
|
2313
|
+
source: "schema"
|
|
2314
|
+
});
|
|
2315
|
+
} else {
|
|
2316
|
+
throw new Error(
|
|
2317
|
+
`Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2262
2320
|
}
|
|
2263
2321
|
}
|
|
2264
2322
|
}
|
|
2323
|
+
const attachDiagnostics = (node) => {
|
|
2324
|
+
if (diagnostics.length === 0) return node;
|
|
2325
|
+
return { ...node, diagnostics };
|
|
2326
|
+
};
|
|
2265
2327
|
switch (command) {
|
|
2266
2328
|
case "on": {
|
|
2267
2329
|
const eventValue = roles.get("event");
|
|
2268
2330
|
if (!eventValue) {
|
|
2331
|
+
if (collect) {
|
|
2332
|
+
diagnostics.push({
|
|
2333
|
+
severity: "error",
|
|
2334
|
+
code: "MISSING_EVENT_ROLE",
|
|
2335
|
+
message: "Event handler requires event role: [on event:click ...]",
|
|
2336
|
+
source: "schema"
|
|
2337
|
+
});
|
|
2338
|
+
return attachDiagnostics(
|
|
2339
|
+
createEventHandlerNode("on", roles, [], {
|
|
2340
|
+
sourceLanguage: "explicit"
|
|
2341
|
+
})
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2269
2344
|
throw new Error("Event handler requires event role: [on event:click ...]");
|
|
2270
2345
|
}
|
|
2271
2346
|
const body = extractStructuralBody(roles, "body", options);
|
|
2272
2347
|
roles.delete("body");
|
|
2273
|
-
return
|
|
2274
|
-
|
|
2275
|
-
|
|
2348
|
+
return attachDiagnostics(
|
|
2349
|
+
createEventHandlerNode("on", roles, body, {
|
|
2350
|
+
sourceLanguage: "explicit"
|
|
2351
|
+
})
|
|
2352
|
+
);
|
|
2276
2353
|
}
|
|
2277
2354
|
case "if": {
|
|
2278
2355
|
const thenBranch = extractStructuralBody(roles, "then", options);
|
|
2279
2356
|
const elseBranch = extractStructuralBody(roles, "else", options);
|
|
2280
2357
|
roles.delete("then");
|
|
2281
2358
|
roles.delete("else");
|
|
2282
|
-
return
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2359
|
+
return attachDiagnostics(
|
|
2360
|
+
createConditionalNode(
|
|
2361
|
+
command,
|
|
2362
|
+
roles,
|
|
2363
|
+
thenBranch,
|
|
2364
|
+
elseBranch.length > 0 ? elseBranch : void 0,
|
|
2365
|
+
{
|
|
2366
|
+
sourceLanguage: "explicit"
|
|
2367
|
+
}
|
|
2368
|
+
)
|
|
2290
2369
|
);
|
|
2291
2370
|
}
|
|
2292
2371
|
case "repeat": {
|
|
@@ -2312,20 +2391,182 @@ function parseExplicit(input, options = {}) {
|
|
|
2312
2391
|
}
|
|
2313
2392
|
const loopVariable = variableValue?.type === "literal" && typeof variableValue.value === "string" ? variableValue.value : variableValue?.type === "expression" ? variableValue.raw : void 0;
|
|
2314
2393
|
const indexVariable = indexVariableValue?.type === "literal" && typeof indexVariableValue.value === "string" ? indexVariableValue.value : void 0;
|
|
2315
|
-
return
|
|
2316
|
-
|
|
2317
|
-
|
|
2394
|
+
return attachDiagnostics(
|
|
2395
|
+
createLoopNode(command, roles, variant, loopBody, loopVariable, indexVariable, {
|
|
2396
|
+
sourceLanguage: "explicit"
|
|
2397
|
+
})
|
|
2398
|
+
);
|
|
2318
2399
|
}
|
|
2319
2400
|
default:
|
|
2320
|
-
return
|
|
2321
|
-
|
|
2322
|
-
|
|
2401
|
+
return attachDiagnostics(
|
|
2402
|
+
createCommandNode(command, roles, {
|
|
2403
|
+
sourceLanguage: "explicit"
|
|
2404
|
+
})
|
|
2405
|
+
);
|
|
2323
2406
|
}
|
|
2324
2407
|
}
|
|
2325
2408
|
function isExplicitSyntax(input) {
|
|
2326
2409
|
const trimmed = input.trim();
|
|
2327
2410
|
return trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
2328
2411
|
}
|
|
2412
|
+
var CHAIN_KEYWORDS = /* @__PURE__ */ new Set(["then", "and", "async", "sequential"]);
|
|
2413
|
+
function splitCompoundSegments(input) {
|
|
2414
|
+
const segments = [];
|
|
2415
|
+
let chainType = null;
|
|
2416
|
+
let current = "";
|
|
2417
|
+
let bracketDepth = 0;
|
|
2418
|
+
let inString = false;
|
|
2419
|
+
let stringChar = "";
|
|
2420
|
+
for (let i = 0; i < input.length; i++) {
|
|
2421
|
+
const char = input[i];
|
|
2422
|
+
if (inString) {
|
|
2423
|
+
current += char;
|
|
2424
|
+
if (char === stringChar && input[i - 1] !== "\\") {
|
|
2425
|
+
inString = false;
|
|
2426
|
+
}
|
|
2427
|
+
continue;
|
|
2428
|
+
}
|
|
2429
|
+
if (char === '"' || char === "'") {
|
|
2430
|
+
inString = true;
|
|
2431
|
+
stringChar = char;
|
|
2432
|
+
current += char;
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
if (char === "[") {
|
|
2436
|
+
bracketDepth++;
|
|
2437
|
+
current += char;
|
|
2438
|
+
continue;
|
|
2439
|
+
}
|
|
2440
|
+
if (char === "]") {
|
|
2441
|
+
bracketDepth--;
|
|
2442
|
+
current += char;
|
|
2443
|
+
if (bracketDepth === 0) {
|
|
2444
|
+
const rest = input.slice(i + 1);
|
|
2445
|
+
const pipeMatch = rest.match(/^\s*\|>\s*/);
|
|
2446
|
+
if (pipeMatch) {
|
|
2447
|
+
segments.push(current.trim());
|
|
2448
|
+
current = "";
|
|
2449
|
+
chainType ?? (chainType = "pipe");
|
|
2450
|
+
i += pipeMatch[0].length;
|
|
2451
|
+
continue;
|
|
2452
|
+
}
|
|
2453
|
+
const keywordMatch = rest.match(/^\s+(then|and|async|sequential)\s+/);
|
|
2454
|
+
if (keywordMatch && CHAIN_KEYWORDS.has(keywordMatch[1])) {
|
|
2455
|
+
segments.push(current.trim());
|
|
2456
|
+
current = "";
|
|
2457
|
+
chainType ?? (chainType = keywordMatch[1]);
|
|
2458
|
+
i += keywordMatch[0].length;
|
|
2459
|
+
continue;
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
current += char;
|
|
2465
|
+
}
|
|
2466
|
+
if (current.trim()) {
|
|
2467
|
+
segments.push(current.trim());
|
|
2468
|
+
}
|
|
2469
|
+
return { segments, chainType };
|
|
2470
|
+
}
|
|
2471
|
+
function parseCompound(input, options) {
|
|
2472
|
+
const trimmed = input.trim();
|
|
2473
|
+
const { annotations, remainder } = extractAnnotations(trimmed);
|
|
2474
|
+
const { segments, chainType } = splitCompoundSegments(remainder);
|
|
2475
|
+
let node;
|
|
2476
|
+
if (segments.length <= 1) {
|
|
2477
|
+
node = parseExplicit(segments[0] || remainder, options);
|
|
2478
|
+
} else {
|
|
2479
|
+
const statements = segments.map((seg) => parseExplicit(seg, options));
|
|
2480
|
+
node = createCompoundNode(statements, chainType ?? "sequential");
|
|
2481
|
+
}
|
|
2482
|
+
if (annotations.length > 0) {
|
|
2483
|
+
return { ...node, annotations };
|
|
2484
|
+
}
|
|
2485
|
+
return node;
|
|
2486
|
+
}
|
|
2487
|
+
function extractAnnotations(input) {
|
|
2488
|
+
const annotations = [];
|
|
2489
|
+
let pos = 0;
|
|
2490
|
+
while (pos < input.length) {
|
|
2491
|
+
while (pos < input.length && (input[pos] === " " || input[pos] === " ")) {
|
|
2492
|
+
pos++;
|
|
2493
|
+
}
|
|
2494
|
+
if (pos >= input.length || input[pos] !== "@") {
|
|
2495
|
+
break;
|
|
2496
|
+
}
|
|
2497
|
+
pos++;
|
|
2498
|
+
const nameStart = pos;
|
|
2499
|
+
while (pos < input.length && /[A-Za-z0-9\-_]/.test(input[pos])) {
|
|
2500
|
+
pos++;
|
|
2501
|
+
}
|
|
2502
|
+
const name = input.slice(nameStart, pos);
|
|
2503
|
+
if (!name) break;
|
|
2504
|
+
let value;
|
|
2505
|
+
if (pos < input.length && input[pos] === "(") {
|
|
2506
|
+
pos++;
|
|
2507
|
+
const valueStart = pos;
|
|
2508
|
+
if (pos < input.length && (input[pos] === '"' || input[pos] === "'")) {
|
|
2509
|
+
const quote = input[pos];
|
|
2510
|
+
pos++;
|
|
2511
|
+
while (pos < input.length && input[pos] !== quote) {
|
|
2512
|
+
if (input[pos] === "\\") pos++;
|
|
2513
|
+
pos++;
|
|
2514
|
+
}
|
|
2515
|
+
pos++;
|
|
2516
|
+
value = input.slice(valueStart + 1, pos - 1);
|
|
2517
|
+
} else {
|
|
2518
|
+
while (pos < input.length && input[pos] !== ")") {
|
|
2519
|
+
pos++;
|
|
2520
|
+
}
|
|
2521
|
+
value = input.slice(valueStart, pos);
|
|
2522
|
+
}
|
|
2523
|
+
if (pos < input.length && input[pos] === ")") {
|
|
2524
|
+
pos++;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
annotations.push(value !== void 0 ? { name, value } : { name });
|
|
2528
|
+
}
|
|
2529
|
+
return { annotations, remainder: input.slice(pos).trim() };
|
|
2530
|
+
}
|
|
2531
|
+
var VERSION_HEADER_RE = /^#!lse\s+(\d+\.\d+(?:\.\d+)?)\s*$/;
|
|
2532
|
+
function parseDocument(input, options) {
|
|
2533
|
+
const lines = input.split("\n");
|
|
2534
|
+
let lseVersion = "1.0";
|
|
2535
|
+
const nodes = [];
|
|
2536
|
+
let startLine = 0;
|
|
2537
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2538
|
+
const trimmed = lines[i].trim();
|
|
2539
|
+
if (!trimmed) continue;
|
|
2540
|
+
const versionMatch = trimmed.match(VERSION_HEADER_RE);
|
|
2541
|
+
if (versionMatch) {
|
|
2542
|
+
lseVersion = versionMatch[1];
|
|
2543
|
+
startLine = i + 1;
|
|
2544
|
+
}
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
2548
|
+
const trimmed = lines[i].trim();
|
|
2549
|
+
if (!trimmed) continue;
|
|
2550
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
|
|
2551
|
+
continue;
|
|
2552
|
+
}
|
|
2553
|
+
nodes.push(parseCompound(trimmed, options));
|
|
2554
|
+
}
|
|
2555
|
+
return { lseVersion, nodes };
|
|
2556
|
+
}
|
|
2557
|
+
function isCompoundSyntax(input) {
|
|
2558
|
+
const { segments } = splitCompoundSegments(input.trim());
|
|
2559
|
+
return segments.length > 1;
|
|
2560
|
+
}
|
|
2561
|
+
function isDocumentSyntax(input) {
|
|
2562
|
+
const trimmed = input.trim();
|
|
2563
|
+
if (trimmed.includes("\n")) return true;
|
|
2564
|
+
if (VERSION_HEADER_RE.test(trimmed)) return true;
|
|
2565
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
|
|
2566
|
+
return true;
|
|
2567
|
+
}
|
|
2568
|
+
return false;
|
|
2569
|
+
}
|
|
2329
2570
|
function extractStructuralBody(roles, roleName, options) {
|
|
2330
2571
|
const value = roles.get(roleName);
|
|
2331
2572
|
if (!value) return [];
|
|
@@ -2427,11 +2668,33 @@ function findMatchingBracket(str, start) {
|
|
|
2427
2668
|
|
|
2428
2669
|
// src/ir/explicit-renderer.ts
|
|
2429
2670
|
function renderExplicit(node) {
|
|
2671
|
+
let result;
|
|
2430
2672
|
if (node.kind === "compound") {
|
|
2431
2673
|
const compoundNode = node;
|
|
2432
2674
|
const renderedStatements = compoundNode.statements.map((stmt) => renderExplicit(stmt));
|
|
2433
|
-
|
|
2675
|
+
result = renderedStatements.join(` ${compoundNode.chainType} `);
|
|
2676
|
+
} else {
|
|
2677
|
+
result = renderBracketCommand(node);
|
|
2434
2678
|
}
|
|
2679
|
+
if (node.annotations && node.annotations.length > 0) {
|
|
2680
|
+
const annParts = node.annotations.map(
|
|
2681
|
+
(ann) => ann.value !== void 0 ? `@${ann.name}(${ann.value})` : `@${ann.name}`
|
|
2682
|
+
);
|
|
2683
|
+
return annParts.join(" ") + " " + result;
|
|
2684
|
+
}
|
|
2685
|
+
return result;
|
|
2686
|
+
}
|
|
2687
|
+
function renderDocument(envelope) {
|
|
2688
|
+
const lines = [];
|
|
2689
|
+
if (envelope.lseVersion && envelope.lseVersion !== "1.0") {
|
|
2690
|
+
lines.push(`#!lse ${envelope.lseVersion}`);
|
|
2691
|
+
}
|
|
2692
|
+
for (const node of envelope.nodes) {
|
|
2693
|
+
lines.push(renderExplicit(node));
|
|
2694
|
+
}
|
|
2695
|
+
return lines.join("\n");
|
|
2696
|
+
}
|
|
2697
|
+
function renderBracketCommand(node) {
|
|
2435
2698
|
const parts = [node.action];
|
|
2436
2699
|
for (const [role, value] of node.roles) {
|
|
2437
2700
|
if (value.type === "flag") {
|
|
@@ -2769,12 +3032,16 @@ function toProtocolJSON(node) {
|
|
|
2769
3032
|
);
|
|
2770
3033
|
}
|
|
2771
3034
|
if (node.diagnostics && node.diagnostics.length > 0) {
|
|
2772
|
-
result.diagnostics = node.diagnostics.map((d) =>
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
3035
|
+
result.diagnostics = node.diagnostics.map((d) => {
|
|
3036
|
+
const json = {
|
|
3037
|
+
level: d.severity,
|
|
3038
|
+
message: d.message
|
|
3039
|
+
};
|
|
3040
|
+
if (d.code) json.code = d.code;
|
|
3041
|
+
if (d.source) json.source = d.source;
|
|
3042
|
+
if (d.suggestions && d.suggestions.length > 0) json.suggestions = [...d.suggestions];
|
|
3043
|
+
return json;
|
|
3044
|
+
});
|
|
2778
3045
|
}
|
|
2779
3046
|
return result;
|
|
2780
3047
|
}
|
|
@@ -2822,10 +3089,11 @@ function fromProtocolJSON(json) {
|
|
|
2822
3089
|
(a) => a.value !== void 0 ? { name: a.name, value: a.value } : { name: a.name }
|
|
2823
3090
|
);
|
|
2824
3091
|
const diagnostics = json.diagnostics?.map((d) => ({
|
|
2825
|
-
|
|
2826
|
-
role: d.role,
|
|
3092
|
+
severity: d.level,
|
|
2827
3093
|
message: d.message,
|
|
2828
|
-
code: d.code
|
|
3094
|
+
...d.code ? { code: d.code } : {},
|
|
3095
|
+
...d.source ? { source: d.source } : {},
|
|
3096
|
+
...d.suggestions && d.suggestions.length > 0 ? { suggestions: d.suggestions } : {}
|
|
2829
3097
|
}));
|
|
2830
3098
|
if (json.trigger) {
|
|
2831
3099
|
const eventName = json.trigger.event;
|
|
@@ -2966,7 +3234,7 @@ var VALID_VALUE_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
2966
3234
|
]);
|
|
2967
3235
|
var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set(["then", "and", "async", "sequential", "pipe"]);
|
|
2968
3236
|
var VALID_ASYNC_VARIANTS = /* @__PURE__ */ new Set(["all", "race"]);
|
|
2969
|
-
var VALID_DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set(["error", "warning"]);
|
|
3237
|
+
var VALID_DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set(["error", "warning", "info"]);
|
|
2970
3238
|
function validateProtocolJSON(json) {
|
|
2971
3239
|
const diagnostics = [];
|
|
2972
3240
|
if (typeof json !== "object" || json === null) {
|
|
@@ -3115,14 +3383,7 @@ function validateProtocolJSON(json) {
|
|
|
3115
3383
|
diagnostics.push({
|
|
3116
3384
|
severity: "error",
|
|
3117
3385
|
code: "INVALID_DIAGNOSTIC_LEVEL",
|
|
3118
|
-
message: `diagnostics[${i}].level must be "error" or "
|
|
3119
|
-
});
|
|
3120
|
-
}
|
|
3121
|
-
if (typeof d.role !== "string") {
|
|
3122
|
-
diagnostics.push({
|
|
3123
|
-
severity: "error",
|
|
3124
|
-
code: "MISSING_DIAGNOSTIC_ROLE",
|
|
3125
|
-
message: `diagnostics[${i}] missing required field: role`
|
|
3386
|
+
message: `diagnostics[${i}].level must be "error", "warning", or "info"`
|
|
3126
3387
|
});
|
|
3127
3388
|
}
|
|
3128
3389
|
if (typeof d.message !== "string") {
|
|
@@ -3132,11 +3393,11 @@ function validateProtocolJSON(json) {
|
|
|
3132
3393
|
message: `diagnostics[${i}] missing required field: message`
|
|
3133
3394
|
});
|
|
3134
3395
|
}
|
|
3135
|
-
if (typeof d.code !== "string") {
|
|
3396
|
+
if ("code" in d && typeof d.code !== "string") {
|
|
3136
3397
|
diagnostics.push({
|
|
3137
|
-
severity: "
|
|
3138
|
-
code: "
|
|
3139
|
-
message: `diagnostics[${i}]
|
|
3398
|
+
severity: "warning",
|
|
3399
|
+
code: "INVALID_DIAGNOSTIC_CODE",
|
|
3400
|
+
message: `diagnostics[${i}].code must be a string if present`
|
|
3140
3401
|
});
|
|
3141
3402
|
}
|
|
3142
3403
|
}
|
|
@@ -3572,6 +3833,123 @@ function bridgeEventModifiers(mods) {
|
|
|
3572
3833
|
};
|
|
3573
3834
|
}
|
|
3574
3835
|
|
|
3836
|
+
// src/ir/to-runtime-ast.ts
|
|
3837
|
+
function semanticNodeToRuntimeAST(node) {
|
|
3838
|
+
switch (node.kind) {
|
|
3839
|
+
case "event-handler":
|
|
3840
|
+
return convertEventHandler(node);
|
|
3841
|
+
case "conditional":
|
|
3842
|
+
return convertConditional(node);
|
|
3843
|
+
case "loop":
|
|
3844
|
+
return convertLoop(node);
|
|
3845
|
+
case "compound": {
|
|
3846
|
+
const compound = node;
|
|
3847
|
+
const commands = (compound.statements ?? []).map(semanticNodeToRuntimeAST);
|
|
3848
|
+
return {
|
|
3849
|
+
type: "CommandSequence",
|
|
3850
|
+
commands
|
|
3851
|
+
};
|
|
3852
|
+
}
|
|
3853
|
+
case "command":
|
|
3854
|
+
default:
|
|
3855
|
+
return convertCommand2(node);
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
function convertEventHandler(eh) {
|
|
3859
|
+
const eventValue = eh.roles.get("event");
|
|
3860
|
+
const eventName = eventValue && "value" in eventValue ? String(eventValue.value) : "click";
|
|
3861
|
+
const modifiers = {};
|
|
3862
|
+
if (eh.eventModifiers) {
|
|
3863
|
+
if (eh.eventModifiers.once) modifiers.once = true;
|
|
3864
|
+
if (eh.eventModifiers.debounce) modifiers.debounce = eh.eventModifiers.debounce;
|
|
3865
|
+
if (eh.eventModifiers.throttle) modifiers.throttle = eh.eventModifiers.throttle;
|
|
3866
|
+
if (eh.eventModifiers.queue) modifiers.queue = eh.eventModifiers.queue;
|
|
3867
|
+
}
|
|
3868
|
+
return {
|
|
3869
|
+
type: "event",
|
|
3870
|
+
event: eventName,
|
|
3871
|
+
modifiers,
|
|
3872
|
+
body: (eh.body ?? []).map(semanticNodeToRuntimeAST)
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
function convertCommand2(node) {
|
|
3876
|
+
const roles = {};
|
|
3877
|
+
const args = [];
|
|
3878
|
+
for (const [roleName, value] of node.roles) {
|
|
3879
|
+
const astValue = semanticValueToAST(value);
|
|
3880
|
+
roles[roleName] = astValue;
|
|
3881
|
+
args.push(astValue);
|
|
3882
|
+
}
|
|
3883
|
+
return {
|
|
3884
|
+
type: "command",
|
|
3885
|
+
name: node.action,
|
|
3886
|
+
args,
|
|
3887
|
+
roles
|
|
3888
|
+
};
|
|
3889
|
+
}
|
|
3890
|
+
function convertConditional(node) {
|
|
3891
|
+
const conditionValue = node.roles.get("condition");
|
|
3892
|
+
return {
|
|
3893
|
+
type: "command",
|
|
3894
|
+
name: "if",
|
|
3895
|
+
args: conditionValue ? [semanticValueToAST(conditionValue)] : [],
|
|
3896
|
+
condition: conditionValue ? semanticValueToAST(conditionValue) : void 0,
|
|
3897
|
+
thenBranch: (node.thenBranch ?? []).map(semanticNodeToRuntimeAST),
|
|
3898
|
+
elseBranch: (node.elseBranch ?? []).map(semanticNodeToRuntimeAST)
|
|
3899
|
+
};
|
|
3900
|
+
}
|
|
3901
|
+
function convertLoop(node) {
|
|
3902
|
+
const countValue = node.roles.get("patient") || node.roles.get("count");
|
|
3903
|
+
return {
|
|
3904
|
+
type: "command",
|
|
3905
|
+
name: "repeat",
|
|
3906
|
+
args: countValue ? [semanticValueToAST(countValue)] : [],
|
|
3907
|
+
loopVariant: node.loopVariant ?? "forever",
|
|
3908
|
+
body: (node.body ?? []).map(semanticNodeToRuntimeAST),
|
|
3909
|
+
loopVariable: node.loopVariable,
|
|
3910
|
+
indexVariable: node.indexVariable
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
function semanticValueToAST(value) {
|
|
3914
|
+
switch (value.type) {
|
|
3915
|
+
case "selector":
|
|
3916
|
+
return { type: "selector", value: value.value };
|
|
3917
|
+
case "reference":
|
|
3918
|
+
return { type: "identifier", value: value.value };
|
|
3919
|
+
case "literal": {
|
|
3920
|
+
const lit = value;
|
|
3921
|
+
if (lit.dataType === "duration") {
|
|
3922
|
+
const str = String(lit.value);
|
|
3923
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s)$/.exec(str);
|
|
3924
|
+
if (match) {
|
|
3925
|
+
const ms = match[2] === "s" ? parseFloat(match[1]) * 1e3 : parseFloat(match[1]);
|
|
3926
|
+
return { type: "literal", value: ms };
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
return { type: "literal", value: lit.value };
|
|
3930
|
+
}
|
|
3931
|
+
case "property-path": {
|
|
3932
|
+
const pp = value;
|
|
3933
|
+
const objectAST = semanticValueToAST(pp.object);
|
|
3934
|
+
return {
|
|
3935
|
+
type: "member",
|
|
3936
|
+
object: objectAST,
|
|
3937
|
+
property: pp.property
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
case "expression": {
|
|
3941
|
+
const expr = value;
|
|
3942
|
+
return { type: "expression", value: expr.raw };
|
|
3943
|
+
}
|
|
3944
|
+
case "flag": {
|
|
3945
|
+
const flag = value;
|
|
3946
|
+
return { type: "literal", value: flag.enabled };
|
|
3947
|
+
}
|
|
3948
|
+
default:
|
|
3949
|
+
return { type: "literal", value: String(value.value ?? "") };
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
|
|
3575
3953
|
// src/api/create-dsl.ts
|
|
3576
3954
|
var DSLRegistry = class {
|
|
3577
3955
|
constructor(config) {
|
|
@@ -6543,6 +6921,138 @@ function normalized(stem, confidence, metadata) {
|
|
|
6543
6921
|
return { stem, confidence };
|
|
6544
6922
|
}
|
|
6545
6923
|
|
|
6924
|
+
// src/core/tokenization/morphology/base-normalizer.ts
|
|
6925
|
+
var BaseMorphologicalNormalizer = class {
|
|
6926
|
+
constructor(config) {
|
|
6927
|
+
this.language = config.language;
|
|
6928
|
+
this.config = {
|
|
6929
|
+
minWordLength: 3,
|
|
6930
|
+
minStemLength: 2,
|
|
6931
|
+
...config
|
|
6932
|
+
};
|
|
6933
|
+
}
|
|
6934
|
+
/**
|
|
6935
|
+
* Standard normalization pipeline. Override for custom behavior.
|
|
6936
|
+
*/
|
|
6937
|
+
normalize(word) {
|
|
6938
|
+
const lower = word.toLowerCase();
|
|
6939
|
+
if (this.isAlreadyNormalized(lower)) {
|
|
6940
|
+
return noChange(word);
|
|
6941
|
+
}
|
|
6942
|
+
if (this.config.reflexiveSuffixes) {
|
|
6943
|
+
const reflexive = this.tryReflexiveNormalization(lower);
|
|
6944
|
+
if (reflexive) return reflexive;
|
|
6945
|
+
}
|
|
6946
|
+
if (this.config.endings) {
|
|
6947
|
+
const conjugation = this.tryConjugationEndings(lower);
|
|
6948
|
+
if (conjugation) return conjugation;
|
|
6949
|
+
}
|
|
6950
|
+
if (this.config.suffixRules) {
|
|
6951
|
+
const suffix = this.trySuffixRules(lower);
|
|
6952
|
+
if (suffix) return suffix;
|
|
6953
|
+
}
|
|
6954
|
+
if (this.config.prefixRules) {
|
|
6955
|
+
const prefix = this.tryPrefixRules(lower);
|
|
6956
|
+
if (prefix) return prefix;
|
|
6957
|
+
}
|
|
6958
|
+
return noChange(word);
|
|
6959
|
+
}
|
|
6960
|
+
/**
|
|
6961
|
+
* Check if word is already in dictionary form (e.g., ends in -ar/-er/-ir).
|
|
6962
|
+
* Override for language-specific checks.
|
|
6963
|
+
*/
|
|
6964
|
+
isAlreadyNormalized(word) {
|
|
6965
|
+
if (this.config.infinitiveEndings) {
|
|
6966
|
+
return this.config.infinitiveEndings.some((e) => word.endsWith(e));
|
|
6967
|
+
}
|
|
6968
|
+
return false;
|
|
6969
|
+
}
|
|
6970
|
+
/**
|
|
6971
|
+
* Try to strip reflexive suffixes and normalize the remainder.
|
|
6972
|
+
* Common in Romance languages (Spanish, Portuguese, French).
|
|
6973
|
+
*/
|
|
6974
|
+
tryReflexiveNormalization(word) {
|
|
6975
|
+
const suffixes = this.config.reflexiveSuffixes;
|
|
6976
|
+
if (!suffixes) return null;
|
|
6977
|
+
for (const suffix of suffixes) {
|
|
6978
|
+
if (!word.endsWith(suffix)) continue;
|
|
6979
|
+
const remainder = word.slice(0, -suffix.length);
|
|
6980
|
+
if (this.isAlreadyNormalized(remainder)) {
|
|
6981
|
+
return normalized(remainder, 0.88, {
|
|
6982
|
+
removedSuffixes: [suffix],
|
|
6983
|
+
conjugationType: "reflexive"
|
|
6984
|
+
});
|
|
6985
|
+
}
|
|
6986
|
+
const inner = this.tryConjugationEndings(remainder) || this.trySuffixRules(remainder);
|
|
6987
|
+
if (inner && inner.stem !== remainder) {
|
|
6988
|
+
return normalized(inner.stem, inner.confidence * 0.95, {
|
|
6989
|
+
removedSuffixes: [suffix, ...inner.metadata?.removedSuffixes || []],
|
|
6990
|
+
conjugationType: "reflexive"
|
|
6991
|
+
});
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
return null;
|
|
6995
|
+
}
|
|
6996
|
+
/**
|
|
6997
|
+
* Try conjugation endings (verb class endings like -ar/-er/-ir patterns).
|
|
6998
|
+
* Endings must be pre-sorted longest-first.
|
|
6999
|
+
*/
|
|
7000
|
+
tryConjugationEndings(word) {
|
|
7001
|
+
const endings = this.config.endings;
|
|
7002
|
+
if (!endings) return null;
|
|
7003
|
+
const minStem = this.config.minStemLength ?? 2;
|
|
7004
|
+
for (const rule of endings) {
|
|
7005
|
+
if (!word.endsWith(rule.ending)) continue;
|
|
7006
|
+
const stemBase = word.slice(0, -rule.ending.length);
|
|
7007
|
+
if (stemBase.length < minStem) continue;
|
|
7008
|
+
const infinitive = stemBase + rule.stem;
|
|
7009
|
+
return normalized(infinitive, rule.confidence, {
|
|
7010
|
+
removedSuffixes: [rule.ending],
|
|
7011
|
+
conjugationType: rule.type
|
|
7012
|
+
});
|
|
7013
|
+
}
|
|
7014
|
+
return null;
|
|
7015
|
+
}
|
|
7016
|
+
/**
|
|
7017
|
+
* Try SuffixRule-style normalization.
|
|
7018
|
+
* Rules must be pre-sorted longest-first.
|
|
7019
|
+
*/
|
|
7020
|
+
trySuffixRules(word) {
|
|
7021
|
+
const rules = this.config.suffixRules;
|
|
7022
|
+
if (!rules) return null;
|
|
7023
|
+
const defaultMinStem = this.config.minStemLength ?? 2;
|
|
7024
|
+
for (const rule of rules) {
|
|
7025
|
+
if (!word.endsWith(rule.pattern)) continue;
|
|
7026
|
+
const stem = word.slice(0, -rule.pattern.length);
|
|
7027
|
+
const minStem = rule.minStemLength ?? defaultMinStem;
|
|
7028
|
+
if (stem.length < minStem) continue;
|
|
7029
|
+
const result = stem + (rule.replacement || "");
|
|
7030
|
+
return normalized(result, rule.confidence, {
|
|
7031
|
+
removedSuffixes: [rule.pattern],
|
|
7032
|
+
...rule.conjugationType && { conjugationType: rule.conjugationType }
|
|
7033
|
+
});
|
|
7034
|
+
}
|
|
7035
|
+
return null;
|
|
7036
|
+
}
|
|
7037
|
+
/**
|
|
7038
|
+
* Try PrefixRule-style normalization.
|
|
7039
|
+
*/
|
|
7040
|
+
tryPrefixRules(word) {
|
|
7041
|
+
const rules = this.config.prefixRules;
|
|
7042
|
+
if (!rules) return null;
|
|
7043
|
+
for (const rule of rules) {
|
|
7044
|
+
if (!word.startsWith(rule.pattern)) continue;
|
|
7045
|
+
const remainder = word.slice(rule.pattern.length);
|
|
7046
|
+
const minRemaining = rule.minRemaining ?? this.config.minStemLength ?? 2;
|
|
7047
|
+
if (remainder.length < minRemaining) continue;
|
|
7048
|
+
return normalized(remainder, 1 - rule.confidencePenalty, {
|
|
7049
|
+
removedPrefixes: [rule.pattern]
|
|
7050
|
+
});
|
|
7051
|
+
}
|
|
7052
|
+
return null;
|
|
7053
|
+
}
|
|
7054
|
+
};
|
|
7055
|
+
|
|
6546
7056
|
// src/training/jsonl-writer.ts
|
|
6547
7057
|
function toJSONL(pairs) {
|
|
6548
7058
|
return pairs.map((pair) => JSON.stringify(toJSONLRow(pair))).join("\n");
|
|
@@ -6940,6 +7450,7 @@ function accumulateIndented(statements, config) {
|
|
|
6940
7450
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6941
7451
|
0 && (module.exports = {
|
|
6942
7452
|
AOTOrchestrator,
|
|
7453
|
+
BaseMorphologicalNormalizer,
|
|
6943
7454
|
BaseTokenizer,
|
|
6944
7455
|
CrossDomainDispatcher,
|
|
6945
7456
|
DEFAULT_OPERATORS,
|
|
@@ -7022,8 +7533,10 @@ function accumulateIndented(statements, config) {
|
|
|
7022
7533
|
isCSSPropertyRef,
|
|
7023
7534
|
isCSSSelector,
|
|
7024
7535
|
isClassName,
|
|
7536
|
+
isCompoundSyntax,
|
|
7025
7537
|
isContextAwareExtractor,
|
|
7026
7538
|
isDigit,
|
|
7539
|
+
isDocumentSyntax,
|
|
7027
7540
|
isEnvelope,
|
|
7028
7541
|
isExplicitSyntax,
|
|
7029
7542
|
isIdSelector,
|
|
@@ -7047,14 +7560,19 @@ function accumulateIndented(statements, config) {
|
|
|
7047
7560
|
needsDisambiguation,
|
|
7048
7561
|
noChange,
|
|
7049
7562
|
normalized,
|
|
7563
|
+
parseCompound,
|
|
7564
|
+
parseDocument,
|
|
7050
7565
|
parseExplicit,
|
|
7051
7566
|
parseJSONL,
|
|
7052
7567
|
patternMatcher,
|
|
7053
7568
|
registryToAOTBackends,
|
|
7569
|
+
renderDocument,
|
|
7054
7570
|
renderExplicit,
|
|
7055
7571
|
renderExpr,
|
|
7056
7572
|
reorderRoles,
|
|
7057
7573
|
semanticNodeToJSON,
|
|
7574
|
+
semanticNodeToRuntimeAST,
|
|
7575
|
+
semanticValueToAST,
|
|
7058
7576
|
synthesizeFromSchemas,
|
|
7059
7577
|
toEnvelopeJSON,
|
|
7060
7578
|
toJSONL,
|