toilscript 0.1.11 → 0.1.13
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/web.js +3 -3
- package/package.json +1 -1
- package/std/ts-plugin.cjs +152 -9
package/dist/importmap.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"imports": {
|
|
3
|
-
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
4
|
-
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
3
|
+
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.13/dist/toilscript.js",
|
|
4
|
+
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.13/dist/cli.js",
|
|
5
5
|
"binaryen": "https://cdn.jsdelivr.net/npm/binaryen@129.0.0-nightly.20260428/index.js",
|
|
6
6
|
"long": "https://cdn.jsdelivr.net/npm/long@5.3.2/index.js"
|
|
7
7
|
}
|
package/dist/web.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var ASSEMBLYSCRIPT_VERSION = "0.1.
|
|
1
|
+
var ASSEMBLYSCRIPT_VERSION = "0.1.13";
|
|
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.13/dist/toilscript.js",
|
|
5
|
+
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.13/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/ts-plugin.cjs
CHANGED
|
@@ -4,19 +4,122 @@
|
|
|
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, and treats a class/method that is only ever used
|
|
9
|
+
* via a toil decorator (`@data`, `@rest`, `@service`, `@remote`, ...) as unused.
|
|
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:
|
|
10
12
|
*
|
|
11
13
|
* TS1206 "Decorators are not valid here."
|
|
12
14
|
* TS1249 "A decorator can only decorate a method implementation, not an overload."
|
|
15
|
+
* TS2339 "Property '<m>' does not exist on type '<T>'." - but ONLY when `<m>` is a
|
|
16
|
+
* `@data`-injected member and `<T>` is a `@data` class (a typo on any other
|
|
17
|
+
* type still surfaces).
|
|
18
|
+
* TS6133 / TS6196 "'<x>' is declared but never used." - but ONLY when `<x>` is a
|
|
19
|
+
* class/method/function carrying a toil-native decorator (so the compiler
|
|
20
|
+
* uses it); an undecorated unused declaration is still greyed out.
|
|
13
21
|
*
|
|
14
|
-
* Every other diagnostic
|
|
22
|
+
* Every other diagnostic - unknown types, bad calls, missing names - passes
|
|
15
23
|
* through untouched, so real type errors are still surfaced.
|
|
16
24
|
*/
|
|
17
25
|
const DECORATOR_GRAMMAR_CODES = new Set([1206, 1249]);
|
|
26
|
+
const PROPERTY_NOT_EXIST = 2339;
|
|
27
|
+
const DECLARED_NEVER_USED = new Set([6133, 6196]);
|
|
28
|
+
|
|
29
|
+
/** Members the compiler injects into every `@data` class (instance + static). */
|
|
30
|
+
const DATA_MEMBERS = new Set([
|
|
31
|
+
'encode',
|
|
32
|
+
'encodeInto',
|
|
33
|
+
'decode',
|
|
34
|
+
'decodeFrom',
|
|
35
|
+
'toJSON',
|
|
36
|
+
'fromJSON',
|
|
37
|
+
'dataId',
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/** Toil-native decorators whose presence means the compiler uses the declaration. */
|
|
41
|
+
const TOIL_DECORATORS = new Set([
|
|
42
|
+
'data',
|
|
43
|
+
'remote',
|
|
44
|
+
'service',
|
|
45
|
+
'rest',
|
|
46
|
+
'route',
|
|
47
|
+
'get',
|
|
48
|
+
'post',
|
|
49
|
+
'put',
|
|
50
|
+
'del',
|
|
51
|
+
'patch',
|
|
52
|
+
'head',
|
|
53
|
+
'options',
|
|
54
|
+
'main',
|
|
55
|
+
'global',
|
|
56
|
+
'inline',
|
|
57
|
+
'external',
|
|
58
|
+
'unmanaged',
|
|
59
|
+
'final',
|
|
60
|
+
'operator',
|
|
61
|
+
'lazy',
|
|
62
|
+
'unsafe',
|
|
63
|
+
'builtin',
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
function init(modules) {
|
|
67
|
+
const ts = modules.typescript;
|
|
68
|
+
|
|
69
|
+
/** Deepest node spanning `pos`. */
|
|
70
|
+
function nodeAt(node, pos) {
|
|
71
|
+
if (pos < node.getStart() || pos >= node.getEnd()) return undefined;
|
|
72
|
+
let found = node;
|
|
73
|
+
node.forEachChild((child) => {
|
|
74
|
+
const inner = nodeAt(child, pos);
|
|
75
|
+
if (inner) found = inner;
|
|
76
|
+
});
|
|
77
|
+
return found;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** A decorator's bare name, for `@name` and `@name(...)`. */
|
|
81
|
+
function decoratorName(d) {
|
|
82
|
+
const e = d.expression;
|
|
83
|
+
return e && (e.text || (e.expression && e.expression.text));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function declHasDecorator(decl, names) {
|
|
87
|
+
const decorators = (ts.getDecorators ? ts.getDecorators(decl) : decl.decorators) || [];
|
|
88
|
+
return decorators.some((d) => {
|
|
89
|
+
const n = decoratorName(d);
|
|
90
|
+
return typeof names === 'string' ? n === names : !!n && names.has(n);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function declsAreDataClass(declarations) {
|
|
95
|
+
return (
|
|
96
|
+
!!declarations &&
|
|
97
|
+
declarations.some((d) => ts.isClassDeclaration(d) && declHasDecorator(d, 'data'))
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Whether `expr` is (an instance of, or the static side of) a `@data` class. */
|
|
102
|
+
function resolvesToDataClass(expr, checker) {
|
|
103
|
+
const type = checker.getTypeAtLocation(expr);
|
|
104
|
+
const typeSym = type && type.getSymbol && type.getSymbol();
|
|
105
|
+
if (typeSym && declsAreDataClass(typeSym.declarations)) return true;
|
|
106
|
+
// Static access like `Player.decode(...)`: resolve the identifier's own symbol.
|
|
107
|
+
const sym = checker.getSymbolAtLocation(expr);
|
|
108
|
+
return !!sym && declsAreDataClass(sym.declarations);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function canHoldDecorators(node) {
|
|
112
|
+
return (
|
|
113
|
+
ts.isClassDeclaration(node) ||
|
|
114
|
+
ts.isClassExpression(node) ||
|
|
115
|
+
ts.isMethodDeclaration(node) ||
|
|
116
|
+
ts.isFunctionDeclaration(node) ||
|
|
117
|
+
ts.isPropertyDeclaration(node) ||
|
|
118
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
119
|
+
ts.isSetAccessorDeclaration(node)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
18
122
|
|
|
19
|
-
function init() {
|
|
20
123
|
return {
|
|
21
124
|
create(info) {
|
|
22
125
|
const ls = info.languageService;
|
|
@@ -28,13 +131,53 @@ function init() {
|
|
|
28
131
|
proxy[key] = typeof value === 'function' ? value.bind(ls) : value;
|
|
29
132
|
}
|
|
30
133
|
|
|
31
|
-
|
|
32
|
-
|
|
134
|
+
// A TS2339 for a `@data`-injected member accessed on a `@data` class.
|
|
135
|
+
const isInjectedDataMember = (fileName, diag) => {
|
|
136
|
+
if (diag.code !== PROPERTY_NOT_EXIST || diag.start == null) return false;
|
|
137
|
+
const program = ls.getProgram();
|
|
138
|
+
const sf = program && program.getSourceFile(fileName);
|
|
139
|
+
if (!sf) return false;
|
|
140
|
+
const node = nodeAt(sf, diag.start);
|
|
141
|
+
const access =
|
|
142
|
+
node && ts.isPropertyAccessExpression(node)
|
|
143
|
+
? node
|
|
144
|
+
: node && ts.isPropertyAccessExpression(node.parent)
|
|
145
|
+
? node.parent
|
|
146
|
+
: undefined;
|
|
147
|
+
if (!access || !DATA_MEMBERS.has(access.name.text)) return false;
|
|
148
|
+
return resolvesToDataClass(access.expression, program.getTypeChecker());
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// A "declared but never used" for a class/method/function with a toil decorator.
|
|
152
|
+
const isToilDecoratedUnused = (fileName, diag) => {
|
|
153
|
+
if (!DECLARED_NEVER_USED.has(diag.code) || diag.start == null) return false;
|
|
154
|
+
const program = ls.getProgram();
|
|
155
|
+
const sf = program && program.getSourceFile(fileName);
|
|
156
|
+
if (!sf) return false;
|
|
157
|
+
const node = nodeAt(sf, diag.start);
|
|
158
|
+
if (!node) return false;
|
|
159
|
+
const decl = canHoldDecorators(node) ? node : node.parent;
|
|
160
|
+
return !!decl && canHoldDecorators(decl) && declHasDecorator(decl, TOIL_DECORATORS);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const strip = (fileName, diagnostics) =>
|
|
164
|
+
diagnostics.filter(
|
|
165
|
+
(d) =>
|
|
166
|
+
!DECORATOR_GRAMMAR_CODES.has(d.code) &&
|
|
167
|
+
!isInjectedDataMember(fileName, d) &&
|
|
168
|
+
!isToilDecoratedUnused(fileName, d),
|
|
169
|
+
);
|
|
33
170
|
|
|
34
171
|
proxy.getSemanticDiagnostics = (fileName) =>
|
|
35
|
-
strip(ls.getSemanticDiagnostics(fileName));
|
|
172
|
+
strip(fileName, ls.getSemanticDiagnostics(fileName));
|
|
36
173
|
proxy.getSyntacticDiagnostics = (fileName) =>
|
|
37
|
-
strip(ls.getSyntacticDiagnostics(fileName));
|
|
174
|
+
strip(fileName, ls.getSyntacticDiagnostics(fileName));
|
|
175
|
+
|
|
176
|
+
// The "unused" greying is a suggestion diagnostic when `noUnusedLocals` is off.
|
|
177
|
+
if (typeof ls.getSuggestionDiagnostics === 'function') {
|
|
178
|
+
proxy.getSuggestionDiagnostics = (fileName) =>
|
|
179
|
+
ls.getSuggestionDiagnostics(fileName).filter((d) => !isToilDecoratedUnused(fileName, d));
|
|
180
|
+
}
|
|
38
181
|
|
|
39
182
|
return proxy;
|
|
40
183
|
},
|