@elaraai/tsserver-plugin-east 1.0.27 → 1.0.29

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.
Files changed (2) hide show
  1. package/dist/index.cjs +860 -100
  2. 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 = importDeclOfSymbol(ctx.checker.getSymbolAtLocation(callee.expression), t);
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) && resolvesToEastImport2(root, ctx))
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, t) {
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, t))
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.27",
3
+ "version": "1.0.29",
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.27",
36
- "@elaraai/east-diagnostics": "1.0.27"
35
+ "@elaraai/east": "1.0.29",
36
+ "@elaraai/east-diagnostics": "1.0.29"
37
37
  },
38
38
  "scripts": {
39
39
  "build": "node scripts/build.mjs",