@elaraai/tsserver-plugin-east 1.0.28 → 1.0.30
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/index.cjs +860 -100
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -49,6 +49,37 @@ function isBlockBuilderType(type) {
|
|
|
49
49
|
const name = type.aliasSymbol?.name ?? type.symbol?.name;
|
|
50
50
|
return name === "BlockBuilder";
|
|
51
51
|
}
|
|
52
|
+
function someTypeName(type, match) {
|
|
53
|
+
const seen = /* @__PURE__ */ new Set();
|
|
54
|
+
const stack = [type];
|
|
55
|
+
while (stack.length > 0) {
|
|
56
|
+
const current = stack.pop();
|
|
57
|
+
if (current === void 0 || seen.has(current))
|
|
58
|
+
continue;
|
|
59
|
+
seen.add(current);
|
|
60
|
+
const name = current.aliasSymbol?.name ?? current.symbol?.name;
|
|
61
|
+
if (name !== void 0 && match(name))
|
|
62
|
+
return true;
|
|
63
|
+
if (current.isUnionOrIntersection())
|
|
64
|
+
stack.push(...current.types);
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function isEastPlatformDefinitionType(type) {
|
|
69
|
+
return someTypeName(type, (name) => name.endsWith("PlatformDefinition"));
|
|
70
|
+
}
|
|
71
|
+
var E3_DEFINITION_NAMES = /* @__PURE__ */ new Set([
|
|
72
|
+
"TaskDef",
|
|
73
|
+
"DatasetDef",
|
|
74
|
+
"DataTreeDef",
|
|
75
|
+
"FunctionDef",
|
|
76
|
+
"MutationDef",
|
|
77
|
+
"RecordDef",
|
|
78
|
+
"PackageDef"
|
|
79
|
+
]);
|
|
80
|
+
function isEastDefinitionType(type) {
|
|
81
|
+
return someTypeName(type, (name) => E3_DEFINITION_NAMES.has(name) || name.endsWith("PlatformDefinition"));
|
|
82
|
+
}
|
|
52
83
|
|
|
53
84
|
// ../east-diagnostics/dist/src/block-builder.js
|
|
54
85
|
function matchBlockBuilderCall(node, ctx) {
|
|
@@ -174,6 +205,124 @@ var preferExplicitEastType = {
|
|
|
174
205
|
}
|
|
175
206
|
};
|
|
176
207
|
|
|
208
|
+
// ../east-diagnostics/dist/src/east-source.js
|
|
209
|
+
var import_node_fs = require("node:fs");
|
|
210
|
+
var import_node_path = require("node:path");
|
|
211
|
+
function importDeclarationOf(sym, t) {
|
|
212
|
+
for (const d of sym?.declarations ?? []) {
|
|
213
|
+
let n = d;
|
|
214
|
+
if (t.isImportSpecifier(n))
|
|
215
|
+
n = n.parent.parent.parent;
|
|
216
|
+
else if (t.isNamespaceImport(n))
|
|
217
|
+
n = n.parent.parent;
|
|
218
|
+
else if (t.isImportClause(n))
|
|
219
|
+
n = n.parent;
|
|
220
|
+
else
|
|
221
|
+
continue;
|
|
222
|
+
if (t.isImportDeclaration(n))
|
|
223
|
+
return n;
|
|
224
|
+
}
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
function resolvesToEastImport(id, checker, t) {
|
|
228
|
+
const imp = importDeclarationOf(checker.getSymbolAtLocation(id), t);
|
|
229
|
+
return imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text.startsWith("@elaraai/");
|
|
230
|
+
}
|
|
231
|
+
var importsCache = /* @__PURE__ */ new WeakMap();
|
|
232
|
+
function importsEastPackage(sf, t) {
|
|
233
|
+
const cached = importsCache.get(sf);
|
|
234
|
+
if (cached !== void 0)
|
|
235
|
+
return cached;
|
|
236
|
+
let found = false;
|
|
237
|
+
for (const stmt of sf.statements) {
|
|
238
|
+
if (!t.isImportDeclaration(stmt) && !t.isExportDeclaration(stmt))
|
|
239
|
+
continue;
|
|
240
|
+
const spec = stmt.moduleSpecifier;
|
|
241
|
+
if (spec !== void 0 && t.isStringLiteral(spec) && spec.text.startsWith("@elaraai/")) {
|
|
242
|
+
found = true;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
importsCache.set(sf, found);
|
|
247
|
+
return found;
|
|
248
|
+
}
|
|
249
|
+
var declaresCache = /* @__PURE__ */ new WeakMap();
|
|
250
|
+
var E3_DECLARATION_MEMBERS = /* @__PURE__ */ new Set([
|
|
251
|
+
"input",
|
|
252
|
+
"task",
|
|
253
|
+
"customTask",
|
|
254
|
+
"function",
|
|
255
|
+
"record",
|
|
256
|
+
"mutation",
|
|
257
|
+
"package",
|
|
258
|
+
"export"
|
|
259
|
+
]);
|
|
260
|
+
function declaresEastProgram(sf, checker, t) {
|
|
261
|
+
const cached = declaresCache.get(sf);
|
|
262
|
+
if (cached !== void 0)
|
|
263
|
+
return cached;
|
|
264
|
+
let found = false;
|
|
265
|
+
const visit = (n) => {
|
|
266
|
+
if (found)
|
|
267
|
+
return;
|
|
268
|
+
if (t.isCallExpression(n)) {
|
|
269
|
+
const callee = n.expression;
|
|
270
|
+
if (t.isPropertyAccessExpression(callee) && t.isIdentifier(callee.expression)) {
|
|
271
|
+
const root = callee.expression;
|
|
272
|
+
if (root.text === "East" && resolvesToEastImport(root, checker, t)) {
|
|
273
|
+
found = true;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (E3_DECLARATION_MEMBERS.has(callee.name.text)) {
|
|
277
|
+
const imp = importDeclarationOf(checker.getSymbolAtLocation(root), t);
|
|
278
|
+
if (imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text === "@elaraai/e3") {
|
|
279
|
+
found = true;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
} else if (t.isIdentifier(callee) && callee.text === "ui" && resolvesToEastImport(callee, checker, t)) {
|
|
284
|
+
found = true;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
t.forEachChild(n, visit);
|
|
289
|
+
};
|
|
290
|
+
visit(sf);
|
|
291
|
+
declaresCache.set(sf, found);
|
|
292
|
+
return found;
|
|
293
|
+
}
|
|
294
|
+
var pkgDirCache = /* @__PURE__ */ new Map();
|
|
295
|
+
function packageDirOf(p) {
|
|
296
|
+
const start = (0, import_node_path.dirname)((0, import_node_path.resolve)(p));
|
|
297
|
+
if (pkgDirCache.has(start))
|
|
298
|
+
return pkgDirCache.get(start);
|
|
299
|
+
let dir = start;
|
|
300
|
+
let result;
|
|
301
|
+
for (; ; ) {
|
|
302
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "package.json"))) {
|
|
303
|
+
result = dir;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
const parent = (0, import_node_path.dirname)(dir);
|
|
307
|
+
if (parent === dir)
|
|
308
|
+
break;
|
|
309
|
+
dir = parent;
|
|
310
|
+
}
|
|
311
|
+
pkgDirCache.set(start, result);
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
function resolvesWithinOwnPackage(sourceFileName, specifierText) {
|
|
315
|
+
try {
|
|
316
|
+
const own = packageDirOf(sourceFileName);
|
|
317
|
+
if (own === void 0)
|
|
318
|
+
return false;
|
|
319
|
+
const targetAbs = (0, import_node_path.resolve)((0, import_node_path.dirname)(sourceFileName), specifierText);
|
|
320
|
+
return packageDirOf(targetAbs) === own;
|
|
321
|
+
} catch {
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
177
326
|
// ../east-diagnostics/dist/src/rules/prefer-some-none.js
|
|
178
327
|
var NAME3 = "prefer-some-none";
|
|
179
328
|
var CODE3 = 990003;
|
|
@@ -188,6 +337,8 @@ var preferSomeNone = {
|
|
|
188
337
|
const callee = node.expression;
|
|
189
338
|
if (!t.isIdentifier(callee) || callee.text !== "variant")
|
|
190
339
|
return;
|
|
340
|
+
if (!resolvesToEastImport(callee, ctx.checker, t))
|
|
341
|
+
return;
|
|
191
342
|
const first = node.arguments[0];
|
|
192
343
|
if (first === void 0 || !t.isStringLiteralLike(first))
|
|
193
344
|
return;
|
|
@@ -309,6 +460,23 @@ function enclosingBlockScope(node, ctx) {
|
|
|
309
460
|
function insideBlockScope(node, ctx) {
|
|
310
461
|
return enclosingBlockScope(node, ctx) !== void 0;
|
|
311
462
|
}
|
|
463
|
+
function insideReactive(node, t) {
|
|
464
|
+
let cur = node.parent;
|
|
465
|
+
while (cur !== void 0) {
|
|
466
|
+
if (t.isJsxElement(cur) && cur.openingElement.tagName.getText().endsWith("Reactive"))
|
|
467
|
+
return true;
|
|
468
|
+
if (t.isJsxSelfClosingElement(cur) && cur.tagName.getText().endsWith("Reactive"))
|
|
469
|
+
return true;
|
|
470
|
+
if (t.isCallExpression(cur)) {
|
|
471
|
+
const callee = cur.expression;
|
|
472
|
+
if (t.isPropertyAccessExpression(callee) && t.isIdentifier(callee.expression) && callee.expression.text === "Reactive") {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
cur = cur.parent;
|
|
477
|
+
}
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
312
480
|
|
|
313
481
|
// ../east-diagnostics/dist/src/rules/prefer-let-const-over-east-value.js
|
|
314
482
|
var NAME6 = "prefer-let-const-over-east-value";
|
|
@@ -358,59 +526,6 @@ var preferLetConstOverEastValue = {
|
|
|
358
526
|
}
|
|
359
527
|
};
|
|
360
528
|
|
|
361
|
-
// ../east-diagnostics/dist/src/east-source.js
|
|
362
|
-
var import_node_fs = require("node:fs");
|
|
363
|
-
var import_node_path = require("node:path");
|
|
364
|
-
var importsCache = /* @__PURE__ */ new WeakMap();
|
|
365
|
-
function importsEastPackage(sf, t) {
|
|
366
|
-
const cached = importsCache.get(sf);
|
|
367
|
-
if (cached !== void 0)
|
|
368
|
-
return cached;
|
|
369
|
-
let found = false;
|
|
370
|
-
for (const stmt of sf.statements) {
|
|
371
|
-
if (!t.isImportDeclaration(stmt) && !t.isExportDeclaration(stmt))
|
|
372
|
-
continue;
|
|
373
|
-
const spec = stmt.moduleSpecifier;
|
|
374
|
-
if (spec !== void 0 && t.isStringLiteral(spec) && spec.text.startsWith("@elaraai/")) {
|
|
375
|
-
found = true;
|
|
376
|
-
break;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
importsCache.set(sf, found);
|
|
380
|
-
return found;
|
|
381
|
-
}
|
|
382
|
-
var pkgDirCache = /* @__PURE__ */ new Map();
|
|
383
|
-
function packageDirOf(p) {
|
|
384
|
-
const start = (0, import_node_path.dirname)((0, import_node_path.resolve)(p));
|
|
385
|
-
if (pkgDirCache.has(start))
|
|
386
|
-
return pkgDirCache.get(start);
|
|
387
|
-
let dir = start;
|
|
388
|
-
let result;
|
|
389
|
-
for (; ; ) {
|
|
390
|
-
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "package.json"))) {
|
|
391
|
-
result = dir;
|
|
392
|
-
break;
|
|
393
|
-
}
|
|
394
|
-
const parent = (0, import_node_path.dirname)(dir);
|
|
395
|
-
if (parent === dir)
|
|
396
|
-
break;
|
|
397
|
-
dir = parent;
|
|
398
|
-
}
|
|
399
|
-
pkgDirCache.set(start, result);
|
|
400
|
-
return result;
|
|
401
|
-
}
|
|
402
|
-
function resolvesWithinOwnPackage(sourceFileName, specifierText) {
|
|
403
|
-
try {
|
|
404
|
-
const own = packageDirOf(sourceFileName);
|
|
405
|
-
if (own === void 0)
|
|
406
|
-
return false;
|
|
407
|
-
const targetAbs = (0, import_node_path.resolve)((0, import_node_path.dirname)(sourceFileName), specifierText);
|
|
408
|
-
return packageDirOf(targetAbs) === own;
|
|
409
|
-
} catch {
|
|
410
|
-
return true;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
529
|
// ../east-diagnostics/dist/src/rules/no-relative-src-import.js
|
|
415
530
|
var NAME7 = "no-relative-src-import";
|
|
416
531
|
var CODE7 = 990007;
|
|
@@ -815,6 +930,8 @@ var noCompileTimeDataInjection = {
|
|
|
815
930
|
const t = ctx.ts;
|
|
816
931
|
if (!importsEastPackage(ctx.sourceFile, t))
|
|
817
932
|
return;
|
|
933
|
+
if (!declaresEastProgram(ctx.sourceFile, ctx.checker, t))
|
|
934
|
+
return;
|
|
818
935
|
if (t.isImportDeclaration(node)) {
|
|
819
936
|
const spec = node.moduleSpecifier;
|
|
820
937
|
if (t.isStringLiteral(spec) && FS_MODULES.has(spec.text)) {
|
|
@@ -850,27 +967,6 @@ function fire2(ctx, target, messageText) {
|
|
|
850
967
|
const start = target.getStart(sf);
|
|
851
968
|
ctx.report({ ruleName: NAME14, code: CODE14, start, length: target.getEnd() - start, messageText, category: "warning" });
|
|
852
969
|
}
|
|
853
|
-
function importDeclOfSymbol(sym, t) {
|
|
854
|
-
for (const d of sym?.declarations ?? []) {
|
|
855
|
-
let n = d;
|
|
856
|
-
if (t.isImportSpecifier(n))
|
|
857
|
-
n = n.parent.parent.parent;
|
|
858
|
-
else if (t.isNamespaceImport(n))
|
|
859
|
-
n = n.parent.parent;
|
|
860
|
-
else if (t.isImportClause(n))
|
|
861
|
-
n = n.parent;
|
|
862
|
-
else
|
|
863
|
-
continue;
|
|
864
|
-
if (t.isImportDeclaration(n))
|
|
865
|
-
return n;
|
|
866
|
-
}
|
|
867
|
-
return void 0;
|
|
868
|
-
}
|
|
869
|
-
function resolvesToEastImport(id, ctx) {
|
|
870
|
-
const t = ctx.ts;
|
|
871
|
-
const imp = importDeclOfSymbol(ctx.checker.getSymbolAtLocation(id), t);
|
|
872
|
-
return imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text.startsWith("@elaraai/");
|
|
873
|
-
}
|
|
874
970
|
function isE3InputCall(node, ctx) {
|
|
875
971
|
const t = ctx.ts;
|
|
876
972
|
const callee = node.expression;
|
|
@@ -878,7 +974,7 @@ function isE3InputCall(node, ctx) {
|
|
|
878
974
|
return false;
|
|
879
975
|
if (!t.isIdentifier(callee.expression))
|
|
880
976
|
return false;
|
|
881
|
-
const imp =
|
|
977
|
+
const imp = importDeclarationOf(ctx.checker.getSymbolAtLocation(callee.expression), t);
|
|
882
978
|
return imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text === "@elaraai/e3";
|
|
883
979
|
}
|
|
884
980
|
function rootIdentifier(node, t) {
|
|
@@ -918,13 +1014,13 @@ function embedsHostComputation(expr, ctx) {
|
|
|
918
1014
|
return;
|
|
919
1015
|
if (t.isCallExpression(n)) {
|
|
920
1016
|
const root = rootIdentifier(n.expression, t);
|
|
921
|
-
if (root === void 0 || !resolvesToEastImport(root, ctx)) {
|
|
1017
|
+
if (root === void 0 || !resolvesToEastImport(root, ctx.checker, t)) {
|
|
922
1018
|
bad = true;
|
|
923
1019
|
return;
|
|
924
1020
|
}
|
|
925
1021
|
} else if (t.isNewExpression(n)) {
|
|
926
1022
|
const ctor = n.expression;
|
|
927
|
-
const ok = t.isIdentifier(ctor) && (VALUE_CTORS.has(ctor.text) || resolvesToEastImport(ctor, ctx));
|
|
1023
|
+
const ok = t.isIdentifier(ctor) && (VALUE_CTORS.has(ctor.text) || resolvesToEastImport(ctor, ctx.checker, t));
|
|
928
1024
|
if (!ok) {
|
|
929
1025
|
bad = true;
|
|
930
1026
|
return;
|
|
@@ -1014,25 +1110,6 @@ var noCompileTimeSeedData = {
|
|
|
1014
1110
|
// ../east-diagnostics/dist/src/rules/no-host-in-east-block.js
|
|
1015
1111
|
var NAME15 = "no-host-in-east-block";
|
|
1016
1112
|
var CODE15 = 990020;
|
|
1017
|
-
function resolvesToEastImport2(id, ctx) {
|
|
1018
|
-
const t = ctx.ts;
|
|
1019
|
-
const sym = ctx.checker.getSymbolAtLocation(id);
|
|
1020
|
-
for (const d of sym?.declarations ?? []) {
|
|
1021
|
-
let n = d;
|
|
1022
|
-
if (t.isImportSpecifier(n))
|
|
1023
|
-
n = n.parent.parent.parent;
|
|
1024
|
-
else if (t.isNamespaceImport(n))
|
|
1025
|
-
n = n.parent.parent;
|
|
1026
|
-
else if (t.isImportClause(n))
|
|
1027
|
-
n = n.parent;
|
|
1028
|
-
else
|
|
1029
|
-
continue;
|
|
1030
|
-
if (t.isImportDeclaration(n) && t.isStringLiteral(n.moduleSpecifier) && n.moduleSpecifier.text.startsWith("@elaraai/")) {
|
|
1031
|
-
return true;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
return false;
|
|
1035
|
-
}
|
|
1036
1113
|
function resolvesToInBlockEastBinding(id, ctx) {
|
|
1037
1114
|
const t = ctx.ts;
|
|
1038
1115
|
const sym = ctx.checker.getSymbolAtLocation(id);
|
|
@@ -1063,21 +1140,115 @@ function isEastCall(call, ctx) {
|
|
|
1063
1140
|
return true;
|
|
1064
1141
|
if (t.isPropertyAccessExpression(f) && isEastExprType(ctx.checker.getTypeAtLocation(f.expression)))
|
|
1065
1142
|
return true;
|
|
1066
|
-
if (t.isIdentifier(root) &&
|
|
1143
|
+
if (t.isIdentifier(root) && resolvesToEastImport(root, ctx.checker, t))
|
|
1067
1144
|
return true;
|
|
1068
1145
|
if (t.isPropertyAccessExpression(f) && t.isIdentifier(root) && resolvesToInBlockEastBinding(root, ctx))
|
|
1069
1146
|
return true;
|
|
1147
|
+
if (isEastPlatformDefinitionType(ctx.checker.getTypeAtLocation(f)))
|
|
1148
|
+
return true;
|
|
1149
|
+
if (isJsxCompositionCall(call, ctx))
|
|
1150
|
+
return true;
|
|
1151
|
+
if (t.isPropertyAccessExpression(f) && isLibDeclaredEastCall(call, f, ctx))
|
|
1152
|
+
return true;
|
|
1153
|
+
if (isConstantFoldCall(call, ctx))
|
|
1154
|
+
return true;
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
function isConstantFoldCall(call, ctx) {
|
|
1158
|
+
const t = ctx.ts;
|
|
1159
|
+
if ((ctx.checker.getTypeAtLocation(call).flags & t.TypeFlags.StringLike) === 0)
|
|
1160
|
+
return false;
|
|
1161
|
+
let constant = true;
|
|
1162
|
+
const visit = (n) => {
|
|
1163
|
+
if (!constant)
|
|
1164
|
+
return;
|
|
1165
|
+
if (t.isIdentifier(n)) {
|
|
1166
|
+
const p = n.parent;
|
|
1167
|
+
if (p !== void 0 && t.isPropertyAccessExpression(p) && p.name === n)
|
|
1168
|
+
return;
|
|
1169
|
+
constant = false;
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
if (t.isTemplateExpression(n)) {
|
|
1173
|
+
constant = false;
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
t.forEachChild(n, visit);
|
|
1177
|
+
};
|
|
1178
|
+
visit(call);
|
|
1179
|
+
return constant;
|
|
1180
|
+
}
|
|
1181
|
+
function isLibDeclaredEastCall(call, f, ctx) {
|
|
1182
|
+
if (!isEastExprType(ctx.checker.getTypeAtLocation(call)))
|
|
1183
|
+
return false;
|
|
1184
|
+
const inPackageDts = (sym) => (sym?.declarations ?? []).some((d) => {
|
|
1185
|
+
const sf = d.getSourceFile();
|
|
1186
|
+
if (!sf.isDeclarationFile)
|
|
1187
|
+
return false;
|
|
1188
|
+
if (ctx.program !== void 0)
|
|
1189
|
+
return !ctx.program.isSourceFileDefaultLibrary(sf);
|
|
1190
|
+
return !/\/lib\.[^/]*\.d\.ts$/.test(sf.fileName);
|
|
1191
|
+
});
|
|
1192
|
+
if (inPackageDts(ctx.checker.getSymbolAtLocation(f)))
|
|
1193
|
+
return true;
|
|
1194
|
+
const receiverType = ctx.checker.getTypeAtLocation(f.expression);
|
|
1195
|
+
if (inPackageDts(receiverType.aliasSymbol ?? receiverType.symbol))
|
|
1196
|
+
return true;
|
|
1197
|
+
return rootBuiltByEastFactory(chainRootReceiver(f, ctx), ctx);
|
|
1198
|
+
}
|
|
1199
|
+
function rootBuiltByEastFactory(root, ctx) {
|
|
1200
|
+
const t = ctx.ts;
|
|
1201
|
+
if (!t.isIdentifier(root))
|
|
1202
|
+
return false;
|
|
1203
|
+
let sym = ctx.checker.getSymbolAtLocation(root);
|
|
1204
|
+
if (sym !== void 0 && (sym.flags & t.SymbolFlags.Alias) !== 0) {
|
|
1205
|
+
sym = ctx.checker.getAliasedSymbol(sym);
|
|
1206
|
+
}
|
|
1207
|
+
const decl = sym?.valueDeclaration;
|
|
1208
|
+
if (decl === void 0 || !t.isVariableDeclaration(decl) || decl.initializer === void 0)
|
|
1209
|
+
return false;
|
|
1210
|
+
let init2 = decl.initializer;
|
|
1211
|
+
while (t.isParenthesizedExpression(init2))
|
|
1212
|
+
init2 = init2.expression;
|
|
1213
|
+
if (!t.isCallExpression(init2))
|
|
1214
|
+
return false;
|
|
1215
|
+
const initRoot = chainRootReceiver(init2.expression, ctx);
|
|
1216
|
+
return t.isIdentifier(initRoot) && resolvesToEastImport(initRoot, ctx.checker, t);
|
|
1217
|
+
}
|
|
1218
|
+
function isJsxCompositionCall(call, ctx) {
|
|
1219
|
+
const t = ctx.ts;
|
|
1220
|
+
if (call.arguments.some((a) => isJsx(a, t) || (t.isArrowFunction(a) || t.isFunctionExpression(a)) && returnExpressions(a, t).some((r) => isJsx(r, t)))) {
|
|
1221
|
+
return true;
|
|
1222
|
+
}
|
|
1223
|
+
const f = call.expression;
|
|
1224
|
+
if (!t.isIdentifier(f))
|
|
1225
|
+
return false;
|
|
1226
|
+
const sym = ctx.checker.getSymbolAtLocation(f);
|
|
1227
|
+
for (const d of sym?.declarations ?? []) {
|
|
1228
|
+
let fn;
|
|
1229
|
+
if (t.isFunctionDeclaration(d) && d.body !== void 0)
|
|
1230
|
+
fn = d;
|
|
1231
|
+
else if (t.isVariableDeclaration(d) && d.initializer !== void 0 && (t.isArrowFunction(d.initializer) || t.isFunctionExpression(d.initializer))) {
|
|
1232
|
+
fn = d.initializer;
|
|
1233
|
+
}
|
|
1234
|
+
if (fn !== void 0 && returnExpressions(fn, t).some((r) => isJsx(r, t)))
|
|
1235
|
+
return true;
|
|
1236
|
+
}
|
|
1070
1237
|
return false;
|
|
1071
1238
|
}
|
|
1072
1239
|
function isEast(expr, ctx) {
|
|
1073
1240
|
return isEastExprType(ctx.checker.getTypeAtLocation(expr));
|
|
1074
1241
|
}
|
|
1075
|
-
function insideJsx(node,
|
|
1242
|
+
function insideJsx(node, ctx) {
|
|
1243
|
+
const t = ctx.ts;
|
|
1076
1244
|
let cur = node.parent;
|
|
1077
1245
|
while (cur !== void 0) {
|
|
1078
1246
|
if (t.isJsxElement(cur) || t.isJsxSelfClosingElement(cur) || t.isJsxFragment(cur) || t.isJsxExpression(cur) || t.isJsxAttribute(cur)) {
|
|
1079
1247
|
return true;
|
|
1080
1248
|
}
|
|
1249
|
+
if (t.isArrowFunction(cur) || t.isFunctionExpression(cur) || t.isFunctionDeclaration(cur) || t.isMethodDeclaration(cur)) {
|
|
1250
|
+
return false;
|
|
1251
|
+
}
|
|
1081
1252
|
cur = cur.parent;
|
|
1082
1253
|
}
|
|
1083
1254
|
return false;
|
|
@@ -1123,7 +1294,7 @@ var noHostInEastBlock = {
|
|
|
1123
1294
|
const t = ctx.ts;
|
|
1124
1295
|
if (!insideBlockScope(node, ctx))
|
|
1125
1296
|
return;
|
|
1126
|
-
if (insideJsx(node,
|
|
1297
|
+
if (insideJsx(node, ctx))
|
|
1127
1298
|
return;
|
|
1128
1299
|
{
|
|
1129
1300
|
let fn;
|
|
@@ -1262,6 +1433,8 @@ function returnBuildsEast(r, ctx) {
|
|
|
1262
1433
|
const t = ctx.ts;
|
|
1263
1434
|
if (isJsx2(r, t))
|
|
1264
1435
|
return false;
|
|
1436
|
+
if (isEastDefinitionType(ctx.checker.getTypeAtLocation(r)))
|
|
1437
|
+
return false;
|
|
1265
1438
|
if (isEastValueConstructor(r, t))
|
|
1266
1439
|
return true;
|
|
1267
1440
|
if (isEastExprType(ctx.checker.getTypeAtLocation(r)))
|
|
@@ -1334,6 +1507,582 @@ var noModuleScopeEastMacro = {
|
|
|
1334
1507
|
}
|
|
1335
1508
|
};
|
|
1336
1509
|
|
|
1510
|
+
// ../east-diagnostics/dist/src/rules/require-runner-platforms.js
|
|
1511
|
+
var NAME17 = "require-runner-platforms";
|
|
1512
|
+
var CODE17 = 990022;
|
|
1513
|
+
function isE3TaskCall(node, ctx) {
|
|
1514
|
+
const t = ctx.ts;
|
|
1515
|
+
const callee = node.expression;
|
|
1516
|
+
if (!t.isPropertyAccessExpression(callee) || callee.name.text !== "task")
|
|
1517
|
+
return false;
|
|
1518
|
+
if (!t.isIdentifier(callee.expression))
|
|
1519
|
+
return false;
|
|
1520
|
+
const imp = importDeclarationOf(ctx.checker.getSymbolAtLocation(callee.expression), t);
|
|
1521
|
+
return imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text === "@elaraai/e3";
|
|
1522
|
+
}
|
|
1523
|
+
function projectPlatformCalls(fnArg, ctx) {
|
|
1524
|
+
const t = ctx.ts;
|
|
1525
|
+
const names = [];
|
|
1526
|
+
const visit = (n) => {
|
|
1527
|
+
if (t.isCallExpression(n) && isEastPlatformDefinitionType(ctx.checker.getTypeAtLocation(n.expression))) {
|
|
1528
|
+
const callee = n.expression;
|
|
1529
|
+
const id = t.isIdentifier(callee) ? callee : t.isPropertyAccessExpression(callee) ? callee.name : void 0;
|
|
1530
|
+
const sym = id !== void 0 ? ctx.checker.getSymbolAtLocation(id) : void 0;
|
|
1531
|
+
const resolved = sym !== void 0 && (sym.flags & t.SymbolFlags.Alias) !== 0 ? ctx.checker.getAliasedSymbol(sym) : sym;
|
|
1532
|
+
const declaredInProject = (resolved?.declarations ?? []).some((d) => !d.getSourceFile().isDeclarationFile);
|
|
1533
|
+
if (declaredInProject && id !== void 0)
|
|
1534
|
+
names.push(id.text);
|
|
1535
|
+
}
|
|
1536
|
+
t.forEachChild(n, visit);
|
|
1537
|
+
};
|
|
1538
|
+
visit(fnArg);
|
|
1539
|
+
return names;
|
|
1540
|
+
}
|
|
1541
|
+
function hasCustomPlatformsEntry(options, t) {
|
|
1542
|
+
if (options === void 0)
|
|
1543
|
+
return false;
|
|
1544
|
+
if (!t.isObjectLiteralExpression(options))
|
|
1545
|
+
return void 0;
|
|
1546
|
+
const runnerProp = options.properties.find((p) => t.isPropertyAssignment(p) && t.isIdentifier(p.name) && p.name.text === "runner");
|
|
1547
|
+
if (runnerProp === void 0 || !t.isPropertyAssignment(runnerProp))
|
|
1548
|
+
return false;
|
|
1549
|
+
if (!t.isObjectLiteralExpression(runnerProp.initializer))
|
|
1550
|
+
return void 0;
|
|
1551
|
+
const platformsProp = runnerProp.initializer.properties.find((p) => t.isPropertyAssignment(p) && t.isIdentifier(p.name) && p.name.text === "platforms");
|
|
1552
|
+
if (platformsProp === void 0 || !t.isPropertyAssignment(platformsProp))
|
|
1553
|
+
return false;
|
|
1554
|
+
if (!t.isArrayLiteralExpression(platformsProp.initializer))
|
|
1555
|
+
return void 0;
|
|
1556
|
+
return platformsProp.initializer.elements.some((el) => t.isObjectLiteralExpression(el) && el.properties.some((p) => t.isPropertyAssignment(p) && t.isIdentifier(p.name) && p.name.text === "custom"));
|
|
1557
|
+
}
|
|
1558
|
+
var requireRunnerPlatforms = {
|
|
1559
|
+
name: NAME17,
|
|
1560
|
+
code: CODE17,
|
|
1561
|
+
description: "An e3.task calling project-declared platform functions must declare a runner.platforms custom module \u2014 otherwise it fails only at dataflow runtime.",
|
|
1562
|
+
check(node, ctx) {
|
|
1563
|
+
const t = ctx.ts;
|
|
1564
|
+
if (!t.isCallExpression(node) || !isE3TaskCall(node, ctx))
|
|
1565
|
+
return;
|
|
1566
|
+
const fnArg = node.arguments[2];
|
|
1567
|
+
if (fnArg === void 0)
|
|
1568
|
+
return;
|
|
1569
|
+
const calls = projectPlatformCalls(fnArg, ctx);
|
|
1570
|
+
if (calls.length === 0)
|
|
1571
|
+
return;
|
|
1572
|
+
const ok = hasCustomPlatformsEntry(node.arguments[3], t);
|
|
1573
|
+
if (ok === true || ok === void 0)
|
|
1574
|
+
return;
|
|
1575
|
+
const nameArg = node.arguments[0];
|
|
1576
|
+
const taskName = nameArg !== void 0 && t.isStringLiteralLike(nameArg) ? nameArg.text : "\u2026";
|
|
1577
|
+
const unique = [...new Set(calls)].join(", ");
|
|
1578
|
+
const sf = ctx.sourceFile;
|
|
1579
|
+
const target = node.arguments[3] ?? node.expression;
|
|
1580
|
+
const start = target.getStart(sf);
|
|
1581
|
+
ctx.report({
|
|
1582
|
+
ruleName: NAME17,
|
|
1583
|
+
code: CODE17,
|
|
1584
|
+
start,
|
|
1585
|
+
length: target.getEnd() - start,
|
|
1586
|
+
messageText: `Task "${taskName}" calls project platform function(s) ${unique} but its runner declares no custom platform module \u2014 it will fail at dataflow runtime with "Platform function \u2026 is not available". Add the module to the runner, e.g. \`{ runner: { runtime: "east-py", platforms: [{ custom: "platform_module" }] } }\`.`,
|
|
1587
|
+
category: "warning"
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
// ../east-diagnostics/dist/src/rules/no-cross-block-builder.js
|
|
1593
|
+
var NAME18 = "no-cross-block-builder";
|
|
1594
|
+
var CODE18 = 990023;
|
|
1595
|
+
function nearestBlockCallback(node, ctx) {
|
|
1596
|
+
let cur = node.parent;
|
|
1597
|
+
while (cur !== void 0) {
|
|
1598
|
+
if (isBlockBuilderCallback(cur, ctx))
|
|
1599
|
+
return cur;
|
|
1600
|
+
cur = cur.parent;
|
|
1601
|
+
}
|
|
1602
|
+
return void 0;
|
|
1603
|
+
}
|
|
1604
|
+
function referencesCrossedScope(call, root, owner, ctx) {
|
|
1605
|
+
const t = ctx.ts;
|
|
1606
|
+
const isFnLike = (n) => t.isArrowFunction(n) || t.isFunctionExpression(n) || t.isFunctionDeclaration(n) || t.isMethodDeclaration(n);
|
|
1607
|
+
const enclosingFn = (n) => {
|
|
1608
|
+
let cur = n.parent;
|
|
1609
|
+
while (cur !== void 0 && !isFnLike(cur))
|
|
1610
|
+
cur = cur.parent;
|
|
1611
|
+
return cur;
|
|
1612
|
+
};
|
|
1613
|
+
const contains = (outer, inner) => outer.pos <= inner.pos && inner.end <= outer.end;
|
|
1614
|
+
let crossed = false;
|
|
1615
|
+
const visit = (n) => {
|
|
1616
|
+
if (crossed)
|
|
1617
|
+
return;
|
|
1618
|
+
if (t.isIdentifier(n) && n !== root) {
|
|
1619
|
+
const p = n.parent;
|
|
1620
|
+
const isLabel = p !== void 0 && (t.isPropertyAccessExpression(p) && p.name === n || t.isPropertyAssignment(p) && p.name === n || t.isJsxAttribute(p) && p.name === n);
|
|
1621
|
+
if (!isLabel) {
|
|
1622
|
+
const decl = ctx.checker.getSymbolAtLocation(n)?.valueDeclaration;
|
|
1623
|
+
if (decl !== void 0) {
|
|
1624
|
+
const declFn = enclosingFn(decl);
|
|
1625
|
+
if (declFn !== void 0 && declFn !== owner && contains(owner, declFn) && contains(declFn, call)) {
|
|
1626
|
+
crossed = true;
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
t.forEachChild(n, visit);
|
|
1633
|
+
};
|
|
1634
|
+
visit(call);
|
|
1635
|
+
return crossed;
|
|
1636
|
+
}
|
|
1637
|
+
var noCrossBlockBuilder = {
|
|
1638
|
+
name: NAME18,
|
|
1639
|
+
code: CODE18,
|
|
1640
|
+
description: "Inside a nested East block callback, an outer-`$` emission referencing inner-scope values puts the binding where those values don't exist.",
|
|
1641
|
+
check(node, ctx) {
|
|
1642
|
+
const t = ctx.ts;
|
|
1643
|
+
if (!t.isCallExpression(node))
|
|
1644
|
+
return;
|
|
1645
|
+
const root = chainRootReceiver(node.expression, ctx);
|
|
1646
|
+
if (!t.isIdentifier(root))
|
|
1647
|
+
return;
|
|
1648
|
+
if (!isBlockBuilderType(ctx.checker.getTypeAtLocation(root)))
|
|
1649
|
+
return;
|
|
1650
|
+
const sym = ctx.checker.getSymbolAtLocation(root);
|
|
1651
|
+
const decl = sym?.valueDeclaration;
|
|
1652
|
+
if (decl === void 0 || !t.isParameter(decl))
|
|
1653
|
+
return;
|
|
1654
|
+
const owner = decl.parent;
|
|
1655
|
+
if (!isBlockBuilderCallback(owner, ctx))
|
|
1656
|
+
return;
|
|
1657
|
+
const nearest = nearestBlockCallback(node, ctx);
|
|
1658
|
+
if (nearest === void 0 || nearest === owner)
|
|
1659
|
+
return;
|
|
1660
|
+
if (!referencesCrossedScope(node, root, owner, ctx))
|
|
1661
|
+
return;
|
|
1662
|
+
const sf = ctx.sourceFile;
|
|
1663
|
+
const start = root.getStart(sf);
|
|
1664
|
+
ctx.report({
|
|
1665
|
+
ruleName: NAME18,
|
|
1666
|
+
code: CODE18,
|
|
1667
|
+
start,
|
|
1668
|
+
length: node.getEnd() - start,
|
|
1669
|
+
messageText: "This call uses an OUTER block's `$` inside a nested East callback while referencing inner-callback values \u2014 the binding is emitted into the outer block, where those values don't exist. Use the callback's own builder (name it `$`, not `_$`).",
|
|
1670
|
+
category: "error"
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
|
|
1675
|
+
// ../east-diagnostics/dist/src/rules/no-state-outside-reactive.js
|
|
1676
|
+
var NAME19 = "no-state-outside-reactive";
|
|
1677
|
+
var CODE19 = 990024;
|
|
1678
|
+
function atUiSurfaceRoot(node, ctx) {
|
|
1679
|
+
const t = ctx.ts;
|
|
1680
|
+
const outermost = enclosingBlockScope(node, ctx);
|
|
1681
|
+
if (outermost === void 0 || !t.isCallExpression(outermost))
|
|
1682
|
+
return false;
|
|
1683
|
+
const parent = outermost.parent;
|
|
1684
|
+
if (parent === void 0 || !t.isCallExpression(parent))
|
|
1685
|
+
return false;
|
|
1686
|
+
if (!parent.arguments.some((a) => a === outermost))
|
|
1687
|
+
return false;
|
|
1688
|
+
const callee = parent.expression;
|
|
1689
|
+
return t.isIdentifier(callee) && callee.text === "ui" && resolvesToEastImport(callee, ctx.checker, t);
|
|
1690
|
+
}
|
|
1691
|
+
var noStateOutsideReactive = {
|
|
1692
|
+
name: NAME19,
|
|
1693
|
+
code: CODE19,
|
|
1694
|
+
description: "east-ui State.* must live inside a <Reactive> builder \u2014 outside one the UI function becomes async and is rejected at deploy time.",
|
|
1695
|
+
check(node, ctx) {
|
|
1696
|
+
const t = ctx.ts;
|
|
1697
|
+
if (!t.isCallExpression(node))
|
|
1698
|
+
return;
|
|
1699
|
+
const callee = node.expression;
|
|
1700
|
+
if (!t.isPropertyAccessExpression(callee))
|
|
1701
|
+
return;
|
|
1702
|
+
if (!t.isIdentifier(callee.expression) || callee.expression.text !== "State")
|
|
1703
|
+
return;
|
|
1704
|
+
if (!resolvesToEastImport(callee.expression, ctx.checker, t))
|
|
1705
|
+
return;
|
|
1706
|
+
if (!atUiSurfaceRoot(node, ctx))
|
|
1707
|
+
return;
|
|
1708
|
+
if (insideReactive(node, t))
|
|
1709
|
+
return;
|
|
1710
|
+
const sf = ctx.sourceFile;
|
|
1711
|
+
const start = node.getStart(sf);
|
|
1712
|
+
ctx.report({
|
|
1713
|
+
ruleName: NAME19,
|
|
1714
|
+
code: CODE19,
|
|
1715
|
+
start,
|
|
1716
|
+
length: node.getEnd() - start,
|
|
1717
|
+
messageText: `\`State.${callee.name.text}\` outside a \`<Reactive>\` builder makes this UI function async at analysis time \u2014 the deploy analyzer rejects it (or the surface never re-renders). Move all \`State.*\` into the \`<Reactive>{$ => \u2026}\` inner builder.`,
|
|
1718
|
+
category: "warning"
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
|
|
1723
|
+
// ../east-diagnostics/dist/src/rules/prefer-const-ui-callbacks.js
|
|
1724
|
+
var NAME20 = "prefer-const-ui-callbacks";
|
|
1725
|
+
var CODE20 = 990025;
|
|
1726
|
+
var preferConstUiCallbacks = {
|
|
1727
|
+
name: NAME20,
|
|
1728
|
+
code: CODE20,
|
|
1729
|
+
description: "Inside <Reactive>, bind JSX event handlers with $.const and pass the handle \u2014 an inline East.function prop is rebuilt each re-render and memoized renderers can't see the swap.",
|
|
1730
|
+
check(node, ctx) {
|
|
1731
|
+
const t = ctx.ts;
|
|
1732
|
+
if (!t.isCallExpression(node))
|
|
1733
|
+
return;
|
|
1734
|
+
const callee = node.expression;
|
|
1735
|
+
if (!t.isPropertyAccessExpression(callee))
|
|
1736
|
+
return;
|
|
1737
|
+
if (!t.isIdentifier(callee.expression) || callee.expression.text !== "East")
|
|
1738
|
+
return;
|
|
1739
|
+
if (callee.name.text !== "function" && callee.name.text !== "asyncFunction")
|
|
1740
|
+
return;
|
|
1741
|
+
const parent = node.parent;
|
|
1742
|
+
if (parent === void 0 || !t.isJsxExpression(parent) || parent.expression !== node)
|
|
1743
|
+
return;
|
|
1744
|
+
const attr = parent.parent;
|
|
1745
|
+
if (attr === void 0 || !t.isJsxAttribute(attr))
|
|
1746
|
+
return;
|
|
1747
|
+
if (!insideBlockScope(node, ctx))
|
|
1748
|
+
return;
|
|
1749
|
+
if (!insideReactive(node, t))
|
|
1750
|
+
return;
|
|
1751
|
+
const sf = ctx.sourceFile;
|
|
1752
|
+
const start = callee.getStart(sf);
|
|
1753
|
+
ctx.report({
|
|
1754
|
+
ruleName: NAME20,
|
|
1755
|
+
code: CODE20,
|
|
1756
|
+
start,
|
|
1757
|
+
length: callee.getEnd() - start,
|
|
1758
|
+
messageText: `Inline \`East.${callee.name.text}\` in the \`${attr.name.getText(sf)}\` prop is rebuilt on every render, and \`equalFor\` treats all functions as equal so memoized renderers can't see the swap. Bind it once \u2014 \`const handler = $.const(East.${callee.name.text}(\u2026))\` \u2014 and pass the handle.`,
|
|
1759
|
+
category: "suggestion"
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
// ../east-diagnostics/dist/src/rules/no-dynamic-bind-path.js
|
|
1765
|
+
var NAME21 = "no-dynamic-bind-path";
|
|
1766
|
+
var CODE21 = 990026;
|
|
1767
|
+
var KEY_ARG_INDEX = {
|
|
1768
|
+
Data: 0,
|
|
1769
|
+
State: 1,
|
|
1770
|
+
Navigation: 1
|
|
1771
|
+
};
|
|
1772
|
+
var noDynamicBindPath = {
|
|
1773
|
+
name: NAME21,
|
|
1774
|
+
code: CODE21,
|
|
1775
|
+
description: "Data.bind / State.bind / Navigation.bind keys must be IR-build constants \u2014 an East-computed key can't be captured in the ui() manifest.",
|
|
1776
|
+
check(node, ctx) {
|
|
1777
|
+
const t = ctx.ts;
|
|
1778
|
+
if (!t.isCallExpression(node))
|
|
1779
|
+
return;
|
|
1780
|
+
const callee = node.expression;
|
|
1781
|
+
if (!t.isPropertyAccessExpression(callee) || callee.name.text !== "bind")
|
|
1782
|
+
return;
|
|
1783
|
+
if (!t.isIdentifier(callee.expression))
|
|
1784
|
+
return;
|
|
1785
|
+
const ns = callee.expression.text;
|
|
1786
|
+
const argIndex = KEY_ARG_INDEX[ns];
|
|
1787
|
+
if (argIndex === void 0)
|
|
1788
|
+
return;
|
|
1789
|
+
if (!resolvesToEastImport(callee.expression, ctx.checker, t))
|
|
1790
|
+
return;
|
|
1791
|
+
const keyArg = node.arguments[argIndex];
|
|
1792
|
+
if (keyArg === void 0)
|
|
1793
|
+
return;
|
|
1794
|
+
if (!isEastExprType(ctx.checker.getTypeAtLocation(keyArg)))
|
|
1795
|
+
return;
|
|
1796
|
+
const sf = ctx.sourceFile;
|
|
1797
|
+
const start = keyArg.getStart(sf);
|
|
1798
|
+
ctx.report({
|
|
1799
|
+
ruleName: NAME21,
|
|
1800
|
+
code: CODE21,
|
|
1801
|
+
start,
|
|
1802
|
+
length: keyArg.getEnd() - start,
|
|
1803
|
+
messageText: `The \`${ns}.bind\` key is an East expression \u2014 bind keys must be JS-side constants captured at IR-build time, or the binding is missing from the ui() manifest (no subscription/permission). Bind each candidate as a constant and select the VALUE in East (\`cond.ifElse(() => a.read(), () => b.read())\`).`,
|
|
1804
|
+
category: "error"
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1808
|
+
|
|
1809
|
+
// ../east-diagnostics/dist/src/rules/no-build-time-clock.js
|
|
1810
|
+
var NAME22 = "no-build-time-clock";
|
|
1811
|
+
var CODE22 = 990027;
|
|
1812
|
+
function insideFunction(node, t) {
|
|
1813
|
+
let cur = node.parent;
|
|
1814
|
+
while (cur !== void 0) {
|
|
1815
|
+
if (t.isArrowFunction(cur) || t.isFunctionExpression(cur) || t.isFunctionDeclaration(cur) || t.isMethodDeclaration(cur) || t.isConstructorDeclaration(cur) || t.isGetAccessorDeclaration(cur) || t.isSetAccessorDeclaration(cur)) {
|
|
1816
|
+
return true;
|
|
1817
|
+
}
|
|
1818
|
+
cur = cur.parent;
|
|
1819
|
+
}
|
|
1820
|
+
return false;
|
|
1821
|
+
}
|
|
1822
|
+
var noBuildTimeClock = {
|
|
1823
|
+
name: NAME22,
|
|
1824
|
+
code: CODE22,
|
|
1825
|
+
description: "Flag Date.now() / argless new Date() at module scope of East/e3 source \u2014 the build clock gets baked into the deployed program.",
|
|
1826
|
+
check(node, ctx) {
|
|
1827
|
+
const t = ctx.ts;
|
|
1828
|
+
let target;
|
|
1829
|
+
if (t.isCallExpression(node) && t.isPropertyAccessExpression(node.expression) && t.isIdentifier(node.expression.expression) && node.expression.expression.text === "Date" && node.expression.name.text === "now") {
|
|
1830
|
+
target = node;
|
|
1831
|
+
} else if (t.isNewExpression(node) && t.isIdentifier(node.expression) && node.expression.text === "Date" && (node.arguments === void 0 || node.arguments.length === 0)) {
|
|
1832
|
+
target = node;
|
|
1833
|
+
}
|
|
1834
|
+
if (target === void 0)
|
|
1835
|
+
return;
|
|
1836
|
+
if (!importsEastPackage(ctx.sourceFile, t))
|
|
1837
|
+
return;
|
|
1838
|
+
if (insideFunction(target, t))
|
|
1839
|
+
return;
|
|
1840
|
+
const sf = ctx.sourceFile;
|
|
1841
|
+
const start = target.getStart(sf);
|
|
1842
|
+
ctx.report({
|
|
1843
|
+
ruleName: NAME22,
|
|
1844
|
+
code: CODE22,
|
|
1845
|
+
start,
|
|
1846
|
+
length: target.getEnd() - start,
|
|
1847
|
+
messageText: 'Module-scope clock read in East/e3 source \u2014 this bakes the BUILD moment into the deployed program. Author a constant datetime (`new Date("2026-06-30T07:00:00Z")`), or read time at runtime inside a task (the `Time` platform).',
|
|
1848
|
+
category: "warning"
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
|
|
1853
|
+
// ../east-diagnostics/dist/src/rules/no-handrolled-value-type-mirror.js
|
|
1854
|
+
var NAME23 = "no-handrolled-value-type-mirror";
|
|
1855
|
+
var CODE23 = 990028;
|
|
1856
|
+
function eastTypeValueInFile(name, ctx) {
|
|
1857
|
+
const t = ctx.ts;
|
|
1858
|
+
for (const stmt of ctx.sourceFile.statements) {
|
|
1859
|
+
let ident;
|
|
1860
|
+
if (t.isImportDeclaration(stmt) && stmt.importClause?.namedBindings !== void 0 && t.isNamedImports(stmt.importClause.namedBindings)) {
|
|
1861
|
+
for (const spec of stmt.importClause.namedBindings.elements) {
|
|
1862
|
+
if (spec.name.text === name && !spec.isTypeOnly)
|
|
1863
|
+
ident = spec.name;
|
|
1864
|
+
}
|
|
1865
|
+
} else if (t.isVariableStatement(stmt)) {
|
|
1866
|
+
for (const d of stmt.declarationList.declarations) {
|
|
1867
|
+
if (t.isIdentifier(d.name) && d.name.text === name)
|
|
1868
|
+
ident = d.name;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
if (ident !== void 0) {
|
|
1872
|
+
const type = ctx.checker.getTypeAtLocation(ident);
|
|
1873
|
+
const typeName = type.aliasSymbol?.name ?? type.symbol?.name;
|
|
1874
|
+
if (typeName !== void 0 && typeName.endsWith("Type"))
|
|
1875
|
+
return true;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
return false;
|
|
1879
|
+
}
|
|
1880
|
+
var noHandrolledValueTypeMirror = {
|
|
1881
|
+
name: NAME23,
|
|
1882
|
+
code: CODE23,
|
|
1883
|
+
description: "A hand-authored interface mirroring an in-scope East type \u2014 derive it with ValueTypeOf<typeof XType> instead.",
|
|
1884
|
+
check(node, ctx) {
|
|
1885
|
+
const t = ctx.ts;
|
|
1886
|
+
let name;
|
|
1887
|
+
if (t.isInterfaceDeclaration(node)) {
|
|
1888
|
+
name = node.name;
|
|
1889
|
+
} else if (t.isTypeAliasDeclaration(node) && t.isTypeLiteralNode(node.type)) {
|
|
1890
|
+
name = node.name;
|
|
1891
|
+
}
|
|
1892
|
+
if (name === void 0)
|
|
1893
|
+
return;
|
|
1894
|
+
if (!importsEastPackage(ctx.sourceFile, t))
|
|
1895
|
+
return;
|
|
1896
|
+
const base = name.text.endsWith("Value") ? name.text.slice(0, -"Value".length) : name.text;
|
|
1897
|
+
const counterpart = `${base}Type`;
|
|
1898
|
+
if (counterpart === name.text)
|
|
1899
|
+
return;
|
|
1900
|
+
if (!eastTypeValueInFile(counterpart, ctx))
|
|
1901
|
+
return;
|
|
1902
|
+
const sf = ctx.sourceFile;
|
|
1903
|
+
const start = name.getStart(sf);
|
|
1904
|
+
ctx.report({
|
|
1905
|
+
ruleName: NAME23,
|
|
1906
|
+
code: CODE23,
|
|
1907
|
+
start,
|
|
1908
|
+
length: name.getEnd() - start,
|
|
1909
|
+
messageText: `\`${name.text}\` hand-mirrors the East type \`${counterpart}\` \u2014 it drifts silently when the East type gains a field. Derive it: \`type ${name.text} = ValueTypeOf<typeof ${counterpart}>\`.`,
|
|
1910
|
+
category: "suggestion"
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
|
|
1915
|
+
// ../east-diagnostics/dist/src/rules/no-host-comparison-on-east-values.js
|
|
1916
|
+
var NAME24 = "no-host-comparison-on-east-values";
|
|
1917
|
+
var CODE24 = 990029;
|
|
1918
|
+
var VALUE_SHAPE_NAMES = /* @__PURE__ */ new Set(["variant", "option", "SortedMap", "SortedSet"]);
|
|
1919
|
+
function isEastValueShapeType(type) {
|
|
1920
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1921
|
+
const stack = [type];
|
|
1922
|
+
while (stack.length > 0) {
|
|
1923
|
+
const current = stack.pop();
|
|
1924
|
+
if (current === void 0 || seen.has(current))
|
|
1925
|
+
continue;
|
|
1926
|
+
seen.add(current);
|
|
1927
|
+
const name = current.aliasSymbol?.name ?? current.symbol?.name;
|
|
1928
|
+
if (name !== void 0 && VALUE_SHAPE_NAMES.has(name))
|
|
1929
|
+
return true;
|
|
1930
|
+
if (current.isUnionOrIntersection())
|
|
1931
|
+
stack.push(...current.types);
|
|
1932
|
+
}
|
|
1933
|
+
return false;
|
|
1934
|
+
}
|
|
1935
|
+
function isNullish(e, t) {
|
|
1936
|
+
return e.kind === t.SyntaxKind.NullKeyword || t.isIdentifier(e) && e.text === "undefined";
|
|
1937
|
+
}
|
|
1938
|
+
var noHostComparisonOnEastValues = {
|
|
1939
|
+
name: NAME24,
|
|
1940
|
+
code: CODE24,
|
|
1941
|
+
description: "Flag ===/!==/</> on decoded East values (variants, options, SortedMap/SortedSet) \u2014 use equalFor(T) / compareFor(T).",
|
|
1942
|
+
check(node, ctx) {
|
|
1943
|
+
const t = ctx.ts;
|
|
1944
|
+
if (!t.isBinaryExpression(node))
|
|
1945
|
+
return;
|
|
1946
|
+
const k = t.SyntaxKind;
|
|
1947
|
+
const op = node.operatorToken.kind;
|
|
1948
|
+
const equality = op === k.EqualsEqualsEqualsToken || op === k.ExclamationEqualsEqualsToken || op === k.EqualsEqualsToken || op === k.ExclamationEqualsToken;
|
|
1949
|
+
const relational = op === k.LessThanToken || op === k.LessThanEqualsToken || op === k.GreaterThanToken || op === k.GreaterThanEqualsToken;
|
|
1950
|
+
if (!equality && !relational)
|
|
1951
|
+
return;
|
|
1952
|
+
if (!importsEastPackage(ctx.sourceFile, t))
|
|
1953
|
+
return;
|
|
1954
|
+
if (isNullish(node.left, t) || isNullish(node.right, t))
|
|
1955
|
+
return;
|
|
1956
|
+
const leftShaped = isEastValueShapeType(ctx.checker.getTypeAtLocation(node.left));
|
|
1957
|
+
const rightShaped = isEastValueShapeType(ctx.checker.getTypeAtLocation(node.right));
|
|
1958
|
+
if (!leftShaped && !rightShaped)
|
|
1959
|
+
return;
|
|
1960
|
+
const sf = ctx.sourceFile;
|
|
1961
|
+
const start = node.getStart(sf);
|
|
1962
|
+
ctx.report({
|
|
1963
|
+
ruleName: NAME24,
|
|
1964
|
+
code: CODE24,
|
|
1965
|
+
start,
|
|
1966
|
+
length: node.getEnd() - start,
|
|
1967
|
+
messageText: equality ? "Host equality on a decoded East value compares object identity \u2014 two equal variants are never `===`. Use `equalFor(T)(a, b)`." : "Host ordering on a decoded East value compares the wrong representation. Use `compareFor(T)` / `lessFor(T)` (e.g. `arr.sort(compareFor(T))`).",
|
|
1968
|
+
category: "warning"
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
|
|
1973
|
+
// ../east-diagnostics/dist/src/rules/require-example-returns.js
|
|
1974
|
+
var NAME25 = "require-example-returns";
|
|
1975
|
+
var CODE25 = 990030;
|
|
1976
|
+
var RETURNS_EXEMPT = /* @__PURE__ */ new Set(["NullType", "UIComponentType"]);
|
|
1977
|
+
function propNamed(obj, name, t) {
|
|
1978
|
+
for (const p of obj.properties) {
|
|
1979
|
+
if (t.isPropertyAssignment(p) && (t.isIdentifier(p.name) || t.isStringLiteralLike(p.name)) && p.name.text === name) {
|
|
1980
|
+
return p;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return void 0;
|
|
1984
|
+
}
|
|
1985
|
+
var requireExampleReturns = {
|
|
1986
|
+
name: NAME25,
|
|
1987
|
+
code: CODE25,
|
|
1988
|
+
description: "example() must declare `returns` unless the fn output is NullType/UIComponentType \u2014 omitting it false-passes the example's assertion.",
|
|
1989
|
+
check(node, ctx) {
|
|
1990
|
+
const t = ctx.ts;
|
|
1991
|
+
if (!t.isCallExpression(node))
|
|
1992
|
+
return;
|
|
1993
|
+
const callee = node.expression;
|
|
1994
|
+
if (!t.isIdentifier(callee) || callee.text !== "example")
|
|
1995
|
+
return;
|
|
1996
|
+
if (!resolvesToEastImport(callee, ctx.checker, t))
|
|
1997
|
+
return;
|
|
1998
|
+
const arg = node.arguments[0];
|
|
1999
|
+
if (arg === void 0 || !t.isObjectLiteralExpression(arg))
|
|
2000
|
+
return;
|
|
2001
|
+
if (propNamed(arg, "returns", t) !== void 0)
|
|
2002
|
+
return;
|
|
2003
|
+
const fnProp = propNamed(arg, "fn", t);
|
|
2004
|
+
if (fnProp === void 0 || !t.isCallExpression(fnProp.initializer))
|
|
2005
|
+
return;
|
|
2006
|
+
const outputArg = fnProp.initializer.arguments[1];
|
|
2007
|
+
if (outputArg !== void 0 && t.isIdentifier(outputArg) && RETURNS_EXEMPT.has(outputArg.text))
|
|
2008
|
+
return;
|
|
2009
|
+
const sf = ctx.sourceFile;
|
|
2010
|
+
const start = callee.getStart(sf);
|
|
2011
|
+
ctx.report({
|
|
2012
|
+
ruleName: NAME25,
|
|
2013
|
+
code: CODE25,
|
|
2014
|
+
start,
|
|
2015
|
+
length: callee.getEnd() - start,
|
|
2016
|
+
messageText: "This `example()` has no `returns` \u2014 the harness runs `fn` as a bare statement and the assertion false-passes. Add the hand-verified `returns` value (omit it ONLY for NullType / UIComponentType outputs).",
|
|
2017
|
+
category: "warning"
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
};
|
|
2021
|
+
|
|
2022
|
+
// ../east-diagnostics/dist/src/rules/no-duplicate-definition-name.js
|
|
2023
|
+
var NAME26 = "no-duplicate-definition-name";
|
|
2024
|
+
var CODE26 = 990031;
|
|
2025
|
+
var DEFINITION_KINDS = /* @__PURE__ */ new Map([
|
|
2026
|
+
["input", "input"],
|
|
2027
|
+
["task", "task"],
|
|
2028
|
+
["customTask", "task"],
|
|
2029
|
+
["function", "function"],
|
|
2030
|
+
["record", "record"],
|
|
2031
|
+
["mutation", "mutation"]
|
|
2032
|
+
]);
|
|
2033
|
+
function e3Definition(node, ctx) {
|
|
2034
|
+
const t = ctx.ts;
|
|
2035
|
+
if (!t.isCallExpression(node))
|
|
2036
|
+
return void 0;
|
|
2037
|
+
const callee = node.expression;
|
|
2038
|
+
if (!t.isPropertyAccessExpression(callee) || !t.isIdentifier(callee.expression))
|
|
2039
|
+
return void 0;
|
|
2040
|
+
const kind = DEFINITION_KINDS.get(callee.name.text);
|
|
2041
|
+
if (kind === void 0)
|
|
2042
|
+
return void 0;
|
|
2043
|
+
const imp = importDeclarationOf(ctx.checker.getSymbolAtLocation(callee.expression), t);
|
|
2044
|
+
if (imp === void 0 || !t.isStringLiteral(imp.moduleSpecifier) || imp.moduleSpecifier.text !== "@elaraai/e3")
|
|
2045
|
+
return void 0;
|
|
2046
|
+
const nameArg = node.arguments[0];
|
|
2047
|
+
if (nameArg === void 0 || !t.isStringLiteralLike(nameArg))
|
|
2048
|
+
return void 0;
|
|
2049
|
+
return { kind, nameArg };
|
|
2050
|
+
}
|
|
2051
|
+
var noDuplicateDefinitionName = {
|
|
2052
|
+
name: NAME26,
|
|
2053
|
+
code: CODE26,
|
|
2054
|
+
description: "Two e3 definitions of the same kind with the same name string collide at deploy time \u2014 names must be unique per kind.",
|
|
2055
|
+
check(node, ctx) {
|
|
2056
|
+
const t = ctx.ts;
|
|
2057
|
+
if (!t.isSourceFile(node))
|
|
2058
|
+
return;
|
|
2059
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2060
|
+
const visit = (n) => {
|
|
2061
|
+
const def = e3Definition(n, ctx);
|
|
2062
|
+
if (def !== void 0) {
|
|
2063
|
+
const key = `${def.kind}:${def.nameArg.text}`;
|
|
2064
|
+
const first = seen.get(key);
|
|
2065
|
+
if (first === void 0) {
|
|
2066
|
+
seen.set(key, def.nameArg);
|
|
2067
|
+
} else {
|
|
2068
|
+
const sf = ctx.sourceFile;
|
|
2069
|
+
const start = def.nameArg.getStart(sf);
|
|
2070
|
+
ctx.report({
|
|
2071
|
+
ruleName: NAME26,
|
|
2072
|
+
code: CODE26,
|
|
2073
|
+
start,
|
|
2074
|
+
length: def.nameArg.getEnd() - start,
|
|
2075
|
+
messageText: `Duplicate e3 ${def.kind} name "${def.nameArg.text}" \u2014 it collides with the earlier definition at deploy time. Definition names must be unique per kind.`,
|
|
2076
|
+
category: "error"
|
|
2077
|
+
});
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
t.forEachChild(n, visit);
|
|
2081
|
+
};
|
|
2082
|
+
visit(node);
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
|
|
1337
2086
|
// ../east-diagnostics/dist/src/rules/index.js
|
|
1338
2087
|
var allRules = [
|
|
1339
2088
|
// East-side idiom hygiene (original set)
|
|
@@ -1355,7 +2104,18 @@ var allRules = [
|
|
|
1355
2104
|
noHostInEastBlock,
|
|
1356
2105
|
noModuleScopeEastMacro,
|
|
1357
2106
|
noCompileTimeDataInjection,
|
|
1358
|
-
noCompileTimeSeedData
|
|
2107
|
+
noCompileTimeSeedData,
|
|
2108
|
+
// deploy/runtime-failure classes that type-check clean (epic #208)
|
|
2109
|
+
requireRunnerPlatforms,
|
|
2110
|
+
noCrossBlockBuilder,
|
|
2111
|
+
noStateOutsideReactive,
|
|
2112
|
+
preferConstUiCallbacks,
|
|
2113
|
+
noDynamicBindPath,
|
|
2114
|
+
noBuildTimeClock,
|
|
2115
|
+
noHandrolledValueTypeMirror,
|
|
2116
|
+
noHostComparisonOnEastValues,
|
|
2117
|
+
requireExampleReturns,
|
|
2118
|
+
noDuplicateDefinitionName
|
|
1359
2119
|
];
|
|
1360
2120
|
|
|
1361
2121
|
// ../east-diagnostics/dist/src/run.js
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elaraai/tsserver-plugin-east",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"description": "TypeScript language service plugin for East — East idiom diagnostics and localized East type-diff error messages as native editor squiggles.",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"esbuild": "^0.27.3",
|
|
34
34
|
"typescript": "~5.9.2",
|
|
35
|
-
"@elaraai/east": "1.0.
|
|
36
|
-
"@elaraai/east
|
|
35
|
+
"@elaraai/east-diagnostics": "1.0.30",
|
|
36
|
+
"@elaraai/east": "1.0.30"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "node scripts/build.mjs",
|