@lokascript/framework 2.3.0 → 2.4.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 +29 -516
- package/dist/api/index.js.map +1 -1
- package/dist/core/index.js +20 -128
- package/dist/core/index.js.map +1 -1
- package/dist/core/pattern-matching/index.js +19 -12
- package/dist/core/pattern-matching/index.js.map +1 -1
- package/dist/core/tokenization/index.js.map +1 -1
- package/dist/core/types.d.ts +7 -354
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +21 -129
- package/dist/core/types.js.map +1 -1
- package/dist/generation/diagnostics.d.ts +5 -115
- package/dist/generation/diagnostics.d.ts.map +1 -1
- package/dist/generation/index.js +20 -77
- package/dist/generation/index.js.map +1 -1
- package/dist/index.cjs +189 -1458
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +108 -1347
- package/dist/index.js.map +1 -1
- package/dist/interfaces/value-extractor.d.ts +20 -0
- package/dist/interfaces/value-extractor.d.ts.map +1 -1
- package/dist/ir/explicit-parser.d.ts +2 -83
- package/dist/ir/explicit-parser.d.ts.map +1 -1
- package/dist/ir/explicit-renderer.d.ts +2 -31
- package/dist/ir/explicit-renderer.d.ts.map +1 -1
- package/dist/ir/index.js +89 -1260
- package/dist/ir/index.js.map +1 -1
- package/dist/ir/protocol-json.d.ts +2 -70
- package/dist/ir/protocol-json.d.ts.map +1 -1
- package/dist/ir/references.d.ts +2 -16
- package/dist/ir/references.d.ts.map +1 -1
- package/dist/ir/types.d.ts +2 -148
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/parsing/index.js +19 -12
- package/dist/parsing/index.js.map +1 -1
- package/dist/schema/command-schema.d.ts +3 -92
- package/dist/schema/command-schema.d.ts.map +1 -1
- package/dist/schema/index.js +3 -20
- package/dist/schema/index.js.map +1 -1
- package/dist/testing/index.js +1133 -755
- package/dist/testing/index.js.map +1 -1
- package/package.json +6 -2
- package/src/core/types.ts +71 -600
- package/src/generation/diagnostics.ts +12 -233
- package/src/interfaces/value-extractor.ts +32 -0
- package/src/ir/explicit-parser.ts +12 -792
- package/src/ir/explicit-renderer.ts +2 -195
- package/src/ir/from-interchange.test.ts +91 -4
- package/src/ir/from-interchange.ts +59 -0
- package/src/ir/protocol-json.test.ts +16 -7
- package/src/ir/protocol-json.ts +9 -748
- package/src/ir/references.ts +2 -30
- package/src/ir/types.ts +18 -190
- package/src/schema/command-schema.ts +3 -134
package/dist/index.js
CHANGED
|
@@ -1,132 +1,23 @@
|
|
|
1
1
|
// src/core/types.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
|
|
22
|
-
const node = {
|
|
23
|
-
kind: "command",
|
|
24
|
-
action,
|
|
25
|
-
roles: rolesMap
|
|
26
|
-
};
|
|
27
|
-
if (metadata) {
|
|
28
|
-
return { ...node, metadata };
|
|
29
|
-
}
|
|
30
|
-
return node;
|
|
31
|
-
}
|
|
32
|
-
function createEventHandlerNode(action, roles, body, metadata, eventModifiers) {
|
|
33
|
-
const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
|
|
34
|
-
const base = {
|
|
35
|
-
kind: "event-handler",
|
|
36
|
-
action,
|
|
37
|
-
roles: rolesMap,
|
|
38
|
-
body
|
|
39
|
-
};
|
|
40
|
-
return {
|
|
41
|
-
...base,
|
|
42
|
-
...eventModifiers && { eventModifiers },
|
|
43
|
-
...metadata && { metadata }
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function createConditionalNode(action, roles, thenBranch, elseBranch, metadata) {
|
|
47
|
-
const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
|
|
48
|
-
const base = {
|
|
49
|
-
kind: "conditional",
|
|
50
|
-
action,
|
|
51
|
-
roles: rolesMap,
|
|
52
|
-
thenBranch
|
|
53
|
-
};
|
|
54
|
-
return {
|
|
55
|
-
...base,
|
|
56
|
-
...elseBranch && { elseBranch },
|
|
57
|
-
...metadata && { metadata }
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function createCompoundNode(statements, chainType = "sequential", metadata) {
|
|
61
|
-
const base = {
|
|
62
|
-
kind: "compound",
|
|
63
|
-
action: "compound",
|
|
64
|
-
roles: /* @__PURE__ */ new Map(),
|
|
65
|
-
statements,
|
|
66
|
-
chainType
|
|
67
|
-
};
|
|
68
|
-
return metadata ? { ...base, metadata } : base;
|
|
69
|
-
}
|
|
70
|
-
function extractValue(value) {
|
|
71
|
-
if (value.type === "flag") return value.name;
|
|
72
|
-
if ("raw" in value && value.raw !== void 0) return String(value.raw);
|
|
73
|
-
if ("value" in value && value.value !== void 0) return String(value.value);
|
|
74
|
-
if (value.type === "property-path") return `${extractValue(value.object)}.${value.property}`;
|
|
75
|
-
return "";
|
|
76
|
-
}
|
|
77
|
-
function extractRoleValue(node, role) {
|
|
78
|
-
const value = node.roles.get(role);
|
|
79
|
-
if (!value) return "";
|
|
80
|
-
return extractValue(value);
|
|
81
|
-
}
|
|
82
|
-
function createLoopNode(action, roles, loopVariant, body, loopVariable, indexVariable, metadata) {
|
|
83
|
-
const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
|
|
84
|
-
const base = {
|
|
85
|
-
kind: "loop",
|
|
86
|
-
action,
|
|
87
|
-
roles: rolesMap,
|
|
88
|
-
loopVariant,
|
|
89
|
-
body
|
|
90
|
-
};
|
|
91
|
-
return {
|
|
92
|
-
...base,
|
|
93
|
-
...loopVariable && { loopVariable },
|
|
94
|
-
...indexVariable && { indexVariable },
|
|
95
|
-
...metadata && { metadata }
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
function createTryNode(body, catchBranch, finallyBranch, metadata) {
|
|
99
|
-
return {
|
|
100
|
-
kind: "command",
|
|
101
|
-
action: "try",
|
|
102
|
-
roles: /* @__PURE__ */ new Map(),
|
|
103
|
-
body,
|
|
104
|
-
...catchBranch && catchBranch.length > 0 ? { catchBranch } : {},
|
|
105
|
-
...finallyBranch && finallyBranch.length > 0 ? { finallyBranch } : {},
|
|
106
|
-
...metadata ? { metadata } : {}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
function createAsyncNode(variant, asyncBody, metadata) {
|
|
110
|
-
return {
|
|
111
|
-
kind: "command",
|
|
112
|
-
action: variant,
|
|
113
|
-
roles: /* @__PURE__ */ new Map(),
|
|
114
|
-
asyncVariant: variant,
|
|
115
|
-
asyncBody,
|
|
116
|
-
...metadata ? { metadata } : {}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function createMatchNode(roles, arms, defaultArm, metadata) {
|
|
120
|
-
const rolesMap = roles instanceof Map ? roles : new Map(Object.entries(roles));
|
|
121
|
-
return {
|
|
122
|
-
kind: "command",
|
|
123
|
-
action: "match",
|
|
124
|
-
roles: rolesMap,
|
|
125
|
-
arms,
|
|
126
|
-
...defaultArm && defaultArm.length > 0 ? { defaultArm } : {},
|
|
127
|
-
...metadata ? { metadata } : {}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
createLiteral,
|
|
4
|
+
createSelector,
|
|
5
|
+
createReference,
|
|
6
|
+
createPropertyPath,
|
|
7
|
+
createExpression,
|
|
8
|
+
createFlag,
|
|
9
|
+
createCommandNode,
|
|
10
|
+
createEventHandlerNode,
|
|
11
|
+
createConditionalNode,
|
|
12
|
+
createCompoundNode,
|
|
13
|
+
createLoopNode,
|
|
14
|
+
createTryNode,
|
|
15
|
+
createAsyncNode,
|
|
16
|
+
createMatchNode,
|
|
17
|
+
extractValue,
|
|
18
|
+
extractRoleValue,
|
|
19
|
+
getRoleValue
|
|
20
|
+
} from "@lokascript/intent";
|
|
130
21
|
|
|
131
22
|
// src/core/logger.ts
|
|
132
23
|
var DebugLogger = class {
|
|
@@ -1974,6 +1865,22 @@ var UnicodeIdentifierExtractor = class {
|
|
|
1974
1865
|
return length > 0 ? { value: input.substring(position, position + length), length } : null;
|
|
1975
1866
|
}
|
|
1976
1867
|
};
|
|
1868
|
+
var LatinExtendedIdentifierExtractor = class {
|
|
1869
|
+
constructor() {
|
|
1870
|
+
this.name = "latin-extended-identifier";
|
|
1871
|
+
}
|
|
1872
|
+
canExtract(input, position) {
|
|
1873
|
+
return /\p{L}/u.test(input[position]);
|
|
1874
|
+
}
|
|
1875
|
+
extract(input, position) {
|
|
1876
|
+
let end = position;
|
|
1877
|
+
while (end < input.length && /[\p{L}\p{N}_-]/u.test(input[end])) {
|
|
1878
|
+
end++;
|
|
1879
|
+
}
|
|
1880
|
+
if (end === position) return null;
|
|
1881
|
+
return { value: input.slice(position, end), length: end - position };
|
|
1882
|
+
}
|
|
1883
|
+
};
|
|
1977
1884
|
var WhitespaceExtractor = class {
|
|
1978
1885
|
constructor() {
|
|
1979
1886
|
this.name = "whitespace";
|
|
@@ -2010,621 +1917,21 @@ function createTokenizerContext(tokenizer) {
|
|
|
2010
1917
|
}
|
|
2011
1918
|
|
|
2012
1919
|
// src/ir/references.ts
|
|
2013
|
-
|
|
2014
|
-
"me",
|
|
2015
|
-
"you",
|
|
2016
|
-
"it",
|
|
2017
|
-
"result",
|
|
2018
|
-
"event",
|
|
2019
|
-
"target",
|
|
2020
|
-
"body"
|
|
2021
|
-
]);
|
|
2022
|
-
function isValidReference2(value, referenceSet = DEFAULT_REFERENCES) {
|
|
2023
|
-
return referenceSet.has(value);
|
|
2024
|
-
}
|
|
1920
|
+
import { DEFAULT_REFERENCES, isValidReference as isValidReference2 } from "@lokascript/intent";
|
|
2025
1921
|
|
|
2026
1922
|
// src/ir/explicit-parser.ts
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
"finally"
|
|
2037
|
-
// v1.2: try/catch/finally
|
|
2038
|
-
]);
|
|
2039
|
-
function isNestedCommand(value) {
|
|
2040
|
-
const inner = value.slice(1, -1);
|
|
2041
|
-
let depth = 0;
|
|
2042
|
-
for (const ch of inner) {
|
|
2043
|
-
if (ch === "[") depth++;
|
|
2044
|
-
else if (ch === "]") depth--;
|
|
2045
|
-
else if (depth === 0 && (ch === " " || ch === ":")) return true;
|
|
2046
|
-
}
|
|
2047
|
-
return false;
|
|
2048
|
-
}
|
|
2049
|
-
function parseExplicit(input, options = {}) {
|
|
2050
|
-
const trimmed = input.trim();
|
|
2051
|
-
const collect = options.collectDiagnostics === true;
|
|
2052
|
-
const diagnostics = [];
|
|
2053
|
-
if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
|
|
2054
|
-
throw new Error("Explicit syntax must be wrapped in brackets: [command role:value ...]");
|
|
2055
|
-
}
|
|
2056
|
-
const content = trimmed.slice(1, -1).trim();
|
|
2057
|
-
if (!content) {
|
|
2058
|
-
throw new Error("Empty explicit statement");
|
|
2059
|
-
}
|
|
2060
|
-
const tokens = tokenizeExplicit(content);
|
|
2061
|
-
if (tokens.length === 0) {
|
|
2062
|
-
throw new Error("No command specified in explicit statement");
|
|
2063
|
-
}
|
|
2064
|
-
const command = tokens[0].toLowerCase();
|
|
2065
|
-
const roles = /* @__PURE__ */ new Map();
|
|
2066
|
-
const refSet = options.referenceSet ?? DEFAULT_REFERENCES;
|
|
2067
|
-
const schema = options.schemaLookup?.getSchema(command);
|
|
2068
|
-
const validRoleNames = schema ? new Set(schema.roles.map((r) => r.role)) : null;
|
|
2069
|
-
for (let i = 1; i < tokens.length; i++) {
|
|
2070
|
-
const token = tokens[i];
|
|
2071
|
-
if (token.startsWith("+") || token.startsWith("~")) {
|
|
2072
|
-
const enabled = token.startsWith("+");
|
|
2073
|
-
const flagName = token.slice(1);
|
|
2074
|
-
if (!flagName) {
|
|
2075
|
-
if (collect) {
|
|
2076
|
-
diagnostics.push({
|
|
2077
|
-
severity: "error",
|
|
2078
|
-
code: "EMPTY_FLAG",
|
|
2079
|
-
message: `Empty flag name: "${token}"`,
|
|
2080
|
-
source: "schema"
|
|
2081
|
-
});
|
|
2082
|
-
continue;
|
|
2083
|
-
}
|
|
2084
|
-
throw new Error(`Empty flag name: "${token}"`);
|
|
2085
|
-
}
|
|
2086
|
-
if (validRoleNames && !validRoleNames.has(flagName)) {
|
|
2087
|
-
const roleList = [...validRoleNames].join(", ");
|
|
2088
|
-
if (collect) {
|
|
2089
|
-
diagnostics.push({
|
|
2090
|
-
severity: "error",
|
|
2091
|
-
code: "UNKNOWN_FLAG",
|
|
2092
|
-
message: `Unknown flag "${flagName}" for command "${command}"`,
|
|
2093
|
-
source: "schema",
|
|
2094
|
-
suggestions: [...validRoleNames].map((r) => `+${r}`)
|
|
2095
|
-
});
|
|
2096
|
-
roles.set(flagName, createFlag(flagName, enabled));
|
|
2097
|
-
continue;
|
|
2098
|
-
}
|
|
2099
|
-
throw new Error(
|
|
2100
|
-
`Unknown flag "${flagName}" for command "${command}". Valid roles: ${roleList}`
|
|
2101
|
-
);
|
|
2102
|
-
}
|
|
2103
|
-
roles.set(flagName, createFlag(flagName, enabled));
|
|
2104
|
-
continue;
|
|
2105
|
-
}
|
|
2106
|
-
const colonIndex = token.indexOf(":");
|
|
2107
|
-
if (colonIndex === -1) {
|
|
2108
|
-
if (collect) {
|
|
2109
|
-
diagnostics.push({
|
|
2110
|
-
severity: "error",
|
|
2111
|
-
code: "INVALID_ROLE_FORMAT",
|
|
2112
|
-
message: `Invalid role format: "${token}". Expected role:value or +flag`,
|
|
2113
|
-
source: "schema"
|
|
2114
|
-
});
|
|
2115
|
-
continue;
|
|
2116
|
-
}
|
|
2117
|
-
throw new Error(`Invalid role format: "${token}". Expected role:value or +flag`);
|
|
2118
|
-
}
|
|
2119
|
-
const roleName = token.slice(0, colonIndex);
|
|
2120
|
-
if (validRoleNames && !STRUCTURAL_ROLES.has(roleName) && !validRoleNames.has(roleName)) {
|
|
2121
|
-
const roleList = [...validRoleNames].join(", ");
|
|
2122
|
-
if (collect) {
|
|
2123
|
-
diagnostics.push({
|
|
2124
|
-
severity: "error",
|
|
2125
|
-
code: "UNKNOWN_ROLE",
|
|
2126
|
-
message: `Unknown role "${roleName}" for command "${command}"`,
|
|
2127
|
-
source: "schema",
|
|
2128
|
-
suggestions: [...validRoleNames]
|
|
2129
|
-
});
|
|
2130
|
-
} else {
|
|
2131
|
-
throw new Error(
|
|
2132
|
-
`Unknown role "${roleName}" for command "${command}". Valid roles: ${roleList}`
|
|
2133
|
-
);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
const role = roleName;
|
|
2137
|
-
const valueStr = token.slice(colonIndex + 1);
|
|
2138
|
-
if (STRUCTURAL_ROLES.has(roleName) && valueStr.startsWith("[") && isNestedCommand(valueStr)) {
|
|
2139
|
-
const nestedEnd = findMatchingBracket(token, colonIndex + 1);
|
|
2140
|
-
const nestedSyntax = token.slice(colonIndex + 1, nestedEnd + 1);
|
|
2141
|
-
roles.set(role, { type: "expression", raw: nestedSyntax });
|
|
2142
|
-
continue;
|
|
2143
|
-
}
|
|
2144
|
-
const value = parseExplicitValue(valueStr, refSet);
|
|
2145
|
-
roles.set(role, value);
|
|
2146
|
-
}
|
|
2147
|
-
if (schema && command !== "on") {
|
|
2148
|
-
for (const roleSpec of schema.roles) {
|
|
2149
|
-
if (roleSpec.required && !roles.has(roleSpec.role) && !roleSpec.default) {
|
|
2150
|
-
if (collect) {
|
|
2151
|
-
diagnostics.push({
|
|
2152
|
-
severity: "error",
|
|
2153
|
-
code: "MISSING_REQUIRED_ROLE",
|
|
2154
|
-
message: `Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`,
|
|
2155
|
-
source: "schema"
|
|
2156
|
-
});
|
|
2157
|
-
} else {
|
|
2158
|
-
throw new Error(
|
|
2159
|
-
`Missing required role "${roleSpec.role}" for command "${command}": ${roleSpec.description}`
|
|
2160
|
-
);
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
|
-
const attachDiagnostics = (node) => {
|
|
2166
|
-
if (diagnostics.length === 0) return node;
|
|
2167
|
-
return { ...node, diagnostics };
|
|
2168
|
-
};
|
|
2169
|
-
switch (command) {
|
|
2170
|
-
case "on": {
|
|
2171
|
-
const eventValue = roles.get("event");
|
|
2172
|
-
if (!eventValue) {
|
|
2173
|
-
if (collect) {
|
|
2174
|
-
diagnostics.push({
|
|
2175
|
-
severity: "error",
|
|
2176
|
-
code: "MISSING_EVENT_ROLE",
|
|
2177
|
-
message: "Event handler requires event role: [on event:click ...]",
|
|
2178
|
-
source: "schema"
|
|
2179
|
-
});
|
|
2180
|
-
return attachDiagnostics(
|
|
2181
|
-
createEventHandlerNode("on", roles, [], {
|
|
2182
|
-
sourceLanguage: "explicit"
|
|
2183
|
-
})
|
|
2184
|
-
);
|
|
2185
|
-
}
|
|
2186
|
-
throw new Error("Event handler requires event role: [on event:click ...]");
|
|
2187
|
-
}
|
|
2188
|
-
const body = extractStructuralBody(roles, "body", options);
|
|
2189
|
-
roles.delete("body");
|
|
2190
|
-
return attachDiagnostics(
|
|
2191
|
-
createEventHandlerNode("on", roles, body, {
|
|
2192
|
-
sourceLanguage: "explicit"
|
|
2193
|
-
})
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2196
|
-
case "if": {
|
|
2197
|
-
const thenBranch = extractStructuralBody(roles, "then", options);
|
|
2198
|
-
const elseBranch = extractStructuralBody(roles, "else", options);
|
|
2199
|
-
roles.delete("then");
|
|
2200
|
-
roles.delete("else");
|
|
2201
|
-
return attachDiagnostics(
|
|
2202
|
-
createConditionalNode(
|
|
2203
|
-
command,
|
|
2204
|
-
roles,
|
|
2205
|
-
thenBranch,
|
|
2206
|
-
elseBranch.length > 0 ? elseBranch : void 0,
|
|
2207
|
-
{
|
|
2208
|
-
sourceLanguage: "explicit"
|
|
2209
|
-
}
|
|
2210
|
-
)
|
|
2211
|
-
);
|
|
2212
|
-
}
|
|
2213
|
-
case "repeat": {
|
|
2214
|
-
const loopBody = extractStructuralBody(roles, "loop-body", options);
|
|
2215
|
-
const loopVariantValue = roles.get("loop-variant");
|
|
2216
|
-
const variableValue = roles.get("variable");
|
|
2217
|
-
const indexVariableValue = roles.get("index-variable");
|
|
2218
|
-
roles.delete("loop-body");
|
|
2219
|
-
roles.delete("loop-variant");
|
|
2220
|
-
roles.delete("variable");
|
|
2221
|
-
roles.delete("index-variable");
|
|
2222
|
-
let variant;
|
|
2223
|
-
if (loopVariantValue && loopVariantValue.type === "literal" && typeof loopVariantValue.value === "string") {
|
|
2224
|
-
variant = loopVariantValue.value;
|
|
2225
|
-
} else if (roles.has("quantity")) {
|
|
2226
|
-
variant = "times";
|
|
2227
|
-
} else if (roles.has("source")) {
|
|
2228
|
-
variant = "for";
|
|
2229
|
-
} else if (roles.has("condition")) {
|
|
2230
|
-
variant = "while";
|
|
2231
|
-
} else {
|
|
2232
|
-
variant = "forever";
|
|
2233
|
-
}
|
|
2234
|
-
const loopVariable = variableValue?.type === "literal" && typeof variableValue.value === "string" ? variableValue.value : variableValue?.type === "expression" ? variableValue.raw : void 0;
|
|
2235
|
-
const indexVariable = indexVariableValue?.type === "literal" && typeof indexVariableValue.value === "string" ? indexVariableValue.value : void 0;
|
|
2236
|
-
return attachDiagnostics(
|
|
2237
|
-
createLoopNode(command, roles, variant, loopBody, loopVariable, indexVariable, {
|
|
2238
|
-
sourceLanguage: "explicit"
|
|
2239
|
-
})
|
|
2240
|
-
);
|
|
2241
|
-
}
|
|
2242
|
-
default:
|
|
2243
|
-
return attachDiagnostics(
|
|
2244
|
-
createCommandNode(command, roles, {
|
|
2245
|
-
sourceLanguage: "explicit"
|
|
2246
|
-
})
|
|
2247
|
-
);
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
function isExplicitSyntax(input) {
|
|
2251
|
-
const trimmed = input.trim();
|
|
2252
|
-
return trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
2253
|
-
}
|
|
2254
|
-
var CHAIN_KEYWORDS = /* @__PURE__ */ new Set(["then", "and", "async", "sequential"]);
|
|
2255
|
-
function splitCompoundSegments(input) {
|
|
2256
|
-
const segments = [];
|
|
2257
|
-
let chainType = null;
|
|
2258
|
-
let current = "";
|
|
2259
|
-
let bracketDepth = 0;
|
|
2260
|
-
let inString = false;
|
|
2261
|
-
let stringChar = "";
|
|
2262
|
-
for (let i = 0; i < input.length; i++) {
|
|
2263
|
-
const char = input[i];
|
|
2264
|
-
if (inString) {
|
|
2265
|
-
current += char;
|
|
2266
|
-
if (char === stringChar && input[i - 1] !== "\\") {
|
|
2267
|
-
inString = false;
|
|
2268
|
-
}
|
|
2269
|
-
continue;
|
|
2270
|
-
}
|
|
2271
|
-
if (char === '"' || char === "'") {
|
|
2272
|
-
inString = true;
|
|
2273
|
-
stringChar = char;
|
|
2274
|
-
current += char;
|
|
2275
|
-
continue;
|
|
2276
|
-
}
|
|
2277
|
-
if (char === "[") {
|
|
2278
|
-
bracketDepth++;
|
|
2279
|
-
current += char;
|
|
2280
|
-
continue;
|
|
2281
|
-
}
|
|
2282
|
-
if (char === "]") {
|
|
2283
|
-
bracketDepth--;
|
|
2284
|
-
current += char;
|
|
2285
|
-
if (bracketDepth === 0) {
|
|
2286
|
-
const rest = input.slice(i + 1);
|
|
2287
|
-
const pipeMatch = rest.match(/^\s*\|>\s*/);
|
|
2288
|
-
if (pipeMatch) {
|
|
2289
|
-
segments.push(current.trim());
|
|
2290
|
-
current = "";
|
|
2291
|
-
chainType ?? (chainType = "pipe");
|
|
2292
|
-
i += pipeMatch[0].length;
|
|
2293
|
-
continue;
|
|
2294
|
-
}
|
|
2295
|
-
const keywordMatch = rest.match(/^\s+(then|and|async|sequential)\s+/);
|
|
2296
|
-
if (keywordMatch && CHAIN_KEYWORDS.has(keywordMatch[1])) {
|
|
2297
|
-
segments.push(current.trim());
|
|
2298
|
-
current = "";
|
|
2299
|
-
chainType ?? (chainType = keywordMatch[1]);
|
|
2300
|
-
i += keywordMatch[0].length;
|
|
2301
|
-
continue;
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
continue;
|
|
2305
|
-
}
|
|
2306
|
-
current += char;
|
|
2307
|
-
}
|
|
2308
|
-
if (current.trim()) {
|
|
2309
|
-
segments.push(current.trim());
|
|
2310
|
-
}
|
|
2311
|
-
return { segments, chainType };
|
|
2312
|
-
}
|
|
2313
|
-
function parseCompound(input, options) {
|
|
2314
|
-
const trimmed = input.trim();
|
|
2315
|
-
const { annotations, remainder } = extractAnnotations(trimmed);
|
|
2316
|
-
const { segments, chainType } = splitCompoundSegments(remainder);
|
|
2317
|
-
let node;
|
|
2318
|
-
if (segments.length <= 1) {
|
|
2319
|
-
node = parseExplicit(segments[0] || remainder, options);
|
|
2320
|
-
} else {
|
|
2321
|
-
const statements = segments.map((seg) => parseExplicit(seg, options));
|
|
2322
|
-
node = createCompoundNode(statements, chainType ?? "sequential");
|
|
2323
|
-
}
|
|
2324
|
-
if (annotations.length > 0) {
|
|
2325
|
-
return { ...node, annotations };
|
|
2326
|
-
}
|
|
2327
|
-
return node;
|
|
2328
|
-
}
|
|
2329
|
-
function extractAnnotations(input) {
|
|
2330
|
-
const annotations = [];
|
|
2331
|
-
let pos = 0;
|
|
2332
|
-
while (pos < input.length) {
|
|
2333
|
-
while (pos < input.length && (input[pos] === " " || input[pos] === " ")) {
|
|
2334
|
-
pos++;
|
|
2335
|
-
}
|
|
2336
|
-
if (pos >= input.length || input[pos] !== "@") {
|
|
2337
|
-
break;
|
|
2338
|
-
}
|
|
2339
|
-
pos++;
|
|
2340
|
-
const nameStart = pos;
|
|
2341
|
-
while (pos < input.length && /[A-Za-z0-9\-_]/.test(input[pos])) {
|
|
2342
|
-
pos++;
|
|
2343
|
-
}
|
|
2344
|
-
const name = input.slice(nameStart, pos);
|
|
2345
|
-
if (!name) break;
|
|
2346
|
-
let value;
|
|
2347
|
-
if (pos < input.length && input[pos] === "(") {
|
|
2348
|
-
pos++;
|
|
2349
|
-
const valueStart = pos;
|
|
2350
|
-
if (pos < input.length && (input[pos] === '"' || input[pos] === "'")) {
|
|
2351
|
-
const quote = input[pos];
|
|
2352
|
-
pos++;
|
|
2353
|
-
while (pos < input.length && input[pos] !== quote) {
|
|
2354
|
-
if (input[pos] === "\\") pos++;
|
|
2355
|
-
pos++;
|
|
2356
|
-
}
|
|
2357
|
-
pos++;
|
|
2358
|
-
value = input.slice(valueStart + 1, pos - 1);
|
|
2359
|
-
} else {
|
|
2360
|
-
while (pos < input.length && input[pos] !== ")") {
|
|
2361
|
-
pos++;
|
|
2362
|
-
}
|
|
2363
|
-
value = input.slice(valueStart, pos);
|
|
2364
|
-
}
|
|
2365
|
-
if (pos < input.length && input[pos] === ")") {
|
|
2366
|
-
pos++;
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
annotations.push(value !== void 0 ? { name, value } : { name });
|
|
2370
|
-
}
|
|
2371
|
-
return { annotations, remainder: input.slice(pos).trim() };
|
|
2372
|
-
}
|
|
2373
|
-
var VERSION_HEADER_RE = /^#!lse\s+(\d+\.\d+(?:\.\d+)?)\s*$/;
|
|
2374
|
-
function parseDocument(input, options) {
|
|
2375
|
-
const lines = input.split("\n");
|
|
2376
|
-
let lseVersion = "1.0";
|
|
2377
|
-
const nodes = [];
|
|
2378
|
-
let startLine = 0;
|
|
2379
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2380
|
-
const trimmed = lines[i].trim();
|
|
2381
|
-
if (!trimmed) continue;
|
|
2382
|
-
const versionMatch = trimmed.match(VERSION_HEADER_RE);
|
|
2383
|
-
if (versionMatch) {
|
|
2384
|
-
lseVersion = versionMatch[1];
|
|
2385
|
-
startLine = i + 1;
|
|
2386
|
-
}
|
|
2387
|
-
break;
|
|
2388
|
-
}
|
|
2389
|
-
for (let i = startLine; i < lines.length; i++) {
|
|
2390
|
-
const trimmed = lines[i].trim();
|
|
2391
|
-
if (!trimmed) continue;
|
|
2392
|
-
if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
|
|
2393
|
-
continue;
|
|
2394
|
-
}
|
|
2395
|
-
nodes.push(parseCompound(trimmed, options));
|
|
2396
|
-
}
|
|
2397
|
-
return { lseVersion, nodes };
|
|
2398
|
-
}
|
|
2399
|
-
function isCompoundSyntax(input) {
|
|
2400
|
-
const { segments } = splitCompoundSegments(input.trim());
|
|
2401
|
-
return segments.length > 1;
|
|
2402
|
-
}
|
|
2403
|
-
function isDocumentSyntax(input) {
|
|
2404
|
-
const trimmed = input.trim();
|
|
2405
|
-
if (trimmed.includes("\n")) return true;
|
|
2406
|
-
if (VERSION_HEADER_RE.test(trimmed)) return true;
|
|
2407
|
-
if (trimmed.startsWith("//") || trimmed.startsWith("#") && !trimmed.startsWith("#!")) {
|
|
2408
|
-
return true;
|
|
2409
|
-
}
|
|
2410
|
-
return false;
|
|
2411
|
-
}
|
|
2412
|
-
function extractStructuralBody(roles, roleName, options) {
|
|
2413
|
-
const value = roles.get(roleName);
|
|
2414
|
-
if (!value) return [];
|
|
2415
|
-
if (value.type === "expression") {
|
|
2416
|
-
return [parseExplicit(value.raw, options)];
|
|
2417
|
-
}
|
|
2418
|
-
return [];
|
|
2419
|
-
}
|
|
2420
|
-
function inferSelectorKind(value) {
|
|
2421
|
-
if (!value) return void 0;
|
|
2422
|
-
if (value.startsWith("#")) return "id";
|
|
2423
|
-
if (value.startsWith(".")) return "class";
|
|
2424
|
-
if (value.startsWith("[")) return "attribute";
|
|
2425
|
-
if (value.startsWith("<") || value.startsWith("*")) return "element";
|
|
2426
|
-
if (/[>+~ ]/.test(value) && value.length > 1) return "complex";
|
|
2427
|
-
return void 0;
|
|
2428
|
-
}
|
|
2429
|
-
function tokenizeExplicit(content) {
|
|
2430
|
-
const tokens = [];
|
|
2431
|
-
let current = "";
|
|
2432
|
-
let inString = false;
|
|
2433
|
-
let stringChar = "";
|
|
2434
|
-
let bracketDepth = 0;
|
|
2435
|
-
for (let i = 0; i < content.length; i++) {
|
|
2436
|
-
const char = content[i];
|
|
2437
|
-
if (inString) {
|
|
2438
|
-
current += char;
|
|
2439
|
-
if (char === stringChar && content[i - 1] !== "\\") {
|
|
2440
|
-
inString = false;
|
|
2441
|
-
}
|
|
2442
|
-
continue;
|
|
2443
|
-
}
|
|
2444
|
-
if (char === '"' || char === "'") {
|
|
2445
|
-
inString = true;
|
|
2446
|
-
stringChar = char;
|
|
2447
|
-
current += char;
|
|
2448
|
-
continue;
|
|
2449
|
-
}
|
|
2450
|
-
if (char === "[") {
|
|
2451
|
-
bracketDepth++;
|
|
2452
|
-
current += char;
|
|
2453
|
-
continue;
|
|
2454
|
-
}
|
|
2455
|
-
if (char === "]") {
|
|
2456
|
-
bracketDepth--;
|
|
2457
|
-
current += char;
|
|
2458
|
-
continue;
|
|
2459
|
-
}
|
|
2460
|
-
if (char === " " && bracketDepth === 0) {
|
|
2461
|
-
if (current) {
|
|
2462
|
-
tokens.push(current);
|
|
2463
|
-
current = "";
|
|
2464
|
-
}
|
|
2465
|
-
continue;
|
|
2466
|
-
}
|
|
2467
|
-
current += char;
|
|
2468
|
-
}
|
|
2469
|
-
if (current) {
|
|
2470
|
-
tokens.push(current);
|
|
2471
|
-
}
|
|
2472
|
-
return tokens;
|
|
2473
|
-
}
|
|
2474
|
-
function parseExplicitValue(valueStr, referenceSet) {
|
|
2475
|
-
if (valueStr.startsWith("#") || valueStr.startsWith(".") || valueStr.startsWith("[") || valueStr.startsWith("@") || valueStr.startsWith("*")) {
|
|
2476
|
-
return createSelector(valueStr, inferSelectorKind(valueStr));
|
|
2477
|
-
}
|
|
2478
|
-
if (valueStr.startsWith('"') || valueStr.startsWith("'")) {
|
|
2479
|
-
const inner = valueStr.slice(1, -1);
|
|
2480
|
-
return createLiteral(inner, "string");
|
|
2481
|
-
}
|
|
2482
|
-
if (valueStr === "true") return createLiteral(true, "boolean");
|
|
2483
|
-
if (valueStr === "false") return createLiteral(false, "boolean");
|
|
2484
|
-
const lowerRef = valueStr.toLowerCase();
|
|
2485
|
-
if (isValidReference2(lowerRef, referenceSet)) {
|
|
2486
|
-
return createReference(lowerRef);
|
|
2487
|
-
}
|
|
2488
|
-
const numMatch = valueStr.match(/^(-?\d+(?:\.\d+)?)(ms|s|m|h)?$/);
|
|
2489
|
-
if (numMatch) {
|
|
2490
|
-
const num = parseFloat(numMatch[1]);
|
|
2491
|
-
const suffix = numMatch[2];
|
|
2492
|
-
if (suffix) {
|
|
2493
|
-
return createLiteral(valueStr, "duration");
|
|
2494
|
-
}
|
|
2495
|
-
return createLiteral(num, "number");
|
|
2496
|
-
}
|
|
2497
|
-
return createLiteral(valueStr);
|
|
2498
|
-
}
|
|
2499
|
-
function findMatchingBracket(str, start) {
|
|
2500
|
-
let depth = 0;
|
|
2501
|
-
for (let i = start; i < str.length; i++) {
|
|
2502
|
-
if (str[i] === "[") depth++;
|
|
2503
|
-
else if (str[i] === "]") {
|
|
2504
|
-
depth--;
|
|
2505
|
-
if (depth === 0) return i;
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
return str.length - 1;
|
|
2509
|
-
}
|
|
1923
|
+
import {
|
|
1924
|
+
STRUCTURAL_ROLES,
|
|
1925
|
+
parseExplicit,
|
|
1926
|
+
isExplicitSyntax,
|
|
1927
|
+
parseCompound,
|
|
1928
|
+
parseDocument,
|
|
1929
|
+
isCompoundSyntax,
|
|
1930
|
+
isDocumentSyntax
|
|
1931
|
+
} from "@lokascript/intent";
|
|
2510
1932
|
|
|
2511
1933
|
// src/ir/explicit-renderer.ts
|
|
2512
|
-
|
|
2513
|
-
let result;
|
|
2514
|
-
if (node.kind === "compound") {
|
|
2515
|
-
const compoundNode = node;
|
|
2516
|
-
const renderedStatements = compoundNode.statements.map((stmt) => renderExplicit(stmt));
|
|
2517
|
-
result = renderedStatements.join(` ${compoundNode.chainType} `);
|
|
2518
|
-
} else {
|
|
2519
|
-
result = renderBracketCommand(node);
|
|
2520
|
-
}
|
|
2521
|
-
if (node.annotations && node.annotations.length > 0) {
|
|
2522
|
-
const annParts = node.annotations.map(
|
|
2523
|
-
(ann) => ann.value !== void 0 ? `@${ann.name}(${ann.value})` : `@${ann.name}`
|
|
2524
|
-
);
|
|
2525
|
-
return annParts.join(" ") + " " + result;
|
|
2526
|
-
}
|
|
2527
|
-
return result;
|
|
2528
|
-
}
|
|
2529
|
-
function renderDocument(envelope) {
|
|
2530
|
-
const lines = [];
|
|
2531
|
-
if (envelope.lseVersion && envelope.lseVersion !== "1.0") {
|
|
2532
|
-
lines.push(`#!lse ${envelope.lseVersion}`);
|
|
2533
|
-
}
|
|
2534
|
-
for (const node of envelope.nodes) {
|
|
2535
|
-
lines.push(renderExplicit(node));
|
|
2536
|
-
}
|
|
2537
|
-
return lines.join("\n");
|
|
2538
|
-
}
|
|
2539
|
-
function renderBracketCommand(node) {
|
|
2540
|
-
const parts = [node.action];
|
|
2541
|
-
for (const [role, value] of node.roles) {
|
|
2542
|
-
if (value.type === "flag") {
|
|
2543
|
-
parts.push(value.enabled ? `+${value.name}` : `~${value.name}`);
|
|
2544
|
-
} else {
|
|
2545
|
-
parts.push(`${role}:${valueToString(value)}`);
|
|
2546
|
-
}
|
|
2547
|
-
}
|
|
2548
|
-
if (node.kind === "event-handler") {
|
|
2549
|
-
const eventNode = node;
|
|
2550
|
-
if (eventNode.body && eventNode.body.length > 0) {
|
|
2551
|
-
const bodyParts = eventNode.body.map((n) => renderExplicit(n));
|
|
2552
|
-
parts.push(`body:${bodyParts.join(" ")}`);
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
if (node.kind === "conditional") {
|
|
2556
|
-
const condNode = node;
|
|
2557
|
-
if (condNode.thenBranch && condNode.thenBranch.length > 0) {
|
|
2558
|
-
const thenParts = condNode.thenBranch.map((n) => renderExplicit(n));
|
|
2559
|
-
parts.push(`then:${thenParts.join(" ")}`);
|
|
2560
|
-
}
|
|
2561
|
-
if (condNode.elseBranch && condNode.elseBranch.length > 0) {
|
|
2562
|
-
const elseParts = condNode.elseBranch.map((n) => renderExplicit(n));
|
|
2563
|
-
parts.push(`else:${elseParts.join(" ")}`);
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
if (node.kind === "loop") {
|
|
2567
|
-
const loopNode = node;
|
|
2568
|
-
if (loopNode.loopVariant) {
|
|
2569
|
-
parts.push(`loop-variant:${loopNode.loopVariant}`);
|
|
2570
|
-
}
|
|
2571
|
-
if (loopNode.loopVariable) {
|
|
2572
|
-
parts.push(`variable:${loopNode.loopVariable}`);
|
|
2573
|
-
}
|
|
2574
|
-
if (loopNode.indexVariable) {
|
|
2575
|
-
parts.push(`index-variable:${loopNode.indexVariable}`);
|
|
2576
|
-
}
|
|
2577
|
-
if (loopNode.body && loopNode.body.length > 0) {
|
|
2578
|
-
const bodyParts = loopNode.body.map((n) => renderExplicit(n));
|
|
2579
|
-
parts.push(`loop-body:${bodyParts.join(" ")}`);
|
|
2580
|
-
}
|
|
2581
|
-
}
|
|
2582
|
-
if (node.kind === "command") {
|
|
2583
|
-
const cmd = node;
|
|
2584
|
-
if (cmd.body && cmd.body.length > 0) {
|
|
2585
|
-
const bodyParts = cmd.body.map((n) => renderExplicit(n));
|
|
2586
|
-
parts.push(`body:${bodyParts.join(" ")}`);
|
|
2587
|
-
}
|
|
2588
|
-
if (cmd.catchBranch && cmd.catchBranch.length > 0) {
|
|
2589
|
-
const catchParts = cmd.catchBranch.map((n) => renderExplicit(n));
|
|
2590
|
-
parts.push(`catch:${catchParts.join(" ")}`);
|
|
2591
|
-
}
|
|
2592
|
-
if (cmd.finallyBranch && cmd.finallyBranch.length > 0) {
|
|
2593
|
-
const finallyParts = cmd.finallyBranch.map((n) => renderExplicit(n));
|
|
2594
|
-
parts.push(`finally:${finallyParts.join(" ")}`);
|
|
2595
|
-
}
|
|
2596
|
-
if (cmd.asyncVariant) {
|
|
2597
|
-
parts.push(`async-variant:${cmd.asyncVariant}`);
|
|
2598
|
-
}
|
|
2599
|
-
if (cmd.asyncBody && cmd.asyncBody.length > 0) {
|
|
2600
|
-
const asyncParts = cmd.asyncBody.map((n) => renderExplicit(n));
|
|
2601
|
-
parts.push(`async-body:${asyncParts.join(" ")}`);
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
return `[${parts.join(" ")}]`;
|
|
2605
|
-
}
|
|
2606
|
-
function valueToString(value) {
|
|
2607
|
-
switch (value.type) {
|
|
2608
|
-
case "literal":
|
|
2609
|
-
if (typeof value.value === "string") {
|
|
2610
|
-
if (value.dataType === "string" || /\s/.test(value.value)) {
|
|
2611
|
-
return `"${value.value}"`;
|
|
2612
|
-
}
|
|
2613
|
-
return value.value;
|
|
2614
|
-
}
|
|
2615
|
-
return String(value.value);
|
|
2616
|
-
case "selector":
|
|
2617
|
-
return value.value;
|
|
2618
|
-
case "reference":
|
|
2619
|
-
return value.value;
|
|
2620
|
-
case "property-path":
|
|
2621
|
-
return `${valueToString(value.object)}'s ${value.property}`;
|
|
2622
|
-
case "expression":
|
|
2623
|
-
return value.raw;
|
|
2624
|
-
case "flag":
|
|
2625
|
-
return value.name;
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
1934
|
+
import { renderExplicit, renderDocument } from "@lokascript/intent";
|
|
2628
1935
|
|
|
2629
1936
|
// src/ir/json-schema.ts
|
|
2630
1937
|
var VALID_VALUE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -2796,527 +2103,14 @@ function detectSelectorKind(selector) {
|
|
|
2796
2103
|
}
|
|
2797
2104
|
|
|
2798
2105
|
// src/ir/protocol-json.ts
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
result.body = cmd.body.map(toProtocolJSON);
|
|
2808
|
-
}
|
|
2809
|
-
if (cmd.catchBranch && cmd.catchBranch.length > 0) {
|
|
2810
|
-
result.catchBranch = cmd.catchBranch.map(toProtocolJSON);
|
|
2811
|
-
}
|
|
2812
|
-
if (cmd.finallyBranch && cmd.finallyBranch.length > 0) {
|
|
2813
|
-
result.finallyBranch = cmd.finallyBranch.map(toProtocolJSON);
|
|
2814
|
-
}
|
|
2815
|
-
if (cmd.asyncVariant) {
|
|
2816
|
-
result.asyncVariant = cmd.asyncVariant;
|
|
2817
|
-
}
|
|
2818
|
-
if (cmd.asyncBody && cmd.asyncBody.length > 0) {
|
|
2819
|
-
result.asyncBody = cmd.asyncBody.map(toProtocolJSON);
|
|
2820
|
-
}
|
|
2821
|
-
if (cmd.arms && cmd.arms.length > 0) {
|
|
2822
|
-
result.arms = cmd.arms.map((arm) => ({
|
|
2823
|
-
pattern: valueToProtocol(arm.pattern),
|
|
2824
|
-
body: arm.body.map(toProtocolJSON)
|
|
2825
|
-
}));
|
|
2826
|
-
}
|
|
2827
|
-
if (cmd.defaultArm && cmd.defaultArm.length > 0) {
|
|
2828
|
-
result.defaultArm = cmd.defaultArm.map(toProtocolJSON);
|
|
2829
|
-
}
|
|
2830
|
-
break;
|
|
2831
|
-
}
|
|
2832
|
-
case "event-handler": {
|
|
2833
|
-
const eh = node;
|
|
2834
|
-
result = {
|
|
2835
|
-
kind: "event-handler",
|
|
2836
|
-
action: node.action,
|
|
2837
|
-
roles,
|
|
2838
|
-
body: eh.body.map(toProtocolJSON)
|
|
2839
|
-
};
|
|
2840
|
-
break;
|
|
2841
|
-
}
|
|
2842
|
-
case "compound": {
|
|
2843
|
-
const c = node;
|
|
2844
|
-
result = {
|
|
2845
|
-
kind: "compound",
|
|
2846
|
-
action: "compound",
|
|
2847
|
-
statements: c.statements.map(toProtocolJSON),
|
|
2848
|
-
chainType: c.chainType
|
|
2849
|
-
};
|
|
2850
|
-
break;
|
|
2851
|
-
}
|
|
2852
|
-
case "conditional": {
|
|
2853
|
-
const cond = node;
|
|
2854
|
-
result = { kind: "command", action: node.action, roles };
|
|
2855
|
-
result.thenBranch = cond.thenBranch.map(toProtocolJSON);
|
|
2856
|
-
if (cond.elseBranch && cond.elseBranch.length > 0) {
|
|
2857
|
-
result.elseBranch = cond.elseBranch.map(toProtocolJSON);
|
|
2858
|
-
}
|
|
2859
|
-
break;
|
|
2860
|
-
}
|
|
2861
|
-
case "loop": {
|
|
2862
|
-
const loop = node;
|
|
2863
|
-
result = { kind: "command", action: node.action, roles };
|
|
2864
|
-
result.loopVariant = loop.loopVariant;
|
|
2865
|
-
result.loopBody = loop.body.map(toProtocolJSON);
|
|
2866
|
-
if (loop.loopVariable) result.loopVariable = loop.loopVariable;
|
|
2867
|
-
if (loop.indexVariable) result.indexVariable = loop.indexVariable;
|
|
2868
|
-
break;
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
if (node.annotations && node.annotations.length > 0) {
|
|
2872
|
-
result.annotations = node.annotations.map(
|
|
2873
|
-
(a) => a.value !== void 0 ? { name: a.name, value: a.value } : { name: a.name }
|
|
2874
|
-
);
|
|
2875
|
-
}
|
|
2876
|
-
if (node.diagnostics && node.diagnostics.length > 0) {
|
|
2877
|
-
result.diagnostics = node.diagnostics.map((d) => {
|
|
2878
|
-
const json = {
|
|
2879
|
-
level: d.severity,
|
|
2880
|
-
message: d.message
|
|
2881
|
-
};
|
|
2882
|
-
if (d.code) json.code = d.code;
|
|
2883
|
-
if (d.source) json.source = d.source;
|
|
2884
|
-
if (d.suggestions && d.suggestions.length > 0) json.suggestions = [...d.suggestions];
|
|
2885
|
-
return json;
|
|
2886
|
-
});
|
|
2887
|
-
}
|
|
2888
|
-
return result;
|
|
2889
|
-
}
|
|
2890
|
-
function rolesToProtocol(roles) {
|
|
2891
|
-
const result = {};
|
|
2892
|
-
for (const [role, value] of roles) {
|
|
2893
|
-
result[role] = valueToProtocol(value);
|
|
2894
|
-
}
|
|
2895
|
-
return result;
|
|
2896
|
-
}
|
|
2897
|
-
function valueToProtocol(value) {
|
|
2898
|
-
switch (value.type) {
|
|
2899
|
-
case "selector": {
|
|
2900
|
-
const PROTOCOL_SELECTOR_KINDS = /* @__PURE__ */ new Set([
|
|
2901
|
-
"id",
|
|
2902
|
-
"class",
|
|
2903
|
-
"attribute",
|
|
2904
|
-
"element",
|
|
2905
|
-
"complex"
|
|
2906
|
-
]);
|
|
2907
|
-
const sk = "selectorKind" in value ? value.selectorKind : void 0;
|
|
2908
|
-
const sv = { type: "selector", value: value.value };
|
|
2909
|
-
if (sk && PROTOCOL_SELECTOR_KINDS.has(sk)) {
|
|
2910
|
-
sv.selectorKind = sk;
|
|
2911
|
-
}
|
|
2912
|
-
return sv;
|
|
2913
|
-
}
|
|
2914
|
-
case "literal":
|
|
2915
|
-
return value.dataType ? { type: "literal", value: value.value, dataType: value.dataType } : { type: "literal", value: value.value };
|
|
2916
|
-
case "reference":
|
|
2917
|
-
return { type: "reference", value: value.value };
|
|
2918
|
-
case "expression":
|
|
2919
|
-
return { type: "expression", raw: value.raw };
|
|
2920
|
-
case "property-path":
|
|
2921
|
-
return { type: "expression", raw: extractValue(value) };
|
|
2922
|
-
case "flag":
|
|
2923
|
-
return { type: "flag", name: value.name, enabled: value.enabled };
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
function fromProtocolJSON(json) {
|
|
2927
|
-
const roles = new Map(
|
|
2928
|
-
Object.entries(json.roles ?? {}).map(([role, val]) => [role, valueFromProtocol(val)])
|
|
2929
|
-
);
|
|
2930
|
-
const annotations = json.annotations?.map(
|
|
2931
|
-
(a) => a.value !== void 0 ? { name: a.name, value: a.value } : { name: a.name }
|
|
2932
|
-
);
|
|
2933
|
-
const diagnostics = json.diagnostics?.map((d) => ({
|
|
2934
|
-
severity: d.level,
|
|
2935
|
-
message: d.message,
|
|
2936
|
-
...d.code ? { code: d.code } : {},
|
|
2937
|
-
...d.source ? { source: d.source } : {},
|
|
2938
|
-
...d.suggestions && d.suggestions.length > 0 ? { suggestions: d.suggestions } : {}
|
|
2939
|
-
}));
|
|
2940
|
-
if (json.trigger) {
|
|
2941
|
-
const eventName = json.trigger.event;
|
|
2942
|
-
roles.set("event", createLiteral(eventName, "string"));
|
|
2943
|
-
const bodyRoles = new Map(roles);
|
|
2944
|
-
bodyRoles.delete("event");
|
|
2945
|
-
const bodyNode = createCommandNode(json.action, bodyRoles);
|
|
2946
|
-
const node2 = createEventHandlerNode(
|
|
2947
|
-
"on",
|
|
2948
|
-
roles,
|
|
2949
|
-
[bodyNode],
|
|
2950
|
-
{ sourceLanguage: "json" },
|
|
2951
|
-
json.trigger.modifiers ?? {}
|
|
2952
|
-
);
|
|
2953
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2954
|
-
}
|
|
2955
|
-
const kind = json.kind ?? "command";
|
|
2956
|
-
if (kind === "event-handler") {
|
|
2957
|
-
const body = (json.body ?? []).map(fromProtocolJSON);
|
|
2958
|
-
const node2 = createEventHandlerNode(json.action, roles, body);
|
|
2959
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2960
|
-
}
|
|
2961
|
-
if (kind === "compound") {
|
|
2962
|
-
const statements = (json.statements ?? []).map(fromProtocolJSON);
|
|
2963
|
-
const node2 = createCompoundNode(
|
|
2964
|
-
statements,
|
|
2965
|
-
json.chainType ?? "sequential"
|
|
2966
|
-
);
|
|
2967
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2968
|
-
}
|
|
2969
|
-
if (json.thenBranch && json.thenBranch.length > 0) {
|
|
2970
|
-
const thenBranch = json.thenBranch.map(fromProtocolJSON);
|
|
2971
|
-
const elseBranch = json.elseBranch ? json.elseBranch.map(fromProtocolJSON) : void 0;
|
|
2972
|
-
const node2 = createConditionalNode(json.action, roles, thenBranch, elseBranch);
|
|
2973
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2974
|
-
}
|
|
2975
|
-
if (json.loopVariant) {
|
|
2976
|
-
const loopBody = (json.loopBody ?? []).map(fromProtocolJSON);
|
|
2977
|
-
const node2 = createLoopNode(
|
|
2978
|
-
json.action,
|
|
2979
|
-
roles,
|
|
2980
|
-
json.loopVariant,
|
|
2981
|
-
loopBody,
|
|
2982
|
-
json.loopVariable,
|
|
2983
|
-
json.indexVariable
|
|
2984
|
-
);
|
|
2985
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2986
|
-
}
|
|
2987
|
-
if (json.catchBranch || json.finallyBranch) {
|
|
2988
|
-
const body = (json.body ?? []).map(fromProtocolJSON);
|
|
2989
|
-
const catchBranch = json.catchBranch ? json.catchBranch.map(fromProtocolJSON) : void 0;
|
|
2990
|
-
const finallyBranch = json.finallyBranch ? json.finallyBranch.map(fromProtocolJSON) : void 0;
|
|
2991
|
-
const node2 = createTryNode(body, catchBranch, finallyBranch);
|
|
2992
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2993
|
-
}
|
|
2994
|
-
if (json.asyncVariant) {
|
|
2995
|
-
const asyncBody = (json.asyncBody ?? []).map(fromProtocolJSON);
|
|
2996
|
-
const node2 = createAsyncNode(json.asyncVariant, asyncBody);
|
|
2997
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
2998
|
-
}
|
|
2999
|
-
if (json.arms && json.arms.length > 0) {
|
|
3000
|
-
const arms = json.arms.map((arm) => ({
|
|
3001
|
-
pattern: valueFromProtocol(arm.pattern),
|
|
3002
|
-
body: arm.body.map(fromProtocolJSON)
|
|
3003
|
-
}));
|
|
3004
|
-
const defaultArm = json.defaultArm ? json.defaultArm.map(fromProtocolJSON) : void 0;
|
|
3005
|
-
const node2 = createMatchNode(roles, arms, defaultArm);
|
|
3006
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
3007
|
-
}
|
|
3008
|
-
if (json.body && json.body.length > 0 && kind === "command") {
|
|
3009
|
-
const body = json.body.map(fromProtocolJSON);
|
|
3010
|
-
const node2 = createTryNode(body);
|
|
3011
|
-
return applyV12Metadata(node2, annotations, diagnostics);
|
|
3012
|
-
}
|
|
3013
|
-
const node = createCommandNode(json.action, roles);
|
|
3014
|
-
return applyV12Metadata(node, annotations, diagnostics);
|
|
3015
|
-
}
|
|
3016
|
-
function applyV12Metadata(node, annotations, diagnostics) {
|
|
3017
|
-
if ((!annotations || annotations.length === 0) && (!diagnostics || diagnostics.length === 0)) {
|
|
3018
|
-
return node;
|
|
3019
|
-
}
|
|
3020
|
-
return {
|
|
3021
|
-
...node,
|
|
3022
|
-
...annotations && annotations.length > 0 ? { annotations } : {},
|
|
3023
|
-
...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
|
|
3024
|
-
};
|
|
3025
|
-
}
|
|
3026
|
-
function valueFromProtocol(value) {
|
|
3027
|
-
switch (value.type) {
|
|
3028
|
-
case "selector":
|
|
3029
|
-
return createSelector(String(value.value ?? ""), value.selectorKind);
|
|
3030
|
-
case "literal":
|
|
3031
|
-
return createLiteral(
|
|
3032
|
-
value.value !== void 0 ? value.value : "",
|
|
3033
|
-
value.dataType
|
|
3034
|
-
);
|
|
3035
|
-
case "reference":
|
|
3036
|
-
return createReference(String(value.value ?? ""));
|
|
3037
|
-
case "expression":
|
|
3038
|
-
return createExpression(value.raw ?? String(value.value ?? ""));
|
|
3039
|
-
case "flag":
|
|
3040
|
-
return createFlag(
|
|
3041
|
-
value.name ?? String(value.value ?? ""),
|
|
3042
|
-
value.enabled ?? (typeof value.value === "boolean" ? value.value : true)
|
|
3043
|
-
);
|
|
3044
|
-
case "property-path":
|
|
3045
|
-
return createExpression(String(value.value ?? value.raw ?? ""));
|
|
3046
|
-
}
|
|
3047
|
-
}
|
|
3048
|
-
function toEnvelopeJSON(envelope) {
|
|
3049
|
-
const result = {
|
|
3050
|
-
lseVersion: envelope.lseVersion,
|
|
3051
|
-
nodes: envelope.nodes.map(toProtocolJSON)
|
|
3052
|
-
};
|
|
3053
|
-
if (envelope.features && envelope.features.length > 0) {
|
|
3054
|
-
result.features = [...envelope.features];
|
|
3055
|
-
}
|
|
3056
|
-
return result;
|
|
3057
|
-
}
|
|
3058
|
-
function fromEnvelopeJSON(json) {
|
|
3059
|
-
return {
|
|
3060
|
-
lseVersion: json.lseVersion,
|
|
3061
|
-
...json.features && json.features.length > 0 ? { features: json.features } : {},
|
|
3062
|
-
nodes: json.nodes.map(fromProtocolJSON)
|
|
3063
|
-
};
|
|
3064
|
-
}
|
|
3065
|
-
function isEnvelope(json) {
|
|
3066
|
-
return typeof json === "object" && json !== null && "lseVersion" in json && "nodes" in json && Array.isArray(json.nodes);
|
|
3067
|
-
}
|
|
3068
|
-
var VALID_KINDS = /* @__PURE__ */ new Set(["command", "event-handler", "compound"]);
|
|
3069
|
-
var VALID_VALUE_TYPES2 = /* @__PURE__ */ new Set([
|
|
3070
|
-
"selector",
|
|
3071
|
-
"literal",
|
|
3072
|
-
"reference",
|
|
3073
|
-
"expression",
|
|
3074
|
-
"property-path",
|
|
3075
|
-
"flag"
|
|
3076
|
-
]);
|
|
3077
|
-
var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set(["then", "and", "async", "sequential", "pipe"]);
|
|
3078
|
-
var VALID_ASYNC_VARIANTS = /* @__PURE__ */ new Set(["all", "race"]);
|
|
3079
|
-
var VALID_DIAGNOSTIC_LEVELS = /* @__PURE__ */ new Set(["error", "warning", "info"]);
|
|
3080
|
-
function validateProtocolJSON(json) {
|
|
3081
|
-
const diagnostics = [];
|
|
3082
|
-
if (typeof json !== "object" || json === null) {
|
|
3083
|
-
return [{ severity: "error", code: "INVALID_ROOT", message: "Root must be a JSON object" }];
|
|
3084
|
-
}
|
|
3085
|
-
const node = json;
|
|
3086
|
-
const kind = "kind" in node ? String(node.kind) : "command";
|
|
3087
|
-
if ("kind" in node && !VALID_KINDS.has(kind)) {
|
|
3088
|
-
diagnostics.push({
|
|
3089
|
-
severity: "error",
|
|
3090
|
-
code: "INVALID_KIND",
|
|
3091
|
-
message: `Invalid kind "${node.kind}". Must be one of: command, event-handler, compound`
|
|
3092
|
-
});
|
|
3093
|
-
}
|
|
3094
|
-
if (!("action" in node)) {
|
|
3095
|
-
diagnostics.push({
|
|
3096
|
-
severity: "error",
|
|
3097
|
-
code: "MISSING_ACTION",
|
|
3098
|
-
message: "Missing required field: action"
|
|
3099
|
-
});
|
|
3100
|
-
} else if (typeof node.action !== "string" || node.action.length === 0) {
|
|
3101
|
-
diagnostics.push({
|
|
3102
|
-
severity: "error",
|
|
3103
|
-
code: "INVALID_ACTION",
|
|
3104
|
-
message: "action must be a non-empty string"
|
|
3105
|
-
});
|
|
3106
|
-
}
|
|
3107
|
-
if (!("roles" in node) && kind !== "compound") {
|
|
3108
|
-
diagnostics.push({
|
|
3109
|
-
severity: "error",
|
|
3110
|
-
code: "MISSING_ROLES",
|
|
3111
|
-
message: "Missing required field: roles"
|
|
3112
|
-
});
|
|
3113
|
-
} else if ("roles" in node && (typeof node.roles !== "object" || node.roles === null || Array.isArray(node.roles))) {
|
|
3114
|
-
diagnostics.push({
|
|
3115
|
-
severity: "error",
|
|
3116
|
-
code: "INVALID_ROLES",
|
|
3117
|
-
message: "roles must be a plain object"
|
|
3118
|
-
});
|
|
3119
|
-
} else if ("roles" in node && node.roles) {
|
|
3120
|
-
for (const [role, value] of Object.entries(node.roles)) {
|
|
3121
|
-
if (typeof value !== "object" || value === null) {
|
|
3122
|
-
diagnostics.push({
|
|
3123
|
-
severity: "error",
|
|
3124
|
-
code: "INVALID_ROLE_VALUE",
|
|
3125
|
-
message: `Role "${role}" value must be an object`
|
|
3126
|
-
});
|
|
3127
|
-
continue;
|
|
3128
|
-
}
|
|
3129
|
-
const v = value;
|
|
3130
|
-
if (!("type" in v) || !VALID_VALUE_TYPES2.has(String(v.type))) {
|
|
3131
|
-
diagnostics.push({
|
|
3132
|
-
severity: "error",
|
|
3133
|
-
code: "INVALID_VALUE_TYPE",
|
|
3134
|
-
message: `Role "${role}" has invalid type "${v.type}"`
|
|
3135
|
-
});
|
|
3136
|
-
}
|
|
3137
|
-
if (v.type === "flag") {
|
|
3138
|
-
const hasName = typeof v.name === "string";
|
|
3139
|
-
const hasEnabled = typeof v.enabled === "boolean";
|
|
3140
|
-
const hasValue = "value" in v;
|
|
3141
|
-
if (!hasName && !hasValue) {
|
|
3142
|
-
diagnostics.push({
|
|
3143
|
-
severity: "error",
|
|
3144
|
-
code: "MISSING_FLAG_NAME",
|
|
3145
|
-
message: `Flag role "${role}" missing required field: name (or value)`
|
|
3146
|
-
});
|
|
3147
|
-
}
|
|
3148
|
-
if (!hasEnabled && !hasValue) {
|
|
3149
|
-
diagnostics.push({
|
|
3150
|
-
severity: "error",
|
|
3151
|
-
code: "MISSING_FLAG_ENABLED",
|
|
3152
|
-
message: `Flag role "${role}" missing required field: enabled (or value)`
|
|
3153
|
-
});
|
|
3154
|
-
}
|
|
3155
|
-
}
|
|
3156
|
-
if (v.type === "expression" && typeof v.raw !== "string" && !("value" in v)) {
|
|
3157
|
-
diagnostics.push({
|
|
3158
|
-
severity: "error",
|
|
3159
|
-
code: "MISSING_EXPRESSION_RAW",
|
|
3160
|
-
message: `Expression role "${role}" missing required field: raw (or value)`
|
|
3161
|
-
});
|
|
3162
|
-
}
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
if ("trigger" in node && node.trigger) {
|
|
3166
|
-
const trigger = node.trigger;
|
|
3167
|
-
if (typeof trigger !== "object" || trigger === null) {
|
|
3168
|
-
diagnostics.push({
|
|
3169
|
-
severity: "error",
|
|
3170
|
-
code: "INVALID_TRIGGER",
|
|
3171
|
-
message: "trigger must be an object"
|
|
3172
|
-
});
|
|
3173
|
-
} else if (!trigger.event || typeof trigger.event !== "string") {
|
|
3174
|
-
diagnostics.push({
|
|
3175
|
-
severity: "error",
|
|
3176
|
-
code: "INVALID_TRIGGER",
|
|
3177
|
-
message: "trigger.event is required and must be a non-empty string"
|
|
3178
|
-
});
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
if (kind === "event-handler" && !("trigger" in node)) {
|
|
3182
|
-
if (!("body" in node) || !Array.isArray(node.body)) {
|
|
3183
|
-
diagnostics.push({
|
|
3184
|
-
severity: "error",
|
|
3185
|
-
code: "MISSING_BODY",
|
|
3186
|
-
message: "event-handler node requires a body array"
|
|
3187
|
-
});
|
|
3188
|
-
}
|
|
3189
|
-
}
|
|
3190
|
-
if (kind === "compound") {
|
|
3191
|
-
if (!("statements" in node) || !Array.isArray(node.statements)) {
|
|
3192
|
-
diagnostics.push({
|
|
3193
|
-
severity: "error",
|
|
3194
|
-
code: "MISSING_STATEMENTS",
|
|
3195
|
-
message: "compound node requires a statements array"
|
|
3196
|
-
});
|
|
3197
|
-
}
|
|
3198
|
-
if ("chainType" in node && !VALID_CHAIN_TYPES.has(String(node.chainType))) {
|
|
3199
|
-
diagnostics.push({
|
|
3200
|
-
severity: "error",
|
|
3201
|
-
code: "INVALID_CHAIN_TYPE",
|
|
3202
|
-
message: `Invalid chainType "${node.chainType}". Must be one of: then, and, async, sequential, pipe`
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
|
-
}
|
|
3206
|
-
if ("diagnostics" in node) {
|
|
3207
|
-
if (!Array.isArray(node.diagnostics)) {
|
|
3208
|
-
diagnostics.push({
|
|
3209
|
-
severity: "error",
|
|
3210
|
-
code: "INVALID_DIAGNOSTICS",
|
|
3211
|
-
message: "diagnostics must be an array"
|
|
3212
|
-
});
|
|
3213
|
-
} else {
|
|
3214
|
-
for (let i = 0; i < node.diagnostics.length; i++) {
|
|
3215
|
-
const d = node.diagnostics[i];
|
|
3216
|
-
if (!d || typeof d !== "object") {
|
|
3217
|
-
diagnostics.push({
|
|
3218
|
-
severity: "error",
|
|
3219
|
-
code: "INVALID_DIAGNOSTIC_ENTRY",
|
|
3220
|
-
message: `diagnostics[${i}] must be an object`
|
|
3221
|
-
});
|
|
3222
|
-
continue;
|
|
3223
|
-
}
|
|
3224
|
-
if (!VALID_DIAGNOSTIC_LEVELS.has(String(d.level))) {
|
|
3225
|
-
diagnostics.push({
|
|
3226
|
-
severity: "error",
|
|
3227
|
-
code: "INVALID_DIAGNOSTIC_LEVEL",
|
|
3228
|
-
message: `diagnostics[${i}].level must be "error", "warning", or "info"`
|
|
3229
|
-
});
|
|
3230
|
-
}
|
|
3231
|
-
if (typeof d.message !== "string") {
|
|
3232
|
-
diagnostics.push({
|
|
3233
|
-
severity: "error",
|
|
3234
|
-
code: "MISSING_DIAGNOSTIC_MESSAGE",
|
|
3235
|
-
message: `diagnostics[${i}] missing required field: message`
|
|
3236
|
-
});
|
|
3237
|
-
}
|
|
3238
|
-
if ("code" in d && typeof d.code !== "string") {
|
|
3239
|
-
diagnostics.push({
|
|
3240
|
-
severity: "warning",
|
|
3241
|
-
code: "INVALID_DIAGNOSTIC_CODE",
|
|
3242
|
-
message: `diagnostics[${i}].code must be a string if present`
|
|
3243
|
-
});
|
|
3244
|
-
}
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3248
|
-
if ("annotations" in node) {
|
|
3249
|
-
if (!Array.isArray(node.annotations)) {
|
|
3250
|
-
diagnostics.push({
|
|
3251
|
-
severity: "error",
|
|
3252
|
-
code: "INVALID_ANNOTATIONS",
|
|
3253
|
-
message: "annotations must be an array"
|
|
3254
|
-
});
|
|
3255
|
-
} else {
|
|
3256
|
-
for (let i = 0; i < node.annotations.length; i++) {
|
|
3257
|
-
const a = node.annotations[i];
|
|
3258
|
-
if (!a || typeof a !== "object") {
|
|
3259
|
-
diagnostics.push({
|
|
3260
|
-
severity: "error",
|
|
3261
|
-
code: "INVALID_ANNOTATION_ENTRY",
|
|
3262
|
-
message: `annotations[${i}] must be an object`
|
|
3263
|
-
});
|
|
3264
|
-
continue;
|
|
3265
|
-
}
|
|
3266
|
-
if (typeof a.name !== "string" || a.name.length === 0) {
|
|
3267
|
-
diagnostics.push({
|
|
3268
|
-
severity: "error",
|
|
3269
|
-
code: "MISSING_ANNOTATION_NAME",
|
|
3270
|
-
message: `annotations[${i}] missing required field: name`
|
|
3271
|
-
});
|
|
3272
|
-
}
|
|
3273
|
-
}
|
|
3274
|
-
}
|
|
3275
|
-
}
|
|
3276
|
-
if ("asyncVariant" in node && !VALID_ASYNC_VARIANTS.has(String(node.asyncVariant))) {
|
|
3277
|
-
diagnostics.push({
|
|
3278
|
-
severity: "error",
|
|
3279
|
-
code: "INVALID_ASYNC_VARIANT",
|
|
3280
|
-
message: `Invalid asyncVariant "${node.asyncVariant}". Must be "all" or "race"`
|
|
3281
|
-
});
|
|
3282
|
-
}
|
|
3283
|
-
if ("arms" in node) {
|
|
3284
|
-
if (!Array.isArray(node.arms)) {
|
|
3285
|
-
diagnostics.push({
|
|
3286
|
-
severity: "error",
|
|
3287
|
-
code: "INVALID_ARMS",
|
|
3288
|
-
message: "arms must be an array"
|
|
3289
|
-
});
|
|
3290
|
-
} else {
|
|
3291
|
-
for (let i = 0; i < node.arms.length; i++) {
|
|
3292
|
-
const arm = node.arms[i];
|
|
3293
|
-
if (!arm || typeof arm !== "object") {
|
|
3294
|
-
diagnostics.push({
|
|
3295
|
-
severity: "error",
|
|
3296
|
-
code: "INVALID_ARM_ENTRY",
|
|
3297
|
-
message: `arms[${i}] must be an object`
|
|
3298
|
-
});
|
|
3299
|
-
continue;
|
|
3300
|
-
}
|
|
3301
|
-
if (!arm.pattern || typeof arm.pattern !== "object") {
|
|
3302
|
-
diagnostics.push({
|
|
3303
|
-
severity: "error",
|
|
3304
|
-
code: "MISSING_ARM_PATTERN",
|
|
3305
|
-
message: `arms[${i}] missing required field: pattern`
|
|
3306
|
-
});
|
|
3307
|
-
}
|
|
3308
|
-
if (!Array.isArray(arm.body)) {
|
|
3309
|
-
diagnostics.push({
|
|
3310
|
-
severity: "error",
|
|
3311
|
-
code: "MISSING_ARM_BODY",
|
|
3312
|
-
message: `arms[${i}] missing required field: body (array)`
|
|
3313
|
-
});
|
|
3314
|
-
}
|
|
3315
|
-
}
|
|
3316
|
-
}
|
|
3317
|
-
}
|
|
3318
|
-
return diagnostics;
|
|
3319
|
-
}
|
|
2106
|
+
import {
|
|
2107
|
+
toProtocolJSON,
|
|
2108
|
+
fromProtocolJSON,
|
|
2109
|
+
validateProtocolJSON,
|
|
2110
|
+
toEnvelopeJSON,
|
|
2111
|
+
fromEnvelopeJSON,
|
|
2112
|
+
isEnvelope
|
|
2113
|
+
} from "@lokascript/intent";
|
|
3320
2114
|
|
|
3321
2115
|
// src/ir/from-interchange.ts
|
|
3322
2116
|
function fromInterchangeNode(node) {
|
|
@@ -3455,7 +2249,7 @@ function convertValue(node) {
|
|
|
3455
2249
|
case "literal":
|
|
3456
2250
|
return convertLiteral(node);
|
|
3457
2251
|
case "selector":
|
|
3458
|
-
return createSelector(String(node.value ?? ""),
|
|
2252
|
+
return createSelector(String(node.value ?? ""), inferSelectorKind(String(node.value ?? "")));
|
|
3459
2253
|
case "identifier":
|
|
3460
2254
|
return convertIdentifier(node);
|
|
3461
2255
|
case "variable":
|
|
@@ -3557,6 +2351,33 @@ function renderExpr(node) {
|
|
|
3557
2351
|
return "";
|
|
3558
2352
|
}
|
|
3559
2353
|
}
|
|
2354
|
+
var SCROLL_MARKERS = /* @__PURE__ */ new Set([
|
|
2355
|
+
"to",
|
|
2356
|
+
"of",
|
|
2357
|
+
"the",
|
|
2358
|
+
"top",
|
|
2359
|
+
"bottom",
|
|
2360
|
+
"middle",
|
|
2361
|
+
"center",
|
|
2362
|
+
"nearest",
|
|
2363
|
+
"left",
|
|
2364
|
+
"right",
|
|
2365
|
+
"smoothly",
|
|
2366
|
+
"instantly"
|
|
2367
|
+
]);
|
|
2368
|
+
var URL_MARKERS = /* @__PURE__ */ new Set(["url"]);
|
|
2369
|
+
var PARTIALS_IN_MARKERS = /* @__PURE__ */ new Set(["partials", "in"]);
|
|
2370
|
+
function firstNonMarkerArg(args, markers) {
|
|
2371
|
+
for (const a of args) {
|
|
2372
|
+
if (a.type === "identifier") {
|
|
2373
|
+
const ident = a;
|
|
2374
|
+
const word = typeof ident.name === "string" ? ident.name : ident.value;
|
|
2375
|
+
if (typeof word === "string" && markers.has(word)) continue;
|
|
2376
|
+
}
|
|
2377
|
+
return a;
|
|
2378
|
+
}
|
|
2379
|
+
return void 0;
|
|
2380
|
+
}
|
|
3560
2381
|
function inferRoles(name, args, modifiers, target) {
|
|
3561
2382
|
const roles = {};
|
|
3562
2383
|
switch (name) {
|
|
@@ -3636,6 +2457,25 @@ function inferRoles(name, args, modifiers, target) {
|
|
|
3636
2457
|
if (args[0]) roles.patient = convertValue(args[0]);
|
|
3637
2458
|
break;
|
|
3638
2459
|
}
|
|
2460
|
+
// scroll [to] [position] target [smoothly|instantly] → destination=target
|
|
2461
|
+
case "scroll": {
|
|
2462
|
+
const t = firstNonMarkerArg(args, SCROLL_MARKERS);
|
|
2463
|
+
if (t) roles.destination = convertValue(t);
|
|
2464
|
+
break;
|
|
2465
|
+
}
|
|
2466
|
+
// push|replace url <X> → patient=X
|
|
2467
|
+
case "push":
|
|
2468
|
+
case "replace": {
|
|
2469
|
+
const t = firstNonMarkerArg(args, URL_MARKERS);
|
|
2470
|
+
if (t) roles.patient = convertValue(t);
|
|
2471
|
+
break;
|
|
2472
|
+
}
|
|
2473
|
+
// process partials in <X> → patient=X
|
|
2474
|
+
case "process": {
|
|
2475
|
+
const t = firstNonMarkerArg(args, PARTIALS_IN_MARKERS);
|
|
2476
|
+
if (t) roles.patient = convertValue(t);
|
|
2477
|
+
break;
|
|
2478
|
+
}
|
|
3639
2479
|
default: {
|
|
3640
2480
|
if (args[0]) roles.patient = convertValue(args[0]);
|
|
3641
2481
|
if (target) roles.destination = convertValue(target);
|
|
@@ -3644,7 +2484,7 @@ function inferRoles(name, args, modifiers, target) {
|
|
|
3644
2484
|
}
|
|
3645
2485
|
return roles;
|
|
3646
2486
|
}
|
|
3647
|
-
function
|
|
2487
|
+
function inferSelectorKind(value) {
|
|
3648
2488
|
if (!value) return void 0;
|
|
3649
2489
|
if (value.startsWith("#")) return "id";
|
|
3650
2490
|
if (value.startsWith(".")) return "class";
|
|
@@ -3655,7 +2495,7 @@ function inferSelectorKind2(value) {
|
|
|
3655
2495
|
}
|
|
3656
2496
|
function inferValueFromString(value) {
|
|
3657
2497
|
if (DEFAULT_REFERENCES.has(value)) return createReference(value);
|
|
3658
|
-
const kind =
|
|
2498
|
+
const kind = inferSelectorKind(value);
|
|
3659
2499
|
if (kind) return createSelector(value, kind);
|
|
3660
2500
|
return createLiteral(value);
|
|
3661
2501
|
}
|
|
@@ -5473,25 +4313,7 @@ async function registryToAOTBackends(registry) {
|
|
|
5473
4313
|
}
|
|
5474
4314
|
|
|
5475
4315
|
// src/schema/command-schema.ts
|
|
5476
|
-
|
|
5477
|
-
return {
|
|
5478
|
-
description: schema.description || `${schema.action} command`,
|
|
5479
|
-
category: schema.category || "general",
|
|
5480
|
-
primaryRole: schema.primaryRole || schema.roles[0]?.role || "patient",
|
|
5481
|
-
...schema,
|
|
5482
|
-
action: schema.action,
|
|
5483
|
-
roles: schema.roles
|
|
5484
|
-
};
|
|
5485
|
-
}
|
|
5486
|
-
function defineRole(role) {
|
|
5487
|
-
return {
|
|
5488
|
-
description: role.description || `${role.role} role`,
|
|
5489
|
-
...role,
|
|
5490
|
-
role: role.role,
|
|
5491
|
-
required: role.required,
|
|
5492
|
-
expectedTypes: role.expectedTypes
|
|
5493
|
-
};
|
|
5494
|
-
}
|
|
4316
|
+
import { defineCommand, defineRole, getRoleSpec } from "@lokascript/intent";
|
|
5495
4317
|
|
|
5496
4318
|
// src/generation/renderer.ts
|
|
5497
4319
|
function lookupKeyword(keywords, action, language) {
|
|
@@ -5584,71 +4406,7 @@ function createSchemaRenderer(schemas, profiles) {
|
|
|
5584
4406
|
}
|
|
5585
4407
|
|
|
5586
4408
|
// src/generation/diagnostics.ts
|
|
5587
|
-
|
|
5588
|
-
const diagnostics = [];
|
|
5589
|
-
function addWithSeverity(severity, message, options) {
|
|
5590
|
-
const diag = {
|
|
5591
|
-
message,
|
|
5592
|
-
severity,
|
|
5593
|
-
...options?.code != null && { code: options.code },
|
|
5594
|
-
...options?.line != null && { line: options.line },
|
|
5595
|
-
...options?.column != null && { column: options.column },
|
|
5596
|
-
...options?.source != null && { source: options.source },
|
|
5597
|
-
...options?.suggestions != null && options.suggestions.length > 0 && { suggestions: options.suggestions }
|
|
5598
|
-
};
|
|
5599
|
-
diagnostics.push(diag);
|
|
5600
|
-
}
|
|
5601
|
-
return {
|
|
5602
|
-
error(message, options) {
|
|
5603
|
-
addWithSeverity("error", message, options);
|
|
5604
|
-
},
|
|
5605
|
-
warning(message, options) {
|
|
5606
|
-
addWithSeverity("warning", message, options);
|
|
5607
|
-
},
|
|
5608
|
-
info(message, options) {
|
|
5609
|
-
addWithSeverity("info", message, options);
|
|
5610
|
-
},
|
|
5611
|
-
add(diagnostic) {
|
|
5612
|
-
diagnostics.push(diagnostic);
|
|
5613
|
-
},
|
|
5614
|
-
hasErrors() {
|
|
5615
|
-
return diagnostics.some((d) => d.severity === "error");
|
|
5616
|
-
},
|
|
5617
|
-
getDiagnostics() {
|
|
5618
|
-
return diagnostics;
|
|
5619
|
-
},
|
|
5620
|
-
toResult() {
|
|
5621
|
-
let errors = 0;
|
|
5622
|
-
let warnings = 0;
|
|
5623
|
-
let infos = 0;
|
|
5624
|
-
for (const d of diagnostics) {
|
|
5625
|
-
if (d.severity === "error") errors++;
|
|
5626
|
-
else if (d.severity === "warning") warnings++;
|
|
5627
|
-
else infos++;
|
|
5628
|
-
}
|
|
5629
|
-
return {
|
|
5630
|
-
ok: errors === 0,
|
|
5631
|
-
diagnostics,
|
|
5632
|
-
summary: { errors, warnings, infos }
|
|
5633
|
-
};
|
|
5634
|
-
}
|
|
5635
|
-
};
|
|
5636
|
-
}
|
|
5637
|
-
function fromError(error, options) {
|
|
5638
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5639
|
-
return {
|
|
5640
|
-
message,
|
|
5641
|
-
severity: "error",
|
|
5642
|
-
...options?.code != null && { code: options.code },
|
|
5643
|
-
...options?.line != null && { line: options.line },
|
|
5644
|
-
...options?.column != null && { column: options.column },
|
|
5645
|
-
...options?.source != null && { source: options.source },
|
|
5646
|
-
...options?.suggestions != null && options.suggestions.length > 0 && { suggestions: options.suggestions }
|
|
5647
|
-
};
|
|
5648
|
-
}
|
|
5649
|
-
function filterBySeverity(diagnostics, severity) {
|
|
5650
|
-
return diagnostics.filter((d) => d.severity === severity);
|
|
5651
|
-
}
|
|
4409
|
+
import { createDiagnosticCollector, fromError, filterBySeverity } from "@lokascript/intent";
|
|
5652
4410
|
|
|
5653
4411
|
// src/core/tokenization/token-utils.ts
|
|
5654
4412
|
var TokenStreamImpl = class {
|
|
@@ -7303,6 +6061,7 @@ export {
|
|
|
7303
6061
|
IdentifierExtractor,
|
|
7304
6062
|
InMemoryDictionary,
|
|
7305
6063
|
InMemoryProfileProvider,
|
|
6064
|
+
LatinExtendedIdentifierExtractor,
|
|
7306
6065
|
NullDictionary,
|
|
7307
6066
|
NullProfileProvider,
|
|
7308
6067
|
NumberExtractor,
|
|
@@ -7367,6 +6126,8 @@ export {
|
|
|
7367
6126
|
getAllPossessiveKeywords,
|
|
7368
6127
|
getDefaultExtractors,
|
|
7369
6128
|
getPossessiveReference,
|
|
6129
|
+
getRoleSpec,
|
|
6130
|
+
getRoleValue,
|
|
7370
6131
|
insertMarkers,
|
|
7371
6132
|
isAsciiIdentifierChar,
|
|
7372
6133
|
isAsciiLetter,
|