toilscript 0.1.10 → 0.1.12
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.generated.d.ts +51 -2
- package/dist/cli.js +19 -4
- package/dist/cli.js.map +2 -2
- package/dist/importmap.json +2 -2
- package/dist/toilscript.generated.d.ts +51 -2
- package/dist/toilscript.js +244 -201
- package/dist/toilscript.js.map +3 -3
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/json.ts +15 -0
- package/std/assembly/rest.ts +25 -0
- package/std/assembly/toilscript.d.ts +29 -0
- package/std/ts-plugin.cjs +84 -9
package/dist/web.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var ASSEMBLYSCRIPT_VERSION = "0.1.
|
|
1
|
+
var ASSEMBLYSCRIPT_VERSION = "0.1.12";
|
|
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.12/dist/toilscript.js",
|
|
5
|
+
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.12/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
package/std/assembly/json.ts
CHANGED
|
@@ -320,9 +320,18 @@ export class JSON {
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
/** Recursive-descent parser producing a `JSON` value tree. Internal. */
|
|
323
|
+
/**
|
|
324
|
+
* Maximum array/object nesting depth. Recursive descent costs stack per level, so an
|
|
325
|
+
* unbounded depth lets a small hostile input (e.g. `[[[[...`) overflow the stack and trap
|
|
326
|
+
* the instance. 512 is far beyond any real-world JSON yet far below the overflow point, so
|
|
327
|
+
* over-nested input fails as a normal parse error instead of crashing.
|
|
328
|
+
*/
|
|
329
|
+
const JSON_MAX_DEPTH: i32 = 512;
|
|
330
|
+
|
|
323
331
|
class Parser {
|
|
324
332
|
private src: string;
|
|
325
333
|
private pos: i32 = 0;
|
|
334
|
+
private depth: i32 = 0;
|
|
326
335
|
err: string = "";
|
|
327
336
|
|
|
328
337
|
constructor(src: string) {
|
|
@@ -468,11 +477,13 @@ class Parser {
|
|
|
468
477
|
}
|
|
469
478
|
|
|
470
479
|
private parseArray(): JSON {
|
|
480
|
+
if (++this.depth > JSON_MAX_DEPTH) return this.fail("maximum nesting depth exceeded");
|
|
471
481
|
this.pos++; // [
|
|
472
482
|
const j = JSON.arr();
|
|
473
483
|
this.skipWs();
|
|
474
484
|
if (!this.atEnd() && this.peek() == 0x5d) {
|
|
475
485
|
this.pos++;
|
|
486
|
+
this.depth--;
|
|
476
487
|
return j;
|
|
477
488
|
}
|
|
478
489
|
while (true) {
|
|
@@ -484,15 +495,18 @@ class Parser {
|
|
|
484
495
|
if (c == 0x5d) break; // ]
|
|
485
496
|
if (c != 0x2c) return this.fail("expected ',' or ']'"); // ,
|
|
486
497
|
}
|
|
498
|
+
this.depth--;
|
|
487
499
|
return j;
|
|
488
500
|
}
|
|
489
501
|
|
|
490
502
|
private parseObject(): JSON {
|
|
503
|
+
if (++this.depth > JSON_MAX_DEPTH) return this.fail("maximum nesting depth exceeded");
|
|
491
504
|
this.pos++; // {
|
|
492
505
|
const j = JSON.obj();
|
|
493
506
|
this.skipWs();
|
|
494
507
|
if (!this.atEnd() && this.peek() == 0x7d) {
|
|
495
508
|
this.pos++;
|
|
509
|
+
this.depth--;
|
|
496
510
|
return j;
|
|
497
511
|
}
|
|
498
512
|
while (true) {
|
|
@@ -510,6 +524,7 @@ class Parser {
|
|
|
510
524
|
if (c == 0x7d) break; // }
|
|
511
525
|
if (c != 0x2c) return this.fail("expected ',' or '}'"); // ,
|
|
512
526
|
}
|
|
527
|
+
this.depth--;
|
|
513
528
|
return j;
|
|
514
529
|
}
|
|
515
530
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Globals for the `@rest` / `@route` HTTP layer (no import). Top-level std exports are
|
|
2
|
+
// globalized like the other natives.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTTP method for `@route({ method: Methods.GET, ... })`. Values mirror the server runtime
|
|
6
|
+
* `Method` enum so `req.method == Methods.GET` compiles to a plain integer comparison.
|
|
7
|
+
*/
|
|
8
|
+
export enum Methods {
|
|
9
|
+
GET = 0,
|
|
10
|
+
POST = 1,
|
|
11
|
+
PUT = 2,
|
|
12
|
+
DELETE = 3,
|
|
13
|
+
PATCH = 4,
|
|
14
|
+
HEAD = 5,
|
|
15
|
+
OPTIONS = 6
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Body/response codec for `@route({ stream: DataStream.JSON, ... })`: `JSON` uses the `@data`
|
|
20
|
+
* class's `toJSON`/`fromJSON`, `Binary` uses its `encode`/`decode`.
|
|
21
|
+
*/
|
|
22
|
+
export enum DataStream {
|
|
23
|
+
JSON = 0,
|
|
24
|
+
Binary = 1
|
|
25
|
+
}
|
|
@@ -38,6 +38,35 @@ declare function remote<T>(target: Object, propertyKey: string | symbol, descrip
|
|
|
38
38
|
*/
|
|
39
39
|
declare function service(target: Function): void;
|
|
40
40
|
|
|
41
|
+
// --- HTTP layer (@rest / @route), handled natively by the compiler; typed here for editors ---
|
|
42
|
+
|
|
43
|
+
/** HTTP method for `@route({ method: Methods.GET, ... })`. */
|
|
44
|
+
declare enum Methods { GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS }
|
|
45
|
+
|
|
46
|
+
/** Body/response codec for `@route({ stream: DataStream.JSON, ... })`. */
|
|
47
|
+
declare enum DataStream { JSON, Binary }
|
|
48
|
+
|
|
49
|
+
interface RestOptions { stream?: DataStream }
|
|
50
|
+
interface RouteOptions { method: Methods; path: string; stream?: DataStream }
|
|
51
|
+
/** A legacy method decorator (the return of a `@route`/`@get`/... factory). */
|
|
52
|
+
type ToilRouteDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => void;
|
|
53
|
+
|
|
54
|
+
/** Marks a class as an HTTP controller mounted at `prefix` (default `/`). */
|
|
55
|
+
declare function rest(target: Function): void;
|
|
56
|
+
declare function rest(prefix?: string): (target: Function) => void;
|
|
57
|
+
declare function rest(options: RestOptions): (target: Function) => void;
|
|
58
|
+
|
|
59
|
+
/** Declares an HTTP route on a `@rest` method (`@route({ method, path, stream })`). */
|
|
60
|
+
declare function route(options: RouteOptions): ToilRouteDecorator;
|
|
61
|
+
/** HTTP verb shortcuts for `@route` (`@del` for DELETE, since `delete` is a reserved word). */
|
|
62
|
+
declare function get(path: string): ToilRouteDecorator;
|
|
63
|
+
declare function post(path: string): ToilRouteDecorator;
|
|
64
|
+
declare function put(path: string): ToilRouteDecorator;
|
|
65
|
+
declare function del(path: string): ToilRouteDecorator;
|
|
66
|
+
declare function patch(path: string): ToilRouteDecorator;
|
|
67
|
+
declare function head(path: string): ToilRouteDecorator;
|
|
68
|
+
declare function options(path: string): ToilRouteDecorator;
|
|
69
|
+
|
|
41
70
|
// Big integers, native globals implemented in std/assembly/bignum. The
|
|
42
71
|
// arithmetic/bitwise/comparison operators
|
|
43
72
|
// (+ - * / % & | ^ << >> == != < > <= >=) are operator overloads resolved by
|
package/std/ts-plugin.cjs
CHANGED
|
@@ -4,19 +4,76 @@
|
|
|
4
4
|
* Stock TypeScript has no grammar for toil-native decorators applied to
|
|
5
5
|
* top-level functions and globals (`@main`, `@inline`, `@unmanaged`, ...), so
|
|
6
6
|
* the editor's language service flags them as errors even though the toilscript
|
|
7
|
-
* compiler
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* compiler handles them correctly. It also can't see the members the compiler
|
|
8
|
+
* injects into a `@data` class (`encode`/`decode`/`toJSON`/...). This plugin runs
|
|
9
|
+
* only inside the editor's language service (VS Code, WebStorm, etc. - never
|
|
10
|
+
* `tsc`/compiler builds) and removes exactly those false positives:
|
|
10
11
|
*
|
|
11
12
|
* TS1206 "Decorators are not valid here."
|
|
12
13
|
* TS1249 "A decorator can only decorate a method implementation, not an overload."
|
|
14
|
+
* TS2339 "Property '<m>' does not exist on type '<T>'." - but ONLY when `<m>` is a
|
|
15
|
+
* `@data`-injected member and `<T>` is a `@data` class (so a typo on any
|
|
16
|
+
* other type still surfaces).
|
|
13
17
|
*
|
|
14
|
-
* Every other diagnostic
|
|
18
|
+
* Every other diagnostic - unknown types, bad calls, missing names - passes
|
|
15
19
|
* through untouched, so real type errors are still surfaced.
|
|
16
20
|
*/
|
|
17
21
|
const DECORATOR_GRAMMAR_CODES = new Set([1206, 1249]);
|
|
22
|
+
const PROPERTY_NOT_EXIST = 2339;
|
|
23
|
+
|
|
24
|
+
/** Members the compiler injects into every `@data` class (instance + static). */
|
|
25
|
+
const DATA_MEMBERS = new Set([
|
|
26
|
+
'encode',
|
|
27
|
+
'encodeInto',
|
|
28
|
+
'decode',
|
|
29
|
+
'decodeFrom',
|
|
30
|
+
'toJSON',
|
|
31
|
+
'fromJSON',
|
|
32
|
+
'dataId',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
function init(modules) {
|
|
36
|
+
const ts = modules.typescript;
|
|
37
|
+
|
|
38
|
+
/** Deepest node spanning `pos`. */
|
|
39
|
+
function nodeAt(node, pos) {
|
|
40
|
+
if (pos < node.getStart() || pos >= node.getEnd()) return undefined;
|
|
41
|
+
let found = node;
|
|
42
|
+
node.forEachChild((child) => {
|
|
43
|
+
const inner = nodeAt(child, pos);
|
|
44
|
+
if (inner) found = inner;
|
|
45
|
+
});
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Whether a class declaration carries the `@data` decorator (bare or called). */
|
|
50
|
+
function hasDataDecorator(decl) {
|
|
51
|
+
const decorators = (ts.getDecorators ? ts.getDecorators(decl) : decl.decorators) || [];
|
|
52
|
+
for (const d of decorators) {
|
|
53
|
+
const e = d.expression;
|
|
54
|
+
const name = e && (e.text || (e.expression && e.expression.text));
|
|
55
|
+
if (name === 'data') return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function declsAreDataClass(declarations) {
|
|
61
|
+
return (
|
|
62
|
+
!!declarations &&
|
|
63
|
+
declarations.some((d) => ts.isClassDeclaration(d) && hasDataDecorator(d))
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Whether `expr` is (an instance of, or the static side of) a `@data` class. */
|
|
68
|
+
function resolvesToDataClass(expr, checker) {
|
|
69
|
+
const type = checker.getTypeAtLocation(expr);
|
|
70
|
+
const typeSym = type && type.getSymbol && type.getSymbol();
|
|
71
|
+
if (typeSym && declsAreDataClass(typeSym.declarations)) return true;
|
|
72
|
+
// Static access like `Player.decode(...)`: resolve the identifier's own symbol.
|
|
73
|
+
const sym = checker.getSymbolAtLocation(expr);
|
|
74
|
+
return !!sym && declsAreDataClass(sym.declarations);
|
|
75
|
+
}
|
|
18
76
|
|
|
19
|
-
function init() {
|
|
20
77
|
return {
|
|
21
78
|
create(info) {
|
|
22
79
|
const ls = info.languageService;
|
|
@@ -28,13 +85,31 @@ function init() {
|
|
|
28
85
|
proxy[key] = typeof value === 'function' ? value.bind(ls) : value;
|
|
29
86
|
}
|
|
30
87
|
|
|
31
|
-
const
|
|
32
|
-
|
|
88
|
+
const isInjectedDataMember = (fileName, diag) => {
|
|
89
|
+
if (diag.code !== PROPERTY_NOT_EXIST || diag.start == null) return false;
|
|
90
|
+
const program = ls.getProgram();
|
|
91
|
+
const sf = program && program.getSourceFile(fileName);
|
|
92
|
+
if (!sf) return false;
|
|
93
|
+
const node = nodeAt(sf, diag.start);
|
|
94
|
+
const access =
|
|
95
|
+
node && ts.isPropertyAccessExpression(node)
|
|
96
|
+
? node
|
|
97
|
+
: node && ts.isPropertyAccessExpression(node.parent)
|
|
98
|
+
? node.parent
|
|
99
|
+
: undefined;
|
|
100
|
+
if (!access || !DATA_MEMBERS.has(access.name.text)) return false;
|
|
101
|
+
return resolvesToDataClass(access.expression, program.getTypeChecker());
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const strip = (fileName, diagnostics) =>
|
|
105
|
+
diagnostics.filter(
|
|
106
|
+
(d) => !DECORATOR_GRAMMAR_CODES.has(d.code) && !isInjectedDataMember(fileName, d),
|
|
107
|
+
);
|
|
33
108
|
|
|
34
109
|
proxy.getSemanticDiagnostics = (fileName) =>
|
|
35
|
-
strip(ls.getSemanticDiagnostics(fileName));
|
|
110
|
+
strip(fileName, ls.getSemanticDiagnostics(fileName));
|
|
36
111
|
proxy.getSyntacticDiagnostics = (fileName) =>
|
|
37
|
-
strip(ls.getSyntacticDiagnostics(fileName));
|
|
112
|
+
strip(fileName, ls.getSyntacticDiagnostics(fileName));
|
|
38
113
|
|
|
39
114
|
return proxy;
|
|
40
115
|
},
|