toilscript 0.1.13 → 0.1.15
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/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/importmap.json +2 -2
- package/dist/toilscript.js +4 -4
- package/dist/toilscript.js.map +2 -2
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/toilscript.d.ts +51 -0
- package/std/ts-plugin.cjs +81 -23
package/dist/web.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var ASSEMBLYSCRIPT_VERSION = "0.1.
|
|
1
|
+
var ASSEMBLYSCRIPT_VERSION = "0.1.15";
|
|
2
2
|
var ASSEMBLYSCRIPT_IMPORTMAP = {
|
|
3
3
|
"imports": {
|
|
4
|
-
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
5
|
-
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
4
|
+
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.15/dist/toilscript.js",
|
|
5
|
+
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.15/dist/cli.js",
|
|
6
6
|
"binaryen": "https://cdn.jsdelivr.net/npm/binaryen@129.0.0-nightly.20260428/index.js",
|
|
7
7
|
"long": "https://cdn.jsdelivr.net/npm/long@5.3.2/index.js"
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -323,3 +323,54 @@ declare class i256 {
|
|
|
323
323
|
isNeg(): bool;
|
|
324
324
|
isZero(): bool;
|
|
325
325
|
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* The dynamic JSON value tree. A `@data` class's `toJSON()` returns one of these, and
|
|
329
|
+
* `JSON.parse(...)` produces one. Globalized by std/assembly/json, so it needs no import.
|
|
330
|
+
*/
|
|
331
|
+
declare class JSON {
|
|
332
|
+
/** A JSON null. */
|
|
333
|
+
static nul(): JSON;
|
|
334
|
+
/** An empty JSON object, build it with `.set(key, value)`. */
|
|
335
|
+
static obj(): JSON;
|
|
336
|
+
/** An empty JSON array, build it with `.push(value)`. */
|
|
337
|
+
static arr(): JSON;
|
|
338
|
+
/** Wrap a scalar/string/bool/array as a JSON value. */
|
|
339
|
+
static of<T>(value: T): JSON;
|
|
340
|
+
/** Parse JSON text into a value tree (returns an error value on malformed input). */
|
|
341
|
+
static parse(text: string): JSON;
|
|
342
|
+
/** Serialize a scalar/string/bool/array value to a JSON string. */
|
|
343
|
+
static stringify<T>(value: T): string;
|
|
344
|
+
|
|
345
|
+
/** Append a value to a JSON array; returns `this` for chaining. */
|
|
346
|
+
push(value: JSON): JSON;
|
|
347
|
+
/** Set a key on a JSON object; returns `this` for chaining. */
|
|
348
|
+
set(key: string, value: JSON): JSON;
|
|
349
|
+
|
|
350
|
+
isNull(): bool;
|
|
351
|
+
isBool(): bool;
|
|
352
|
+
isNumber(): bool;
|
|
353
|
+
isString(): bool;
|
|
354
|
+
isArray(): bool;
|
|
355
|
+
isObject(): bool;
|
|
356
|
+
|
|
357
|
+
asBool(): bool;
|
|
358
|
+
asF64(): f64;
|
|
359
|
+
asI64(): i64;
|
|
360
|
+
asU64(): u64;
|
|
361
|
+
asString(): string;
|
|
362
|
+
|
|
363
|
+
/** Element count of an array (or 0). */
|
|
364
|
+
length(): i32;
|
|
365
|
+
/** Element at `index` of an array. */
|
|
366
|
+
at(index: i32): JSON;
|
|
367
|
+
/** Whether an object has `key`. */
|
|
368
|
+
has(key: string): bool;
|
|
369
|
+
/** Value for `key` on an object. */
|
|
370
|
+
get(key: string): JSON;
|
|
371
|
+
/** The keys of an object. */
|
|
372
|
+
objectKeys(): Array<string>;
|
|
373
|
+
|
|
374
|
+
/** Serialize this value tree to a JSON string. */
|
|
375
|
+
toString(): string;
|
|
376
|
+
}
|
package/std/ts-plugin.cjs
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ToilScript TypeScript Language Service plugin.
|
|
3
3
|
*
|
|
4
|
-
* Stock TypeScript
|
|
5
|
-
* top-level functions
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* This plugin runs only inside the editor's language service (VS Code, WebStorm,
|
|
11
|
-
* etc. - never `tsc`/compiler builds) and removes exactly those false positives:
|
|
4
|
+
* Stock TypeScript can't see what the toilscript compiler does to a source file:
|
|
5
|
+
* the native decorators on top-level functions (`@main`, `@inline`, ...), the
|
|
6
|
+
* members it injects into a `@data` class (`encode`/`decode`/`toJSON`/...), or the
|
|
7
|
+
* fact that a class used only via a toil decorator is actually used. This plugin
|
|
8
|
+
* runs only inside the editor's language service (VS Code, WebStorm, etc. - never
|
|
9
|
+
* `tsc`/compiler builds) and bridges that gap:
|
|
12
10
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* uses it); an undecorated unused declaration is still greyed out.
|
|
11
|
+
* 1. Declaration-merges TYPED members onto each `@data` class (so `value.toJSON()`
|
|
12
|
+
* is `JSON`, `Type.decode(bytes)` is the class, etc.) by appending ambient decls
|
|
13
|
+
* to the file the editor sees. Diagnostics in that appended region are hidden.
|
|
14
|
+
* 2. As a fallback (if 1 doesn't apply), still removes the false positives:
|
|
15
|
+
* TS1206 / TS1249 decorator grammar
|
|
16
|
+
* TS2339 a `@data`-injected member accessed on a `@data` class
|
|
17
|
+
* TS6133 / TS6196 a toil-decorated class/method reported as unused
|
|
21
18
|
*
|
|
22
|
-
* Every other diagnostic
|
|
23
|
-
* through untouched, so real type errors are still surfaced.
|
|
19
|
+
* Every other diagnostic passes through untouched, so real errors still surface.
|
|
24
20
|
*/
|
|
25
21
|
const DECORATOR_GRAMMAR_CODES = new Set([1206, 1249]);
|
|
26
22
|
const PROPERTY_NOT_EXIST = 2339;
|
|
@@ -98,12 +94,10 @@ function init(modules) {
|
|
|
98
94
|
);
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
/** Whether `expr` is (an instance of, or the static side of) a `@data` class. */
|
|
102
97
|
function resolvesToDataClass(expr, checker) {
|
|
103
98
|
const type = checker.getTypeAtLocation(expr);
|
|
104
99
|
const typeSym = type && type.getSymbol && type.getSymbol();
|
|
105
100
|
if (typeSym && declsAreDataClass(typeSym.declarations)) return true;
|
|
106
|
-
// Static access like `Player.decode(...)`: resolve the identifier's own symbol.
|
|
107
101
|
const sym = checker.getSymbolAtLocation(expr);
|
|
108
102
|
return !!sym && declsAreDataClass(sym.declarations);
|
|
109
103
|
}
|
|
@@ -120,9 +114,66 @@ function init(modules) {
|
|
|
120
114
|
);
|
|
121
115
|
}
|
|
122
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Ambient declarations to append so the editor types each `@data` class's injected
|
|
119
|
+
* codec members. Returns "" when the file declares no `@data` class. Uses only
|
|
120
|
+
* editor-visible globals (`Uint8Array`, `JSON`, `u32`), so the appended block is
|
|
121
|
+
* itself error-free; any diagnostics there are filtered anyway.
|
|
122
|
+
*/
|
|
123
|
+
function dataAugmentation(text) {
|
|
124
|
+
if (text.indexOf('@data') < 0) return '';
|
|
125
|
+
let sf;
|
|
126
|
+
try {
|
|
127
|
+
sf = ts.createSourceFile('__toil_aug__.ts', text, ts.ScriptTarget.Latest, true);
|
|
128
|
+
} catch {
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
131
|
+
let out = '';
|
|
132
|
+
sf.forEachChild((node) => {
|
|
133
|
+
if (ts.isClassDeclaration(node) && node.name && declHasDecorator(node, 'data')) {
|
|
134
|
+
const n = node.name.text;
|
|
135
|
+
out +=
|
|
136
|
+
`\n// toilscript: editor types for the compiler-injected @data ${n} codec\n` +
|
|
137
|
+
`interface ${n} { encode(): Uint8Array; toJSON(): JSON; }\n` +
|
|
138
|
+
`declare namespace ${n} { function decode(buf: Uint8Array): ${n}; function fromJSON(v: JSON): ${n}; function dataId(): u32; }\n`;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
123
144
|
return {
|
|
124
145
|
create(info) {
|
|
125
146
|
const ls = info.languageService;
|
|
147
|
+
const host = info.languageServiceHost;
|
|
148
|
+
|
|
149
|
+
// Original text length per augmented file, so diagnostics in the appended region drop.
|
|
150
|
+
const originalLength = new Map();
|
|
151
|
+
|
|
152
|
+
// Inject the typed @data members into the editor's view of each source file.
|
|
153
|
+
if (typeof host.getScriptSnapshot === 'function' && typeof host.getScriptVersion === 'function') {
|
|
154
|
+
const origSnapshot = host.getScriptSnapshot.bind(host);
|
|
155
|
+
const origVersion = host.getScriptVersion.bind(host);
|
|
156
|
+
host.getScriptSnapshot = (fileName) => {
|
|
157
|
+
const snap = origSnapshot(fileName);
|
|
158
|
+
if (!snap) return snap;
|
|
159
|
+
let aug = '';
|
|
160
|
+
try {
|
|
161
|
+
aug = dataAugmentation(snap.getText(0, snap.getLength()));
|
|
162
|
+
} catch {
|
|
163
|
+
aug = '';
|
|
164
|
+
}
|
|
165
|
+
if (!aug) {
|
|
166
|
+
originalLength.delete(fileName);
|
|
167
|
+
return snap;
|
|
168
|
+
}
|
|
169
|
+
const text = snap.getText(0, snap.getLength());
|
|
170
|
+
originalLength.set(fileName, text.length);
|
|
171
|
+
return ts.ScriptSnapshot.fromString(text + aug);
|
|
172
|
+
};
|
|
173
|
+
// A stable suffix so the service re-reads once and picks up the augmentation; it
|
|
174
|
+
// still changes whenever the underlying file changes.
|
|
175
|
+
host.getScriptVersion = (fileName) => origVersion(fileName) + ':toil-data';
|
|
176
|
+
}
|
|
126
177
|
|
|
127
178
|
// Proxy the language service, forwarding everything to the real one.
|
|
128
179
|
const proxy = Object.create(null);
|
|
@@ -131,7 +182,12 @@ function init(modules) {
|
|
|
131
182
|
proxy[key] = typeof value === 'function' ? value.bind(ls) : value;
|
|
132
183
|
}
|
|
133
184
|
|
|
134
|
-
|
|
185
|
+
const inAugmentedRegion = (fileName, diag) => {
|
|
186
|
+
const len = originalLength.get(fileName);
|
|
187
|
+
return len != null && diag.start != null && diag.start >= len;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Fallback: a TS2339 for a `@data`-injected member on a `@data` class.
|
|
135
191
|
const isInjectedDataMember = (fileName, diag) => {
|
|
136
192
|
if (diag.code !== PROPERTY_NOT_EXIST || diag.start == null) return false;
|
|
137
193
|
const program = ls.getProgram();
|
|
@@ -164,6 +220,7 @@ function init(modules) {
|
|
|
164
220
|
diagnostics.filter(
|
|
165
221
|
(d) =>
|
|
166
222
|
!DECORATOR_GRAMMAR_CODES.has(d.code) &&
|
|
223
|
+
!inAugmentedRegion(fileName, d) &&
|
|
167
224
|
!isInjectedDataMember(fileName, d) &&
|
|
168
225
|
!isToilDecoratedUnused(fileName, d),
|
|
169
226
|
);
|
|
@@ -173,10 +230,11 @@ function init(modules) {
|
|
|
173
230
|
proxy.getSyntacticDiagnostics = (fileName) =>
|
|
174
231
|
strip(fileName, ls.getSyntacticDiagnostics(fileName));
|
|
175
232
|
|
|
176
|
-
// The "unused" greying is a suggestion diagnostic when `noUnusedLocals` is off.
|
|
177
233
|
if (typeof ls.getSuggestionDiagnostics === 'function') {
|
|
178
234
|
proxy.getSuggestionDiagnostics = (fileName) =>
|
|
179
|
-
ls
|
|
235
|
+
ls
|
|
236
|
+
.getSuggestionDiagnostics(fileName)
|
|
237
|
+
.filter((d) => !inAugmentedRegion(fileName, d) && !isToilDecoratedUnused(fileName, d));
|
|
180
238
|
}
|
|
181
239
|
|
|
182
240
|
return proxy;
|