vne-language 0.1.0 → 0.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/package.json +1 -1
- package/src/collect-command-tokens.js +210 -20
- package/src/load-commands.js +30 -23
- package/src/smoke-check.js +119 -1
- package/syntaxes/base.json +0 -148
- package/syntaxes/vne.json +0 -152
- package/vne-language-0.1.3.vsix +0 -0
- package/vne-language-0.0.1.vsix +0 -0
package/package.json
CHANGED
|
@@ -5,13 +5,194 @@
|
|
|
5
5
|
root.VneCommandTokens = factory();
|
|
6
6
|
}
|
|
7
7
|
})(typeof globalThis !== "undefined" ? globalThis : this, function () {
|
|
8
|
-
const TOKEN_TYPES = ["keyword", "function"];
|
|
8
|
+
const TOKEN_TYPES = ["keyword", "function", "number"];
|
|
9
9
|
|
|
10
10
|
const escapeRegExp = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11
11
|
|
|
12
12
|
const actionLiterals = (entry) =>
|
|
13
13
|
Object.values((entry && entry.actions) || {}).filter((value) => typeof value === "string" && value.length > 0);
|
|
14
14
|
|
|
15
|
+
const enumLiterals = (arg) => {
|
|
16
|
+
if (!arg || arg.kind !== "enum" || !arg.values || typeof arg.values !== "object") return [];
|
|
17
|
+
|
|
18
|
+
return Object.values(arg.values).filter((value) => typeof value === "string" && value.length > 0);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const collectEnumLiteralsFromEntry = (entry) => {
|
|
22
|
+
const literals = new Set();
|
|
23
|
+
|
|
24
|
+
for (const arg of entry.args || []) {
|
|
25
|
+
for (const value of enumLiterals(arg)) literals.add(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (const specs of Object.values(entry.argsByAction || {})) {
|
|
29
|
+
for (const arg of specs || []) {
|
|
30
|
+
for (const value of enumLiterals(arg)) literals.add(value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const value of actionLiterals(entry)) literals.add(value);
|
|
35
|
+
|
|
36
|
+
return [...literals].sort((a, b) => b.length - a.length);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const isDelimitedToken = (token) => {
|
|
40
|
+
if (!token || !token.text) return false;
|
|
41
|
+
const open = token.text[0];
|
|
42
|
+
return open === "{" || open === '"' || open === "'";
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const matchesArg = (spec, token) => {
|
|
46
|
+
if (!spec || !token) return false;
|
|
47
|
+
|
|
48
|
+
if (spec.kind === "id") {
|
|
49
|
+
if (spec.delimited) return isDelimitedToken(token);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (spec.kind === "number") return /^-?\d+(?:\.\d+)?$/.test(token.text);
|
|
54
|
+
|
|
55
|
+
if (spec.kind === "enum") return enumLiterals(spec).includes(token.text);
|
|
56
|
+
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Read `{…}`, `"…"`, or `'…'` as a single token (continues after the closer).
|
|
62
|
+
* @returns {{ text: string, start: number, end: number } | null}
|
|
63
|
+
*/
|
|
64
|
+
const readDelimitedToken = (line, from, end = line.length) => {
|
|
65
|
+
const open = line[from];
|
|
66
|
+
if (from >= end) return null;
|
|
67
|
+
|
|
68
|
+
if (open === "{") {
|
|
69
|
+
let depth = 1;
|
|
70
|
+
let index = from + 1;
|
|
71
|
+
|
|
72
|
+
while (index < end && depth > 0) {
|
|
73
|
+
const ch = line[index];
|
|
74
|
+
if (ch === "{") depth += 1;
|
|
75
|
+
else if (ch === "}") depth -= 1;
|
|
76
|
+
index += 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { text: line.slice(from, index), start: from, end: index };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (open === '"' || open === "'") {
|
|
83
|
+
let index = from + 1;
|
|
84
|
+
|
|
85
|
+
while (index < end) {
|
|
86
|
+
const ch = line[index];
|
|
87
|
+
if (ch === "\\") {
|
|
88
|
+
index += 2;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (ch === open) {
|
|
92
|
+
index += 1;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
index += 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { text: line.slice(from, index), start: from, end: index };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Read next positional token (stops before `|` or `key:`; `{…}` / quotes are one token).
|
|
106
|
+
* @param {string[]} [extraLiterals] longest-first operator/enum literals (e.g. `===`, `++`)
|
|
107
|
+
* @param {number} [end]
|
|
108
|
+
* @returns {{ text: string, start: number, end: number } | null}
|
|
109
|
+
*/
|
|
110
|
+
const nextPositionalToken = (line, from, extraLiterals = [], end = line.length) => {
|
|
111
|
+
let index = from;
|
|
112
|
+
|
|
113
|
+
while (index < end && /\s/.test(line[index])) index += 1;
|
|
114
|
+
|
|
115
|
+
if (index >= end) return null;
|
|
116
|
+
|
|
117
|
+
const ch = line[index];
|
|
118
|
+
if (ch === "|") return null;
|
|
119
|
+
|
|
120
|
+
if (ch === "{" || ch === '"' || ch === "'") {
|
|
121
|
+
return readDelimitedToken(line, index, end);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (/^[a-zA-Z0-9_-]+:/.test(line.slice(index))) return null;
|
|
125
|
+
|
|
126
|
+
const rest = line.slice(index, end);
|
|
127
|
+
|
|
128
|
+
for (const literal of extraLiterals) {
|
|
129
|
+
if (rest.startsWith(literal)) {
|
|
130
|
+
const after = rest.slice(literal.length);
|
|
131
|
+
// Prefer operator match when next char is boundary (space/end/brace) or literal is word-like id
|
|
132
|
+
if (after === "" || /^\s/.test(after) || /^[{|"']/.test(after) || /^[a-zA-Z0-9_-]+:/.test(after)) {
|
|
133
|
+
return { text: literal, start: index, end: index + literal.length };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const numberMatch = /^-?\d+(?:\.\d+)?/.exec(rest);
|
|
139
|
+
if (numberMatch) {
|
|
140
|
+
return { text: numberMatch[0], start: index, end: index + numberMatch[0].length };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const idMatch = /^[a-zA-Z0-9_/-]+/.exec(rest);
|
|
144
|
+
if (!idMatch) return null;
|
|
145
|
+
|
|
146
|
+
return { text: idMatch[0], start: index, end: index + idMatch[0].length };
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const collectPositionalTokens = (line, from, end = line.length, extraLiterals = []) => {
|
|
150
|
+
const tokens = [];
|
|
151
|
+
let cursor = from;
|
|
152
|
+
|
|
153
|
+
while (cursor < end) {
|
|
154
|
+
const token = nextPositionalToken(line, cursor, extraLiterals, end);
|
|
155
|
+
if (!token || token.start >= end) break;
|
|
156
|
+
tokens.push(token);
|
|
157
|
+
cursor = token.end;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return tokens;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const pushArgRanges = (ranges, lineIndex, tokens, specs) => {
|
|
164
|
+
const argSpecs = Array.isArray(specs) ? specs : [];
|
|
165
|
+
let tokenIndex = 0;
|
|
166
|
+
|
|
167
|
+
for (const spec of argSpecs) {
|
|
168
|
+
if (!spec) continue;
|
|
169
|
+
|
|
170
|
+
if (tokenIndex >= tokens.length) {
|
|
171
|
+
if (spec.optional) continue;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const token = tokens[tokenIndex];
|
|
176
|
+
|
|
177
|
+
if (matchesArg(spec, token)) {
|
|
178
|
+
if (spec.kind === "id") {
|
|
179
|
+
ranges.push({ line: lineIndex, start: token.start, length: token.text.length, type: "function" });
|
|
180
|
+
} else if (spec.kind === "number") {
|
|
181
|
+
ranges.push({ line: lineIndex, start: token.start, length: token.text.length, type: "number" });
|
|
182
|
+
} else if (spec.kind === "enum") {
|
|
183
|
+
ranges.push({ line: lineIndex, start: token.start, length: token.text.length, type: "keyword" });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
tokenIndex += 1;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (spec.optional) continue;
|
|
191
|
+
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
15
196
|
/**
|
|
16
197
|
* Collect semantic token ranges for document text.
|
|
17
198
|
* @returns {{ line: number, start: number, length: number, type: string }[]}
|
|
@@ -32,38 +213,42 @@
|
|
|
32
213
|
const lead = line.slice(trimmedStart);
|
|
33
214
|
if (lead.startsWith("//") || lead.startsWith("#")) continue;
|
|
34
215
|
|
|
35
|
-
const
|
|
216
|
+
const pipeIndex = line.indexOf("|");
|
|
217
|
+
const execEnd = pipeIndex === -1 ? line.length : pipeIndex;
|
|
218
|
+
const execMatch = /^(\s*)([%$])\s+([a-zA-Z0-9_.-]+)/.exec(line.slice(0, execEnd));
|
|
36
219
|
|
|
37
220
|
if (execMatch) {
|
|
38
221
|
const prefix = execMatch[2];
|
|
39
222
|
const commandName = execMatch[3];
|
|
40
|
-
const action = execMatch[4];
|
|
41
223
|
const dict = prefix === "$" ? modules : blocks;
|
|
42
224
|
const entry = dict[commandName];
|
|
43
|
-
const actions = actionLiterals(entry);
|
|
44
225
|
|
|
45
|
-
if (entry
|
|
46
|
-
const
|
|
47
|
-
const
|
|
226
|
+
if (entry) {
|
|
227
|
+
const commandStart = line.indexOf(commandName, trimmedStart);
|
|
228
|
+
const extraLiterals = collectEnumLiteralsFromEntry(entry);
|
|
229
|
+
const tokens = collectPositionalTokens(line, commandStart + commandName.length, execEnd, extraLiterals);
|
|
230
|
+
const actions = actionLiterals(entry);
|
|
231
|
+
const first = tokens[0];
|
|
232
|
+
const hasAction = Boolean(first && actions.includes(first.text));
|
|
48
233
|
|
|
49
|
-
if (
|
|
50
|
-
ranges.push({
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
234
|
+
if (hasAction) {
|
|
235
|
+
ranges.push({
|
|
236
|
+
line: lineIndex,
|
|
237
|
+
start: first.start,
|
|
238
|
+
length: first.text.length,
|
|
239
|
+
type: "keyword",
|
|
240
|
+
});
|
|
56
241
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
242
|
+
const specs =
|
|
243
|
+
(entry.argsByAction && entry.argsByAction[first.text]) ||
|
|
244
|
+
(actions.length ? [{ kind: "id" }] : []);
|
|
245
|
+
pushArgRanges(ranges, lineIndex, tokens.slice(1), specs);
|
|
246
|
+
} else if (Array.isArray(entry.args) && entry.args.length) {
|
|
247
|
+
pushArgRanges(ranges, lineIndex, tokens, entry.args);
|
|
61
248
|
}
|
|
62
249
|
}
|
|
63
250
|
}
|
|
64
251
|
|
|
65
|
-
const pipeIndex = line.indexOf("|");
|
|
66
|
-
|
|
67
252
|
if (pipeIndex !== -1 && lineKeywords.length) {
|
|
68
253
|
const rest = line.slice(pipeIndex + 1);
|
|
69
254
|
|
|
@@ -113,7 +298,12 @@
|
|
|
113
298
|
TOKEN_TYPES,
|
|
114
299
|
actionLiterals,
|
|
115
300
|
collectCommandTokenRanges,
|
|
301
|
+
collectPositionalTokens,
|
|
116
302
|
encodeSemanticTokenData,
|
|
303
|
+
enumLiterals,
|
|
117
304
|
escapeRegExp,
|
|
305
|
+
isDelimitedToken,
|
|
306
|
+
nextPositionalToken,
|
|
307
|
+
readDelimitedToken,
|
|
118
308
|
};
|
|
119
309
|
});
|
package/src/load-commands.js
CHANGED
|
@@ -42,10 +42,20 @@ const findContractPackageDirs = (gameRoot) => {
|
|
|
42
42
|
|
|
43
43
|
const importModule = async (filePath) => import(pathToFileURL(filePath).href);
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* @param {unknown} keywords
|
|
47
|
+
* @returns {string[]}
|
|
48
|
+
*/
|
|
49
|
+
const collectLineKeywords = (keywords) => {
|
|
50
|
+
if (!keywords || typeof keywords !== "object") return [];
|
|
51
|
+
|
|
52
|
+
return Object.values(keywords).filter((value) => typeof value === "string" && value.length > 0);
|
|
53
|
+
};
|
|
54
|
+
|
|
45
55
|
/**
|
|
46
56
|
* Load and merge SCENARIO_COMMANDS from contracts in node_modules of the game package.
|
|
47
57
|
*
|
|
48
|
-
* Imports only `dist/commands.js` when present (not the full package entry), so we do not
|
|
58
|
+
* Imports only `dist/commands.js` / `dist/const.js` when present (not the full package entry), so we do not
|
|
49
59
|
* pull every contract's side-effect graph into the editor/extension host.
|
|
50
60
|
*
|
|
51
61
|
* @param {string} gameRoot
|
|
@@ -56,34 +66,31 @@ const loadCommandsFromNodeModules = async (gameRoot) => {
|
|
|
56
66
|
|
|
57
67
|
const packageDirs = findContractPackageDirs(gameRoot);
|
|
58
68
|
const manifests = [];
|
|
59
|
-
|
|
69
|
+
const lineKeywords = [];
|
|
60
70
|
|
|
61
|
-
for (const [
|
|
71
|
+
for (const [, packageDir] of packageDirs) {
|
|
62
72
|
const commandsPath = path.join(packageDir, "dist", "commands.js");
|
|
73
|
+
const constPath = path.join(packageDir, "dist", "const.js");
|
|
63
74
|
|
|
64
|
-
if (
|
|
75
|
+
if (fs.existsSync(commandsPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const mod = await importModule(commandsPath);
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (shortName === "contracts.core.scenario") {
|
|
72
|
-
const constPath = path.join(packageDir, "dist", "const.js");
|
|
79
|
+
if (mod.SCENARIO_COMMANDS) manifests.push(mod.SCENARIO_COMMANDS);
|
|
80
|
+
} catch {
|
|
81
|
+
// Skip unreadable / incompatible packages.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
73
84
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
if (fs.existsSync(constPath)) {
|
|
86
|
+
try {
|
|
87
|
+
const consts = await importModule(constPath);
|
|
88
|
+
const keywords = consts.LINE_KEYWORDS || consts.CONSTANTS?.LINE_KEYWORDS;
|
|
77
89
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
90
|
+
lineKeywords.push(...collectLineKeywords(keywords));
|
|
91
|
+
} catch {
|
|
92
|
+
// Skip unreadable / incompatible packages.
|
|
84
93
|
}
|
|
85
|
-
} catch {
|
|
86
|
-
// Skip unreadable / incompatible packages.
|
|
87
94
|
}
|
|
88
95
|
}
|
|
89
96
|
|
|
@@ -92,7 +99,7 @@ const loadCommandsFromNodeModules = async (gameRoot) => {
|
|
|
92
99
|
return {
|
|
93
100
|
modules: merged.modules,
|
|
94
101
|
blocks: merged.blocks,
|
|
95
|
-
lineKeywords,
|
|
102
|
+
lineKeywords: [...new Set(lineKeywords)],
|
|
96
103
|
};
|
|
97
104
|
};
|
|
98
105
|
|
package/src/smoke-check.js
CHANGED
|
@@ -22,6 +22,11 @@ const main = async () => {
|
|
|
22
22
|
|
|
23
23
|
assert(commands.modules.stack, "expected stack module from contracts");
|
|
24
24
|
assert(commands.modules.scenario, "expected scenario module from contracts");
|
|
25
|
+
assert(commands.modules.save, "expected save module from contracts");
|
|
26
|
+
assert(commands.modules["bl.bg"], "expected bl.bg module from layer contracts");
|
|
27
|
+
assert(commands.modules["audio.music"], "expected audio.music module from contracts");
|
|
28
|
+
assert(commands.blocks.qte, "expected qte block from contracts");
|
|
29
|
+
assert(commands.blocks.choose, "expected choose block from contracts");
|
|
25
30
|
assert(
|
|
26
31
|
Object.values(commands.modules.stack.actions || {}).includes("jump"),
|
|
27
32
|
"expected stack jump action",
|
|
@@ -30,10 +35,51 @@ const main = async () => {
|
|
|
30
35
|
Object.values(commands.modules.scenario.actions || {}).includes("goto"),
|
|
31
36
|
"expected scenario goto action",
|
|
32
37
|
);
|
|
38
|
+
assert(
|
|
39
|
+
Object.values(commands.modules.save.actions || {}).includes("key"),
|
|
40
|
+
"expected save key action",
|
|
41
|
+
);
|
|
42
|
+
assert(
|
|
43
|
+
Object.values(commands.modules["bl.bg"].actions || {}).includes("show"),
|
|
44
|
+
"expected bl.bg show action",
|
|
45
|
+
);
|
|
46
|
+
assert(
|
|
47
|
+
Object.values(commands.modules["audio.music"].actions || {}).includes("play"),
|
|
48
|
+
"expected audio.music play action",
|
|
49
|
+
);
|
|
50
|
+
assert(commands.modules["text.meet"], "expected text.meet module from contracts");
|
|
51
|
+
assert(commands.modules["ul.sprite"], "expected ul.sprite module from layer contracts");
|
|
52
|
+
assert(
|
|
53
|
+
Array.isArray(commands.modules["text.meet"].args) && commands.modules["text.meet"].args[0]?.kind === "id",
|
|
54
|
+
"expected text.meet args id slot",
|
|
55
|
+
);
|
|
56
|
+
assert(
|
|
57
|
+
Array.isArray(commands.modules["ul.sprite"].argsByAction?.show) &&
|
|
58
|
+
commands.modules["ul.sprite"].argsByAction.show.some((arg) => arg.kind === "enum"),
|
|
59
|
+
"expected ul.sprite show position enum slot",
|
|
60
|
+
);
|
|
33
61
|
assert(commands.lineKeywords.includes("async"), "expected LINE_KEYWORDS from scenario contract");
|
|
62
|
+
assert(commands.lineKeywords.includes("extend"), "expected LINE_KEYWORDS from text contract");
|
|
63
|
+
assert(commands.lineKeywords.includes("global"), "expected LINE_KEYWORDS from vars contract");
|
|
64
|
+
assert(commands.lineKeywords.includes("dangerous"), "expected LINE_KEYWORDS from layer animation contract");
|
|
65
|
+
assert(commands.lineKeywords.includes("qte-fallback"), "expected LINE_KEYWORDS from qte contract");
|
|
34
66
|
|
|
35
67
|
const ranges = collectCommandTokenRanges(
|
|
36
|
-
[
|
|
68
|
+
[
|
|
69
|
+
" $ stack jump testsCanvas",
|
|
70
|
+
' "hi" | async global',
|
|
71
|
+
" $ scenario goto loop",
|
|
72
|
+
" $ save key autosave",
|
|
73
|
+
" $ bl.bg show forest",
|
|
74
|
+
" $ audio.music play theme",
|
|
75
|
+
" $ text.meet alice",
|
|
76
|
+
" $ ul.sprite show co center",
|
|
77
|
+
" $ flag quest unset",
|
|
78
|
+
" $ counter gold += 2",
|
|
79
|
+
" $ bl.bg show {castle/surgery_room} opacity 500 | async",
|
|
80
|
+
" $ ul.sprite show co left {co/default} opacity 500",
|
|
81
|
+
" $ ul.sprite hide co opacity 300",
|
|
82
|
+
].join("\n"),
|
|
37
83
|
commands,
|
|
38
84
|
);
|
|
39
85
|
|
|
@@ -53,6 +99,78 @@ const main = async () => {
|
|
|
53
99
|
ranges.some((range) => range.type === "keyword" && range.line === 2),
|
|
54
100
|
"expected keyword token on scenario goto",
|
|
55
101
|
);
|
|
102
|
+
assert(
|
|
103
|
+
ranges.some((range) => range.type === "keyword" && range.line === 3),
|
|
104
|
+
"expected keyword token on save key",
|
|
105
|
+
);
|
|
106
|
+
assert(
|
|
107
|
+
ranges.some((range) => range.type === "keyword" && range.line === 4),
|
|
108
|
+
"expected keyword token on bl.bg show",
|
|
109
|
+
);
|
|
110
|
+
assert(
|
|
111
|
+
ranges.some((range) => range.type === "keyword" && range.line === 5),
|
|
112
|
+
"expected keyword token on audio.music play",
|
|
113
|
+
);
|
|
114
|
+
assert(
|
|
115
|
+
ranges.some((range) => range.type === "function" && range.line === 6),
|
|
116
|
+
"expected function token for text.meet speaker",
|
|
117
|
+
);
|
|
118
|
+
assert(
|
|
119
|
+
ranges.some((range) => range.type === "keyword" && range.line === 7 && range.length === "show".length),
|
|
120
|
+
"expected keyword token on ul.sprite show",
|
|
121
|
+
);
|
|
122
|
+
assert(
|
|
123
|
+
ranges.some((range) => range.type === "function" && range.line === 7),
|
|
124
|
+
"expected function token for sprite name",
|
|
125
|
+
);
|
|
126
|
+
assert(
|
|
127
|
+
ranges.some((range) => range.type === "keyword" && range.line === 7 && range.length === "center".length),
|
|
128
|
+
"expected keyword token for sprite position",
|
|
129
|
+
);
|
|
130
|
+
assert(
|
|
131
|
+
ranges.some((range) => range.type === "function" && range.line === 8),
|
|
132
|
+
"expected function token for flag name",
|
|
133
|
+
);
|
|
134
|
+
assert(
|
|
135
|
+
ranges.some((range) => range.type === "keyword" && range.line === 8 && range.length === "unset".length),
|
|
136
|
+
"expected keyword token for flag unset",
|
|
137
|
+
);
|
|
138
|
+
assert(
|
|
139
|
+
ranges.some((range) => range.type === "function" && range.line === 9),
|
|
140
|
+
"expected function token for counter name",
|
|
141
|
+
);
|
|
142
|
+
assert(
|
|
143
|
+
ranges.some((range) => range.type === "keyword" && range.line === 9 && range.length === "+=".length),
|
|
144
|
+
"expected keyword token for counter +=",
|
|
145
|
+
);
|
|
146
|
+
assert(
|
|
147
|
+
ranges.some((range) => range.type === "function" && range.line === 10 && range.length === "{castle/surgery_room}".length),
|
|
148
|
+
"expected function token for braced bg media ref",
|
|
149
|
+
);
|
|
150
|
+
assert(
|
|
151
|
+
ranges.some((range) => range.type === "keyword" && range.line === 10 && range.length === "opacity".length),
|
|
152
|
+
"expected keyword token for bg opacity transition",
|
|
153
|
+
);
|
|
154
|
+
assert(
|
|
155
|
+
ranges.some((range) => range.type === "number" && range.line === 10 && range.length === "500".length),
|
|
156
|
+
"expected number token for bg duration",
|
|
157
|
+
);
|
|
158
|
+
assert(
|
|
159
|
+
ranges.some((range) => range.type === "function" && range.line === 11 && range.length === "{co/default}".length),
|
|
160
|
+
"expected function token for braced sprite variation",
|
|
161
|
+
);
|
|
162
|
+
assert(
|
|
163
|
+
ranges.some((range) => range.type === "keyword" && range.line === 11 && range.length === "opacity".length),
|
|
164
|
+
"expected keyword token for sprite show opacity",
|
|
165
|
+
);
|
|
166
|
+
assert(
|
|
167
|
+
ranges.some((range) => range.type === "keyword" && range.line === 12 && range.length === "opacity".length),
|
|
168
|
+
"expected keyword token for sprite hide opacity",
|
|
169
|
+
);
|
|
170
|
+
assert(
|
|
171
|
+
ranges.some((range) => range.type === "number" && range.line === 12 && range.length === "300".length),
|
|
172
|
+
"expected number token for sprite hide duration",
|
|
173
|
+
);
|
|
56
174
|
|
|
57
175
|
console.log("ok", {
|
|
58
176
|
gameRoot,
|
package/syntaxes/base.json
CHANGED
|
@@ -61,157 +61,9 @@
|
|
|
61
61
|
"name": "variable.other",
|
|
62
62
|
"match": "(?<=\\s)[a-zA-Z0-9_-]+:(?=\\s|$)"
|
|
63
63
|
},
|
|
64
|
-
{
|
|
65
|
-
"name": "variable.other",
|
|
66
|
-
"match": "(?<=\\b(counter|flag)\\s+)[a-zA-Z0-9_-]+"
|
|
67
|
-
},
|
|
68
64
|
{
|
|
69
65
|
"name": "keyword.other",
|
|
70
66
|
"match": "(?<=^\\s*)[a-zA-Z0-9_-]+(?=\\s+\")"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"name": "keyword.control",
|
|
74
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s)(show|hide|change|move)\\b"
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"name": "keyword.control",
|
|
78
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\s)(show|hide|change)\\b"
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
"name": "keyword.control",
|
|
82
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.video\\s)(show|hide|change)\\b"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"name": "keyword.control",
|
|
86
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.text\\s)(show|hide|change|move)\\b"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"name": "keyword.control",
|
|
90
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.filter\\s)(set|unset)\\b"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"name": "keyword.control",
|
|
94
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.clip\\s)(set|unset)\\b"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"name": "keyword.control",
|
|
98
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.mask\\s)(set|unset|change)\\b"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"name": "keyword.control",
|
|
102
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.scale\\s)(set|unset)\\b"
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
"name": "keyword.control",
|
|
106
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.animation\\s)(set|unset)\\b"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"name": "keyword.control",
|
|
110
|
-
"match": "(?<=\\baudio\\.(music|sound|ambient|voice)\\s)(play|stop|pause|resume|volume)\\b"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"name": "keyword.control",
|
|
114
|
-
"match": "(?<=\\bvideo\\s)play\\b"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"name": "keyword.control",
|
|
118
|
-
"match": "(?<=\\binterface\\s)(show|hide|view)\\b"
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"name": "keyword.control",
|
|
122
|
-
"match": "(?<=\\bsave\\s)key\\b"
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"name": "keyword.control",
|
|
126
|
-
"match": "(?<=\\bflag\\s+[a-zA-Z0-9_-]+\\s)(set|unset)\\b"
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"name": "keyword.control",
|
|
130
|
-
"match": "(?<=\\btime\\s+)(add|set)\\b"
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"name": "keyword.control",
|
|
134
|
-
"match": "(?<=\\bdate\\s+)(add|set)\\b"
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
"name": "keyword.control",
|
|
138
|
-
"match": "(?<=\\btext\\.wall\\s+)(clear|start|end)\\b"
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
"name": "keyword.control",
|
|
142
|
-
"match": "(?<=\\btext\\.meet\\s+)[a-zA-Z0-9_-]+"
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
"name": "keyword.control",
|
|
146
|
-
"match": "(?<=\\bcomment\\s+)hide\\b"
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
"name": "keyword.control",
|
|
150
|
-
"match": "(?<=\\bachievement\\s+)unlock\\b"
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"name": "keyword.control",
|
|
154
|
-
"match": "(?<=\\bwallet\\s+[a-zA-Z0-9_-]+\\s)(add|set|reset)\\b"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"name": "keyword.control",
|
|
158
|
-
"match": "(?<=\\bcredits\\s+)(show|hide)\\b"
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"name": "entity.name.function",
|
|
162
|
-
"match": "(?<=\\bachievement\\s+unlock\\s+)[a-zA-Z0-9_-]+"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"name": "entity.name.function",
|
|
166
|
-
"match": "(?<=\\bwallet\\s+)[a-zA-Z0-9_-]+(?=\\s+(add|set|reset))"
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
"name": "entity.name.type",
|
|
170
|
-
"match": "(?<=\\binterface\\s+view\\s+)[a-zA-Z0-9_-]+"
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
"name": "entity.name.function",
|
|
174
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\sshow\\s\\{[^}]*\\}\\s)[a-zA-Z0-9_-]+"
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"name": "entity.name.function",
|
|
178
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\shide\\s)[a-zA-Z0-9_-]+"
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
"name": "entity.name.function",
|
|
182
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\sshow\\s)[a-zA-Z0-9_-]+"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"name": "entity.name.function",
|
|
186
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s(hide|change|move)\\s)[a-zA-Z0-9_-]+"
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"name": "entity.name.function",
|
|
190
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.video\\s(show|change)\\s)[a-zA-Z0-9_{}/-]+"
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
"name": "entity.name.function",
|
|
194
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.text\\s(show|hide|change|move)\\s)[a-zA-Z0-9_-]+"
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
"name": "entity.name.function",
|
|
198
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.filter\\sset\\s)[a-zA-Z0-9_-]+"
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"name": "entity.name.function",
|
|
202
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.clip\\sset\\s)[a-zA-Z0-9_-]+"
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
"name": "entity.name.function",
|
|
206
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.mask\\sset\\s)[a-zA-Z0-9_-]+"
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
"name": "entity.name.function",
|
|
210
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.animation\\sset\\s)[a-zA-Z0-9_-]+"
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
"name": "keyword.other",
|
|
214
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s(show|hide|change|move)\\s[a-zA-Z0-9_-]+\\s)[a-zA-Z0-9_-]+"
|
|
215
67
|
}
|
|
216
68
|
],
|
|
217
69
|
"repository": {},
|
package/syntaxes/vne.json
CHANGED
|
@@ -61,161 +61,9 @@
|
|
|
61
61
|
"name": "variable.other",
|
|
62
62
|
"match": "(?<=\\s)[a-zA-Z0-9_-]+:(?=\\s|$)"
|
|
63
63
|
},
|
|
64
|
-
{
|
|
65
|
-
"name": "variable.other",
|
|
66
|
-
"match": "(?<=\\b(counter|flag)\\s+)[a-zA-Z0-9_-]+"
|
|
67
|
-
},
|
|
68
64
|
{
|
|
69
65
|
"name": "keyword.other",
|
|
70
66
|
"match": "(?<=^\\s*)[a-zA-Z0-9_-]+(?=\\s+\")"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"name": "keyword.control",
|
|
74
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s)(show|hide|change|move)\\b"
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"name": "keyword.control",
|
|
78
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\s)(show|hide|change)\\b"
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
"name": "keyword.control",
|
|
82
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.video\\s)(show|hide|change)\\b"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"name": "keyword.control",
|
|
86
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.text\\s)(show|hide|change|move)\\b"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"name": "keyword.control",
|
|
90
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.filter\\s)(set|unset)\\b"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"name": "keyword.control",
|
|
94
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.clip\\s)(set|unset)\\b"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"name": "keyword.control",
|
|
98
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.mask\\s)(set|unset|change)\\b"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"name": "keyword.control",
|
|
102
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.scale\\s)(set|unset)\\b"
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
"name": "keyword.control",
|
|
106
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.animation\\s)(set|unset)\\b"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"name": "keyword.control",
|
|
110
|
-
"match": "(?<=\\baudio\\.(music|sound|ambient|voice)\\s)(play|stop|pause|resume|volume)\\b"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"name": "keyword.control",
|
|
114
|
-
"match": "(?<=\\bvideo\\s)play\\b"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"name": "keyword.control",
|
|
118
|
-
"match": "(?<=\\binterface\\s)(show|hide|view)\\b"
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"name": "keyword.control",
|
|
122
|
-
"match": "(?<=\\bsave\\s)key\\b"
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"name": "keyword.control",
|
|
126
|
-
"match": "(?<=\\bflag\\s+[a-zA-Z0-9_-]+\\s)(set|unset)\\b"
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"name": "keyword.control",
|
|
130
|
-
"match": "(?<=\\btime\\s+)(add|set)\\b"
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"name": "keyword.control",
|
|
134
|
-
"match": "(?<=\\bdate\\s+)(add|set)\\b"
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
"name": "keyword.control",
|
|
138
|
-
"match": "(?<=\\btext\\.wall\\s+)(clear|start|end)\\b"
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
"name": "keyword.control",
|
|
142
|
-
"match": "(?<=\\btext\\.meet\\s+)[a-zA-Z0-9_-]+"
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
"name": "keyword.control",
|
|
146
|
-
"match": "(?<=\\bcomment\\s+)hide\\b"
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
"name": "keyword.control",
|
|
150
|
-
"match": "(?<=\\bachievement\\s+)unlock\\b"
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"name": "keyword.control",
|
|
154
|
-
"match": "(?<=\\bwallet\\s+[a-zA-Z0-9_-]+\\s)(add|set|reset)\\b"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"name": "keyword.control",
|
|
158
|
-
"match": "(?<=\\bcredits\\s+)(show|hide)\\b"
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"name": "entity.name.function",
|
|
162
|
-
"match": "(?<=\\bachievement\\s+unlock\\s+)[a-zA-Z0-9_-]+"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"name": "entity.name.function",
|
|
166
|
-
"match": "(?<=\\bwallet\\s+)[a-zA-Z0-9_-]+(?=\\s+(add|set|reset))"
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
"name": "entity.name.type",
|
|
170
|
-
"match": "(?<=\\binterface\\s+view\\s+)[a-zA-Z0-9_-]+"
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
"name": "entity.name.function",
|
|
174
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\sshow\\s\\{[^}]*\\}\\s)[a-zA-Z0-9_-]+"
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"name": "entity.name.function",
|
|
178
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.bg\\shide\\s)[a-zA-Z0-9_-]+"
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
"name": "entity.name.function",
|
|
182
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\sshow\\s)[a-zA-Z0-9_-]+"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"name": "entity.name.function",
|
|
186
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s(hide|change|move)\\s)[a-zA-Z0-9_-]+"
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"name": "entity.name.function",
|
|
190
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.video\\s(show|change)\\s)[a-zA-Z0-9_{}/-]+"
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
"name": "entity.name.function",
|
|
194
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.text\\s(show|hide|change|move)\\s)[a-zA-Z0-9_-]+"
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
"name": "entity.name.function",
|
|
198
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.filter\\sset\\s)[a-zA-Z0-9_-]+"
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"name": "entity.name.function",
|
|
202
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.clip\\sset\\s)[a-zA-Z0-9_-]+"
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
"name": "entity.name.function",
|
|
206
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.mask\\sset\\s)[a-zA-Z0-9_-]+"
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
"name": "entity.name.function",
|
|
210
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.animation\\sset\\s)[a-zA-Z0-9_-]+"
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
"name": "keyword.other",
|
|
214
|
-
"match": "(?<=\\b(bl|ml|fl|ul)\\.sprite\\s(show|hide|change|move)\\s[a-zA-Z0-9_-]+\\s)[a-zA-Z0-9_-]+"
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"name": "keyword.control",
|
|
218
|
-
"match": "(?<=\\s\\|\\s.*)(global|skip-if-possible|async|extend|autonext|dangerous)(?=\\s|$)"
|
|
219
67
|
}
|
|
220
68
|
],
|
|
221
69
|
"repository": {},
|
|
Binary file
|
package/vne-language-0.0.1.vsix
DELETED
|
Binary file
|