@elaraai/tsserver-plugin-east 1.0.80 → 1.0.81

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 +672 -51
  2. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -345,10 +345,58 @@ function resolvesWithinOwnPackage(sourceFileName, specifierText) {
345
345
  // ../east-diagnostics/dist/src/rules/prefer-some-none.js
346
346
  var NAME3 = "prefer-some-none";
347
347
  var CODE3 = 990003;
348
+ function membersOf(types) {
349
+ return types.flatMap((type) => type.isUnion() ? type.types : [type]);
350
+ }
351
+ function literalsOf(type) {
352
+ return membersOf([type]).flatMap((m) => m.isStringLiteral() ? [m.value] : []);
353
+ }
354
+ function variantMembers(expected, at, ctx) {
355
+ const out = [];
356
+ for (const member of membersOf(expected)) {
357
+ if (isEastExprType(member))
358
+ continue;
359
+ if (ctx.checker.getPropertyOfType(member, "value") === void 0)
360
+ continue;
361
+ const tag = ctx.checker.getPropertyOfType(member, "type");
362
+ if (tag === void 0)
363
+ continue;
364
+ out.push({ member, tags: literalsOf(ctx.checker.getTypeOfSymbolAtLocation(tag, at)) });
365
+ }
366
+ return out;
367
+ }
368
+ function propertyTypes(types, name, at, ctx) {
369
+ return membersOf(types).flatMap((m) => {
370
+ const prop = ctx.checker.getPropertyOfType(m, name);
371
+ return prop === void 0 ? [] : [ctx.checker.getTypeOfSymbolAtLocation(prop, at)];
372
+ });
373
+ }
374
+ function uninformative(type, ctx) {
375
+ const t = ctx.ts;
376
+ return (type.flags & (t.TypeFlags.Any | t.TypeFlags.Unknown | t.TypeFlags.TypeParameter)) !== 0;
377
+ }
378
+ function expectedTypes(e, ctx, depth = 0) {
379
+ const t = ctx.ts;
380
+ const parent = e.parent;
381
+ if (depth < 8 && t.isPropertyAssignment(parent) && parent.initializer === e && (t.isIdentifier(parent.name) || t.isStringLiteral(parent.name))) {
382
+ const literal = expectedTypes(parent.parent, ctx, depth + 1);
383
+ if (literal.length > 0)
384
+ return propertyTypes(literal, parent.name.text, e, ctx);
385
+ }
386
+ if (depth < 8 && t.isCallExpression(parent) && parent.arguments[1] === e && t.isIdentifier(parent.expression) && parent.expression.text === "variant" && resolvesToEastImport(parent.expression, ctx.checker, t)) {
387
+ const tag = parent.arguments[0];
388
+ if (tag === void 0 || !t.isStringLiteralLike(tag))
389
+ return [];
390
+ const matches = variantMembers(expectedTypes(parent, ctx, depth + 1), e, ctx).filter((m) => m.tags.includes(tag.text));
391
+ return propertyTypes(matches.map((m) => m.member), "value", e, ctx);
392
+ }
393
+ const direct = ctx.checker.getContextualType(e);
394
+ return direct !== void 0 && !uninformative(direct, ctx) ? [direct] : [];
395
+ }
348
396
  var preferSomeNone = {
349
397
  name: NAME3,
350
398
  code: CODE3,
351
- description: 'Prefer some()/none over variant("some", \u2026)/variant("none", null).',
399
+ description: 'Prefer some()/none over variant("some", \u2026)/variant("none", null) for an Option.',
352
400
  check(node, ctx) {
353
401
  const t = ctx.ts;
354
402
  if (!t.isCallExpression(node))
@@ -364,6 +412,8 @@ var preferSomeNone = {
364
412
  const tag = first.text;
365
413
  if (tag !== "some" && tag !== "none")
366
414
  return;
415
+ if (variantMembers(expectedTypes(node, ctx), node, ctx).some((m) => m.tags.some((other) => other !== "some" && other !== "none")))
416
+ return;
367
417
  const sf = ctx.sourceFile;
368
418
  const start = node.getStart(sf);
369
419
  ctx.report({
@@ -371,7 +421,7 @@ var preferSomeNone = {
371
421
  code: CODE3,
372
422
  start,
373
423
  length: node.getEnd() - start,
374
- messageText: tag === "some" ? 'Use `some(value)` instead of `variant("some", value)`.' : 'Use `none` instead of `variant("none", null)`.',
424
+ messageText: (tag === "some" ? 'Use `some(value)` instead of `variant("some", value)`.' : 'Use `none` instead of `variant("none", null)`.') + " If this is the case of a variant that is not an Option, type the value it builds (`ValueTypeOf<typeof T>`) so the case can be told apart.",
375
425
  category: "warning"
376
426
  });
377
427
  }
@@ -395,16 +445,48 @@ function expectsVariant(type) {
395
445
  }
396
446
  return false;
397
447
  }
448
+ function propertyNamed(node, name, t) {
449
+ for (const p of node.properties) {
450
+ if ((t.isPropertyAssignment(p) || t.isShorthandPropertyAssignment(p)) && (t.isIdentifier(p.name) || t.isStringLiteral(p.name)) && p.name.text === name) {
451
+ return p;
452
+ }
453
+ }
454
+ return void 0;
455
+ }
456
+ function spelledAsVariant(node, ctx) {
457
+ const t = ctx.ts;
458
+ if (node.properties.length !== 2)
459
+ return false;
460
+ const tag = propertyNamed(node, "type", t);
461
+ if (tag === void 0 || propertyNamed(node, "value", t) === void 0)
462
+ return false;
463
+ const tagType = ctx.checker.getTypeAtLocation(t.isPropertyAssignment(tag) ? tag.initializer : tag.name);
464
+ const members = tagType.isUnion() ? tagType.types : [tagType];
465
+ return members.every((m) => (m.flags & t.TypeFlags.StringLike) !== 0);
466
+ }
467
+ function publishedShape(type, t) {
468
+ const members = (type.isUnion() ? type.types : [type]).filter((m) => (m.flags & (t.TypeFlags.Null | t.TypeFlags.Undefined)) === 0);
469
+ return members.length > 0 && members.every((m) => {
470
+ if ((m.flags & t.TypeFlags.Object) === 0)
471
+ return false;
472
+ const declarations = (m.aliasSymbol ?? m.symbol)?.declarations ?? [];
473
+ return declarations.length > 0 && declarations.every((d) => d.getSourceFile().isDeclarationFile);
474
+ });
475
+ }
398
476
  var noHandrolledVariant = {
399
477
  name: NAME4,
400
478
  code: CODE4,
401
- description: "Disallow plain object literals where an East variant/option is expected; use variant()/some()/none.",
479
+ description: "Disallow a variant built as a plain `{ type, value }` object literal \u2014 where a variant is expected, or anywhere in East source; use variant()/some()/none.",
402
480
  check(node, ctx) {
403
481
  const t = ctx.ts;
404
482
  if (!t.isObjectLiteralExpression(node))
405
483
  return;
484
+ if (propertyNamed(node, "type", t) === void 0)
485
+ return;
406
486
  const contextualType = ctx.checker.getContextualType(node);
407
- if (contextualType === void 0 || !expectsVariant(contextualType))
487
+ const inVariantSlot = contextualType !== void 0 && expectsVariant(contextualType);
488
+ const byHand = !inVariantSlot && importsEastPackage(ctx.sourceFile, t) && spelledAsVariant(node, ctx) && (contextualType === void 0 || !publishedShape(contextualType, t));
489
+ if (!inVariantSlot && !byHand)
408
490
  return;
409
491
  const sf = ctx.sourceFile;
410
492
  const start = node.getStart(sf);
@@ -413,7 +495,7 @@ var noHandrolledVariant = {
413
495
  code: CODE4,
414
496
  start,
415
497
  length: node.getEnd() - start,
416
- messageText: 'Hand-rolled variant: build with `variant("Tag", value)`, `some(value)`, or `none` from @elaraai/east \u2014 never a plain `{ type, value }` object literal.',
498
+ messageText: 'Hand-rolled variant: build with `variant("Tag", value)`, `some(value)`, or `none` from @elaraai/east \u2014 never a plain `{ type, value }` object literal, which lacks the symbol East\'s variants carry.',
417
499
  category: "warning"
418
500
  });
419
501
  }
@@ -1463,20 +1545,24 @@ function isJsx2(node, t) {
1463
1545
  function isHostTemplate(e, t) {
1464
1546
  return t.isTemplateExpression(unparen(e, t));
1465
1547
  }
1466
- function isEastValueConstructor(expr, t) {
1548
+ function hasIrArgument(call, ctx) {
1549
+ return call.arguments.some((a) => isEastExprType(ctx.checker.getTypeAtLocation(a)) || containsEastBuilder(a, ctx));
1550
+ }
1551
+ function isEastValueConstructor(expr, ctx) {
1552
+ const t = ctx.ts;
1467
1553
  if (t.isCallExpression(expr)) {
1468
1554
  const callee = expr.expression;
1469
1555
  if (t.isIdentifier(callee) && VALUE_CONSTRUCTORS.has(callee.text))
1470
- return true;
1556
+ return hasIrArgument(expr, ctx);
1471
1557
  return t.isPropertyAccessExpression(callee) && t.isIdentifier(callee.expression) && callee.expression.text === "East" && callee.name.text === "value";
1472
1558
  }
1473
- return t.isIdentifier(expr) && expr.text === "none";
1559
+ return false;
1474
1560
  }
1475
1561
  function isEastBuilderCall(call, ctx) {
1476
1562
  const t = ctx.ts;
1477
1563
  const callee = call.expression;
1478
1564
  if (t.isIdentifier(callee) && VALUE_CONSTRUCTORS.has(callee.text))
1479
- return true;
1565
+ return hasIrArgument(call, ctx);
1480
1566
  const root = chainRootReceiver(callee, ctx);
1481
1567
  if (t.isIdentifier(root) && root.text === "East")
1482
1568
  return true;
@@ -1503,7 +1589,7 @@ function returnBuildsEast(r, ctx) {
1503
1589
  return false;
1504
1590
  if (isEastDefinitionType(ctx.checker.getTypeAtLocation(r)))
1505
1591
  return false;
1506
- if (isEastValueConstructor(r, t))
1592
+ if (isEastValueConstructor(r, ctx))
1507
1593
  return true;
1508
1594
  if (isEastExprType(ctx.checker.getTypeAtLocation(r)))
1509
1595
  return true;
@@ -1513,6 +1599,62 @@ function returnBuildsEast(r, ctx) {
1513
1599
  return true;
1514
1600
  return containsEastBuilder(r, ctx);
1515
1601
  }
1602
+ function buildsEastProgram(root, ctx) {
1603
+ const t = ctx.ts;
1604
+ if (!t.isIdentifier(root))
1605
+ return false;
1606
+ if (isBlockBuilderType(ctx.checker.getTypeAtLocation(root)))
1607
+ return true;
1608
+ if (!resolvesToEastImport(root, ctx.checker, t))
1609
+ return false;
1610
+ if (root.text === "East")
1611
+ return true;
1612
+ const imp = importDeclarationOf(ctx.checker.getSymbolAtLocation(root), t);
1613
+ return imp !== void 0 && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text === "@elaraai/e3";
1614
+ }
1615
+ function flowsIntoEastProgram(call, ctx) {
1616
+ const t = ctx.ts;
1617
+ let node = call;
1618
+ for (; ; ) {
1619
+ const parent = node.parent;
1620
+ if (parent === void 0)
1621
+ return false;
1622
+ if (t.isArrayLiteralExpression(parent) || t.isObjectLiteralExpression(parent) || t.isPropertyAssignment(parent) || t.isParenthesizedExpression(parent) || t.isSpreadElement(parent) || t.isTemplateSpan(parent) || t.isTemplateExpression(parent) || t.isNewExpression(parent)) {
1623
+ node = parent;
1624
+ continue;
1625
+ }
1626
+ if (t.isCallExpression(parent) && parent.expression !== node) {
1627
+ return buildsEastProgram(chainRootReceiver(parent.expression, ctx), ctx);
1628
+ }
1629
+ return false;
1630
+ }
1631
+ }
1632
+ function feedsEastProgram(name, ctx) {
1633
+ const t = ctx.ts;
1634
+ const symbol = ctx.checker.getSymbolAtLocation(name);
1635
+ if (symbol === void 0)
1636
+ return false;
1637
+ let found = false;
1638
+ const visit = (n) => {
1639
+ if (found)
1640
+ return;
1641
+ if (t.isCallExpression(n) && t.isIdentifier(n.expression) && ctx.checker.getSymbolAtLocation(n.expression) === symbol) {
1642
+ if (insideBlockScope(n, ctx) || flowsIntoEastProgram(n, ctx)) {
1643
+ found = true;
1644
+ return;
1645
+ }
1646
+ }
1647
+ t.forEachChild(n, visit);
1648
+ };
1649
+ visit(ctx.sourceFile);
1650
+ return found;
1651
+ }
1652
+ function isValueConstruction(e, t) {
1653
+ const r = unparen(e, t);
1654
+ if (t.isIdentifier(r))
1655
+ return r.text === "none";
1656
+ return t.isCallExpression(r) && t.isIdentifier(r.expression) && VALUE_CONSTRUCTORS.has(r.expression.text);
1657
+ }
1516
1658
  function returnExpressions2(fn, t) {
1517
1659
  if (fn.body === void 0)
1518
1660
  return [];
@@ -1539,12 +1681,16 @@ var noModuleScopeEastMacro = {
1539
1681
  return;
1540
1682
  let fn;
1541
1683
  let reportNode;
1684
+ let nameNode;
1542
1685
  if (t.isFunctionDeclaration(node) && node.body !== void 0) {
1543
1686
  fn = node;
1544
1687
  reportNode = node.name ?? node;
1688
+ nameNode = node.name;
1545
1689
  } else if (t.isVariableDeclaration(node) && node.initializer !== void 0 && (t.isArrowFunction(node.initializer) || t.isFunctionExpression(node.initializer))) {
1546
1690
  fn = node.initializer;
1547
1691
  reportNode = node.name;
1692
+ if (t.isIdentifier(node.name))
1693
+ nameNode = node.name;
1548
1694
  }
1549
1695
  if (fn === void 0 || reportNode === void 0)
1550
1696
  return;
@@ -1558,9 +1704,10 @@ var noModuleScopeEastMacro = {
1558
1704
  return;
1559
1705
  if (rs.length === 0)
1560
1706
  return;
1561
- const everyBuildsEast = rs.every((r) => returnBuildsEast(r, ctx));
1562
- const everyHostKey = rs.every((r) => isHostTemplate(r, t));
1563
- if (!everyBuildsEast && !everyHostKey)
1707
+ const everyBuildsIr = rs.every((r) => returnBuildsEast(r, ctx));
1708
+ const everyBuildsValue = !everyBuildsIr && rs.every((r) => returnBuildsEast(r, ctx) || isValueConstruction(r, t));
1709
+ const everyHostKey = !everyBuildsIr && !everyBuildsValue && rs.every((r) => isHostTemplate(r, t));
1710
+ if (!everyBuildsIr && !((everyBuildsValue || everyHostKey) && nameNode !== void 0 && feedsEastProgram(nameNode, ctx)))
1564
1711
  return;
1565
1712
  const sf = ctx.sourceFile;
1566
1713
  const start = reportNode.getStart(sf);
@@ -1918,6 +2065,158 @@ var noBuildTimeClock = {
1918
2065
  }
1919
2066
  };
1920
2067
 
2068
+ // ../east-diagnostics/dist/src/east-value.js
2069
+ function declaredByEast(decl) {
2070
+ const file = decl.getSourceFile().fileName.replace(/\\/g, "/");
2071
+ return /(?:@elaraai\/east|\/libs\/east)\/(?:dist\/)?src\//.test(file);
2072
+ }
2073
+ function declaredByEastPackage(decl) {
2074
+ const sf = decl.getSourceFile();
2075
+ return sf.isDeclarationFile && /(?:\/@elaraai\/|\/libs\/)/.test(sf.fileName.replace(/\\/g, "/"));
2076
+ }
2077
+ function constituents(type, t) {
2078
+ const members = type.isUnion() ? type.types : [type];
2079
+ return members.filter((m) => (m.flags & (t.TypeFlags.Null | t.TypeFlags.Undefined | t.TypeFlags.Void)) === 0);
2080
+ }
2081
+ function isStructConstituent(type, t) {
2082
+ return (type.symbol?.declarations ?? []).some((d) => t.isMappedTypeNode(d) && declaredByEast(d));
2083
+ }
2084
+ function isVariantConstituent(type, checker) {
2085
+ if ((type.flags & 1) !== 0)
2086
+ return false;
2087
+ for (const prop of checker.getPropertiesOfType(type)) {
2088
+ if (!String(prop.escapedName).startsWith("__@variant_symbol"))
2089
+ continue;
2090
+ if ((prop.declarations ?? []).some(declaredByEast))
2091
+ return true;
2092
+ }
2093
+ return false;
2094
+ }
2095
+ function isSortedConstituent(type) {
2096
+ const name = type.symbol?.name;
2097
+ return (name === "SortedSet" || name === "SortedMap") && (type.symbol?.declarations ?? []).some(declaredByEast);
2098
+ }
2099
+ function isEastValueShape(type, ctx) {
2100
+ if (isEastExprType(type))
2101
+ return false;
2102
+ return constituents(type, ctx.ts).some((m) => isStructConstituent(m, ctx.ts) || isVariantConstituent(m, ctx.checker) || isSortedConstituent(m));
2103
+ }
2104
+ function isRecordShape(type, ctx) {
2105
+ return constituents(type, ctx.ts).some((m) => isStructConstituent(m, ctx.ts) || isVariantConstituent(m, ctx.checker));
2106
+ }
2107
+ function jsPrintDiffers(type, t) {
2108
+ const same = t.TypeFlags.StringLike | t.TypeFlags.BigIntLike | t.TypeFlags.BooleanLike;
2109
+ return constituents(type, t).some((m) => (m.flags & same) === 0);
2110
+ }
2111
+ function isGlobalBuiltin(id, ctx) {
2112
+ const declarations = ctx.checker.getSymbolAtLocation(id)?.declarations ?? [];
2113
+ return declarations.length > 0 && declarations.every((d) => {
2114
+ const file = d.getSourceFile();
2115
+ return ctx.program?.isSourceFileDefaultLibrary(file) ?? /\/typescript\/lib\/lib\.[^/]*\.d\.ts$/.test(file.fileName.replace(/\\/g, "/"));
2116
+ });
2117
+ }
2118
+ function skipValueWrappers(e, t) {
2119
+ let cur = e;
2120
+ for (; ; ) {
2121
+ if (t.isParenthesizedExpression(cur) || t.isNonNullExpression(cur) || t.isAsExpression(cur) || t.isTypeAssertionExpression(cur) || t.isSatisfiesExpression(cur)) {
2122
+ cur = cur.expression;
2123
+ } else {
2124
+ return cur;
2125
+ }
2126
+ }
2127
+ }
2128
+ var ELEMENT_READS = /* @__PURE__ */ new Set(["get", "at"]);
2129
+ function isEastValueExpression(e, ctx) {
2130
+ return eastValueExpression(e, ctx, 0);
2131
+ }
2132
+ function eastValueExpression(e, ctx, depth) {
2133
+ const t = ctx.ts;
2134
+ const expr = skipValueWrappers(e, t);
2135
+ const type = ctx.checker.getTypeAtLocation(expr);
2136
+ if (isEastExprType(type))
2137
+ return false;
2138
+ if (isEastValueShape(type, ctx))
2139
+ return true;
2140
+ if (t.isPropertyAccessExpression(expr)) {
2141
+ return isRecordShape(ctx.checker.getTypeAtLocation(expr.expression), ctx);
2142
+ }
2143
+ if (t.isElementAccessExpression(expr)) {
2144
+ return eastValueExpression(expr.expression, ctx, depth);
2145
+ }
2146
+ if (t.isCallExpression(expr) && t.isPropertyAccessExpression(expr.expression) && ELEMENT_READS.has(expr.expression.name.text)) {
2147
+ return eastValueExpression(expr.expression.expression, ctx, depth);
2148
+ }
2149
+ if (t.isIdentifier(expr) && depth < 3) {
2150
+ const decl = ctx.checker.getSymbolAtLocation(expr)?.valueDeclaration;
2151
+ if (decl !== void 0 && t.isVariableDeclaration(decl) && decl.initializer !== void 0 && t.isVariableDeclarationList(decl.parent) && (decl.parent.flags & t.NodeFlags.Const) !== 0) {
2152
+ return eastValueExpression(decl.initializer, ctx, depth + 1);
2153
+ }
2154
+ }
2155
+ return false;
2156
+ }
2157
+ function isValueConstructorCall(call, ctx) {
2158
+ const t = ctx.ts;
2159
+ const callee = call.expression;
2160
+ return t.isIdentifier(callee) && (callee.text === "variant" || callee.text === "some") && resolvesToEastImport(callee, ctx.checker, t);
2161
+ }
2162
+ function parameterTypeAt(signature, index, call, ctx) {
2163
+ const t = ctx.ts;
2164
+ const params = signature.getParameters();
2165
+ if (params.length === 0)
2166
+ return void 0;
2167
+ const param = params[Math.min(index, params.length - 1)];
2168
+ const type = ctx.checker.getTypeOfSymbolAtLocation(param, call);
2169
+ const declaration = param.valueDeclaration;
2170
+ if (declaration !== void 0 && t.isParameter(declaration) && declaration.dotDotDotToken !== void 0) {
2171
+ return ctx.checker.getTypeArguments(type)[0];
2172
+ }
2173
+ return type;
2174
+ }
2175
+ function flowOf(e, ctx) {
2176
+ const t = ctx.ts;
2177
+ if (insideBlockScope(e, ctx))
2178
+ return "program";
2179
+ let node = e;
2180
+ let east = false;
2181
+ for (; ; ) {
2182
+ const parent = node.parent;
2183
+ if (parent === void 0)
2184
+ return east ? "value" : "host";
2185
+ if (t.isParenthesizedExpression(parent) || t.isAsExpression(parent) || t.isSatisfiesExpression(parent) || t.isNonNullExpression(parent) || t.isTypeAssertionExpression(parent) || t.isArrayLiteralExpression(parent) || t.isSpreadElement(parent)) {
2186
+ node = parent;
2187
+ continue;
2188
+ }
2189
+ if (t.isPropertyAssignment(parent) && parent.initializer === node || t.isShorthandPropertyAssignment(parent)) {
2190
+ const literal = parent.parent;
2191
+ const contextual = ctx.checker.getContextualType(literal);
2192
+ if (contextual !== void 0 && isRecordShape(contextual, ctx))
2193
+ east = true;
2194
+ node = literal;
2195
+ continue;
2196
+ }
2197
+ const args = t.isCallExpression(parent) || t.isNewExpression(parent) ? parent.arguments ?? [] : [];
2198
+ if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && args.includes(node)) {
2199
+ if (t.isCallExpression(parent) && isValueConstructorCall(parent, ctx)) {
2200
+ east = true;
2201
+ node = parent;
2202
+ continue;
2203
+ }
2204
+ const signature = ctx.checker.getResolvedSignature(parent);
2205
+ const declaration = signature?.getDeclaration();
2206
+ if (signature !== void 0 && declaration !== void 0 && declaredByEastPackage(declaration)) {
2207
+ const index = args.indexOf(node);
2208
+ const param = parameterTypeAt(signature, index, parent, ctx);
2209
+ return param !== void 0 && isEastExprType(param) ? "program" : "value";
2210
+ }
2211
+ return east ? "value" : "host";
2212
+ }
2213
+ return east ? "value" : "host";
2214
+ }
2215
+ }
2216
+ function landsInEastSlot(e, ctx) {
2217
+ return flowOf(e, ctx) === "value";
2218
+ }
2219
+
1921
2220
  // ../east-diagnostics/dist/src/rules/no-handrolled-value-type-mirror.js
1922
2221
  var NAME23 = "no-handrolled-value-type-mirror";
1923
2222
  var CODE23 = 990028;
@@ -1945,70 +2244,165 @@ function eastTypeValueInFile(name, ctx) {
1945
2244
  }
1946
2245
  return false;
1947
2246
  }
2247
+ function membersOf2(node) {
2248
+ return node.members;
2249
+ }
2250
+ function mentionsEastImport(typeNode, ctx) {
2251
+ const t = ctx.ts;
2252
+ let found = false;
2253
+ const visit = (n) => {
2254
+ if (found)
2255
+ return;
2256
+ if (t.isTypeReferenceNode(n)) {
2257
+ const name = t.isIdentifier(n.typeName) ? n.typeName : t.isQualifiedName(n.typeName) ? leftmost(n.typeName, t) : void 0;
2258
+ if (name !== void 0 && resolvesToEastImport(name, ctx.checker, t)) {
2259
+ found = true;
2260
+ return;
2261
+ }
2262
+ }
2263
+ t.forEachChild(n, visit);
2264
+ };
2265
+ visit(typeNode);
2266
+ return found;
2267
+ }
2268
+ function leftmost(q, t) {
2269
+ let cur = q;
2270
+ while (t.isQualifiedName(cur))
2271
+ cur = cur.left;
2272
+ return cur;
2273
+ }
2274
+ function holdsEastValue(shape, ctx) {
2275
+ const t = ctx.ts;
2276
+ return membersOf2(shape).some((m) => t.isPropertySignature(m) && m.type !== void 0 && isEastValueShape(ctx.checker.getTypeFromTypeNode(m.type), ctx));
2277
+ }
2278
+ function isFactoryInput(node, ctx) {
2279
+ const t = ctx.ts;
2280
+ const sf = ctx.sourceFile;
2281
+ return membersOf2(node).some((m) => {
2282
+ const type = t.isPropertySignature(m) ? m.type : void 0;
2283
+ return type !== void 0 && /\b(?:SubtypeExprOrValue|ExprType)</.test(type.getText(sf));
2284
+ });
2285
+ }
2286
+ function isVariantShapedLiteral(node, t) {
2287
+ if (!t.isTypeLiteralNode(node))
2288
+ return false;
2289
+ const names = new Set(node.members.flatMap((m) => m.name !== void 0 && t.isIdentifier(m.name) ? [m.name.text] : []));
2290
+ return names.has("type") && names.has("value");
2291
+ }
2292
+ function report2(ctx, node, messageText) {
2293
+ const start = node.getStart(ctx.sourceFile);
2294
+ ctx.report({ ruleName: NAME23, code: CODE23, start, length: node.getEnd() - start, messageText, category: "suggestion" });
2295
+ }
1948
2296
  var noHandrolledValueTypeMirror = {
1949
2297
  name: NAME23,
1950
2298
  code: CODE23,
1951
- description: "A hand-authored interface mirroring an in-scope East type \u2014 derive it with ValueTypeOf<typeof XType> instead.",
2299
+ description: "A hand-authored type mirroring an East type (Foo beside FooType, a *Like stand-in, an `as { type; value }` assertion) \u2014 derive it with ValueTypeOf<typeof XType> instead.",
1952
2300
  check(node, ctx) {
1953
2301
  const t = ctx.ts;
2302
+ if (t.isAsExpression(node) || t.isTypeAssertionExpression(node)) {
2303
+ if (!isVariantShapedLiteral(node.type, t))
2304
+ return;
2305
+ if (!importsEastPackage(ctx.sourceFile, t))
2306
+ return;
2307
+ report2(ctx, node.type, "This `{ type, value }` assertion hand-mirrors an East variant \u2014 it hides the value's real type. Narrow the typed value on its tag (`v.type === \u2026`), or type it with `ValueTypeOf<typeof XType>`.");
2308
+ return;
2309
+ }
1954
2310
  let name;
2311
+ let shape;
1955
2312
  if (t.isInterfaceDeclaration(node)) {
1956
2313
  name = node.name;
2314
+ shape = node;
1957
2315
  } else if (t.isTypeAliasDeclaration(node) && t.isTypeLiteralNode(node.type)) {
1958
2316
  name = node.name;
2317
+ shape = node.type;
1959
2318
  }
1960
- if (name === void 0)
2319
+ if (name === void 0 || shape === void 0)
1961
2320
  return;
1962
2321
  if (!importsEastPackage(ctx.sourceFile, t))
1963
2322
  return;
2323
+ if (isFactoryInput(shape, ctx))
2324
+ return;
2325
+ if (name.text.length > "Like".length && name.text.endsWith("Like") && (mentionsEastImport(shape, ctx) || holdsEastValue(shape, ctx))) {
2326
+ report2(ctx, name, `\`${name.text}\` is a loose stand-in for an East value's type \u2014 it drifts silently when the East type changes. Type the value with \`ValueTypeOf<typeof XType>\` of the East type it holds.`);
2327
+ return;
2328
+ }
1964
2329
  const base = name.text.endsWith("Value") ? name.text.slice(0, -"Value".length) : name.text;
1965
2330
  const counterpart = `${base}Type`;
1966
2331
  if (counterpart === name.text)
1967
2332
  return;
1968
2333
  if (!eastTypeValueInFile(counterpart, ctx))
1969
2334
  return;
1970
- const sf = ctx.sourceFile;
1971
- const start = name.getStart(sf);
1972
- ctx.report({
1973
- ruleName: NAME23,
1974
- code: CODE23,
1975
- start,
1976
- length: name.getEnd() - start,
1977
- 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}>\`.`,
1978
- category: "suggestion"
1979
- });
2335
+ report2(ctx, name, `\`${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}>\`.`);
1980
2336
  }
1981
2337
  };
1982
2338
 
1983
2339
  // ../east-diagnostics/dist/src/rules/no-host-comparison-on-east-values.js
1984
2340
  var NAME24 = "no-host-comparison-on-east-values";
1985
2341
  var CODE24 = 990029;
1986
- var VALUE_SHAPE_NAMES = /* @__PURE__ */ new Set(["variant", "option", "SortedMap", "SortedSet"]);
1987
- function isEastValueShapeType(type) {
1988
- const seen = /* @__PURE__ */ new Set();
1989
- const stack = [type];
1990
- while (stack.length > 0) {
1991
- const current = stack.pop();
1992
- if (current === void 0 || seen.has(current))
1993
- continue;
1994
- seen.add(current);
1995
- const name = current.aliasSymbol?.name ?? current.symbol?.name;
1996
- if (name !== void 0 && VALUE_SHAPE_NAMES.has(name))
1997
- return true;
1998
- if (current.isUnionOrIntersection())
1999
- stack.push(...current.types);
2000
- }
2001
- return false;
2002
- }
2003
2342
  function isNullish(e, t) {
2004
2343
  return e.kind === t.SyntaxKind.NullKeyword || t.isIdentifier(e) && e.text === "undefined";
2005
2344
  }
2345
+ function isEastObject(e, ctx) {
2346
+ const type = ctx.checker.getTypeAtLocation(e);
2347
+ if (isEastValueShape(type, ctx))
2348
+ return true;
2349
+ const objectLike = (type.flags & ctx.ts.TypeFlags.Object) !== 0 || type.isUnion() && type.types.some((m) => (m.flags & ctx.ts.TypeFlags.Object) !== 0);
2350
+ return objectLike && isEastValueExpression(e, ctx);
2351
+ }
2352
+ function returnedExpressions(fn, t) {
2353
+ if (!t.isBlock(fn.body))
2354
+ return [fn.body];
2355
+ const out = [];
2356
+ const visit = (n) => {
2357
+ if (t.isFunctionLike(n))
2358
+ return;
2359
+ if (t.isReturnStatement(n) && n.expression !== void 0)
2360
+ out.push(n.expression);
2361
+ t.forEachChild(n, visit);
2362
+ };
2363
+ t.forEachChild(fn.body, visit);
2364
+ return out;
2365
+ }
2366
+ function subtractingComparator(call, ctx) {
2367
+ const t = ctx.ts;
2368
+ const callee = call.expression;
2369
+ if (!t.isPropertyAccessExpression(callee) || callee.name.text !== "sort" && callee.name.text !== "toSorted")
2370
+ return void 0;
2371
+ const fn = call.arguments[0];
2372
+ if (fn === void 0 || !t.isArrowFunction(fn) && !t.isFunctionExpression(fn))
2373
+ return void 0;
2374
+ for (const r of returnedExpressions(fn, t)) {
2375
+ const e = skipValueWrappers(r, t);
2376
+ if (t.isBinaryExpression(e) && e.operatorToken.kind === t.SyntaxKind.MinusToken && (isEastValueExpression(e.left, ctx) || isEastValueExpression(e.right, ctx))) {
2377
+ return e;
2378
+ }
2379
+ }
2380
+ return void 0;
2381
+ }
2006
2382
  var noHostComparisonOnEastValues = {
2007
2383
  name: NAME24,
2008
2384
  code: CODE24,
2009
- description: "Flag ===/!==/</> on decoded East values (variants, options, SortedMap/SortedSet) \u2014 use equalFor(T) / compareFor(T).",
2385
+ description: "Flag ===/!==/</> and subtracting sort comparators on decoded East values \u2014 use equalFor(T) / compareFor(T).",
2010
2386
  check(node, ctx) {
2011
2387
  const t = ctx.ts;
2388
+ const sf = ctx.sourceFile;
2389
+ if (t.isCallExpression(node)) {
2390
+ if (!importsEastPackage(sf, t))
2391
+ return;
2392
+ const subtraction = subtractingComparator(node, ctx);
2393
+ if (subtraction === void 0)
2394
+ return;
2395
+ const start2 = subtraction.getStart(sf);
2396
+ ctx.report({
2397
+ ruleName: NAME24,
2398
+ code: CODE24,
2399
+ start: start2,
2400
+ length: subtraction.getEnd() - start2,
2401
+ messageText: "A comparator that subtracts East values mis-orders them \u2014 a `NaN` makes it inconsistent and an Integer past 2^53 rounds. Order with `compareFor(T)` (`xs.sort((a, b) => compare(a.v, b.v))`).",
2402
+ category: "warning"
2403
+ });
2404
+ return;
2405
+ }
2012
2406
  if (!t.isBinaryExpression(node))
2013
2407
  return;
2014
2408
  const k = t.SyntaxKind;
@@ -2017,22 +2411,20 @@ var noHostComparisonOnEastValues = {
2017
2411
  const relational = op === k.LessThanToken || op === k.LessThanEqualsToken || op === k.GreaterThanToken || op === k.GreaterThanEqualsToken;
2018
2412
  if (!equality && !relational)
2019
2413
  return;
2020
- if (!importsEastPackage(ctx.sourceFile, t))
2414
+ if (!importsEastPackage(sf, t))
2021
2415
  return;
2022
2416
  if (isNullish(node.left, t) || isNullish(node.right, t))
2023
2417
  return;
2024
- const leftShaped = isEastValueShapeType(ctx.checker.getTypeAtLocation(node.left));
2025
- const rightShaped = isEastValueShapeType(ctx.checker.getTypeAtLocation(node.right));
2026
- if (!leftShaped && !rightShaped)
2418
+ const flagged = equality ? isEastObject(node.left, ctx) || isEastObject(node.right, ctx) : isEastValueShape(ctx.checker.getTypeAtLocation(node.left), ctx) || isEastValueShape(ctx.checker.getTypeAtLocation(node.right), ctx);
2419
+ if (!flagged)
2027
2420
  return;
2028
- const sf = ctx.sourceFile;
2029
2421
  const start = node.getStart(sf);
2030
2422
  ctx.report({
2031
2423
  ruleName: NAME24,
2032
2424
  code: CODE24,
2033
2425
  start,
2034
2426
  length: node.getEnd() - start,
2035
- 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))`).",
2427
+ messageText: equality ? "Host equality on a decoded East value compares object identity \u2014 two equal structs, variants, DateTimes or Sets are never `===`. Use `equalFor(T)(a, b)`, or `Object.is(a, b)` where you mean the same object." : "Host ordering on a decoded East value compares the wrong representation. Use `compareFor(T)` / `lessFor(T)` (e.g. `arr.sort(compareFor(T))`).",
2036
2428
  category: "warning"
2037
2429
  });
2038
2430
  }
@@ -2240,6 +2632,227 @@ var noInlineCredentials = {
2240
2632
  }
2241
2633
  };
2242
2634
 
2635
+ // ../east-diagnostics/dist/src/rules/no-host-print-of-east-values.js
2636
+ var NAME28 = "no-host-print-of-east-values";
2637
+ var CODE28 = 990033;
2638
+ var PRINTING_METHODS = /* @__PURE__ */ new Set(["toString", "toISOString", "toJSON"]);
2639
+ var CSS_UNIT = /^(?:px|r?em|ch|fr|deg|turn|[sdl]?v(?:h|w|min|max))(?![A-Za-z])/;
2640
+ function writesCssLength(span, ctx) {
2641
+ if (!CSS_UNIT.test(span.literal.text))
2642
+ return false;
2643
+ const type = ctx.checker.getTypeAtLocation(span.expression);
2644
+ const members = type.isUnion() ? type.types : [type];
2645
+ return members.every((m) => (m.flags & ctx.ts.TypeFlags.NumberLike) !== 0);
2646
+ }
2647
+ function printedValue(node, ctx) {
2648
+ const t = ctx.ts;
2649
+ if (t.isCallExpression(node)) {
2650
+ const callee = node.expression;
2651
+ if (t.isIdentifier(callee) && callee.text === "String" && node.arguments.length === 1 && isGlobalBuiltin(callee, ctx)) {
2652
+ return [node.arguments[0]];
2653
+ }
2654
+ if (t.isPropertyAccessExpression(callee)) {
2655
+ if (t.isIdentifier(callee.expression) && callee.expression.text === "JSON" && callee.name.text === "stringify" && node.arguments.length > 0 && isGlobalBuiltin(callee.expression, ctx)) {
2656
+ return [node.arguments[0]];
2657
+ }
2658
+ if (PRINTING_METHODS.has(callee.name.text))
2659
+ return [callee.expression];
2660
+ }
2661
+ return [];
2662
+ }
2663
+ if (t.isTemplateExpression(node) && !t.isTaggedTemplateExpression(node.parent)) {
2664
+ return node.templateSpans.filter((span) => !writesCssLength(span, ctx)).map((span) => span.expression);
2665
+ }
2666
+ if (t.isBinaryExpression(node) && node.operatorToken.kind === t.SyntaxKind.PlusToken) {
2667
+ const stringy = (e) => (ctx.checker.getTypeAtLocation(e).flags & t.TypeFlags.StringLike) !== 0;
2668
+ if (stringy(node.left))
2669
+ return [node.right];
2670
+ if (stringy(node.right))
2671
+ return [node.left];
2672
+ }
2673
+ return [];
2674
+ }
2675
+ var noHostPrintOfEastValues = {
2676
+ name: NAME28,
2677
+ code: CODE28,
2678
+ description: "Flag String()/toString()/toISOString()/JSON.stringify/template printing of a decoded East value JavaScript prints differently \u2014 use printFor(T) or the locale Formatters.",
2679
+ check(node, ctx) {
2680
+ const t = ctx.ts;
2681
+ if (!t.isCallExpression(node) && !t.isTemplateExpression(node) && !t.isBinaryExpression(node))
2682
+ return;
2683
+ if (!importsEastPackage(ctx.sourceFile, t))
2684
+ return;
2685
+ for (const value of printedValue(node, ctx)) {
2686
+ if (!jsPrintDiffers(ctx.checker.getTypeAtLocation(value), t))
2687
+ continue;
2688
+ if (!isEastValueExpression(value, ctx))
2689
+ continue;
2690
+ const sf = ctx.sourceFile;
2691
+ const start = value.getStart(sf);
2692
+ ctx.report({
2693
+ ruleName: NAME28,
2694
+ code: CODE28,
2695
+ start,
2696
+ length: value.getEnd() - start,
2697
+ messageText: "JavaScript prints this East value its own way \u2014 `5` for East's `5.0`, a DateTime in local time or with a `Z`, `[object Object]` for a struct. Print it with `printFor(T)`, or in the viewer's language with the locale `Formatters`.",
2698
+ category: "warning"
2699
+ });
2700
+ }
2701
+ }
2702
+ };
2703
+
2704
+ // ../east-diagnostics/dist/src/rules/no-host-parse-to-east-values.js
2705
+ var NAME29 = "no-host-parse-to-east-values";
2706
+ var CODE29 = 990034;
2707
+ var PARSERS = /* @__PURE__ */ new Set(["BigInt", "Number", "parseFloat", "parseInt"]);
2708
+ function isText(e, ctx) {
2709
+ return (ctx.checker.getTypeAtLocation(e).flags & ctx.ts.TypeFlags.StringLike) !== 0;
2710
+ }
2711
+ function literalText(e, t) {
2712
+ return t.isStringLiteral(e) || t.isNoSubstitutionTemplateLiteral(e) ? e.text : void 0;
2713
+ }
2714
+ var ZONELESS_DATE_TIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?$/;
2715
+ function parsesText(node, ctx) {
2716
+ const t = ctx.ts;
2717
+ const misread = (text, date) => {
2718
+ if (!isText(text, ctx))
2719
+ return false;
2720
+ const literal = literalText(text, t);
2721
+ return literal === void 0 || date && ZONELESS_DATE_TIME.test(literal);
2722
+ };
2723
+ if (t.isCallExpression(node)) {
2724
+ const callee = node.expression;
2725
+ const text = node.arguments[0];
2726
+ if (text === void 0)
2727
+ return false;
2728
+ if (t.isIdentifier(callee))
2729
+ return PARSERS.has(callee.text) && isGlobalBuiltin(callee, ctx) && misread(text, false);
2730
+ if (!t.isPropertyAccessExpression(callee) || !t.isIdentifier(callee.expression) || !isGlobalBuiltin(callee.expression, ctx))
2731
+ return false;
2732
+ if (callee.expression.text === "JSON" && callee.name.text === "parse")
2733
+ return misread(text, false);
2734
+ if (callee.expression.text === "Date" && callee.name.text === "parse")
2735
+ return misread(text, true);
2736
+ return false;
2737
+ }
2738
+ if (t.isNewExpression(node) && t.isIdentifier(node.expression) && node.expression.text === "Date") {
2739
+ const text = node.arguments?.[0];
2740
+ return node.arguments?.length === 1 && text !== void 0 && isGlobalBuiltin(node.expression, ctx) && misread(text, true);
2741
+ }
2742
+ return false;
2743
+ }
2744
+ var noHostParseToEastValues = {
2745
+ name: NAME29,
2746
+ code: CODE29,
2747
+ description: "Flag BigInt()/Number()/parseFloat()/parseInt()/JSON.parse()/new Date() reading text into an East slot \u2014 use parseFor(T) or East's datetime format.",
2748
+ check(node, ctx) {
2749
+ const t = ctx.ts;
2750
+ if (!t.isCallExpression(node) && !t.isNewExpression(node))
2751
+ return;
2752
+ if (!importsEastPackage(ctx.sourceFile, t))
2753
+ return;
2754
+ if (!parsesText(node, ctx))
2755
+ return;
2756
+ if (!landsInEastSlot(node, ctx))
2757
+ return;
2758
+ const sf = ctx.sourceFile;
2759
+ const start = node.getStart(sf);
2760
+ ctx.report({
2761
+ ruleName: NAME29,
2762
+ code: CODE29,
2763
+ start,
2764
+ length: node.getEnd() - start,
2765
+ messageText: 'A JavaScript parser reads this text into an East value wrongly \u2014 `BigInt("")` is 0, `BigInt("0x10")` is 16, `new Date(text)` reads local time. Read it with `parseFor(T)` (or East\'s datetime format) and act on its `success`.',
2766
+ category: "warning"
2767
+ });
2768
+ }
2769
+ };
2770
+
2771
+ // ../east-diagnostics/dist/src/rules/no-js-type-dispatch-on-east-values.js
2772
+ var NAME30 = "no-js-type-dispatch-on-east-values";
2773
+ var CODE30 = 990035;
2774
+ var noJsTypeDispatchOnEastValues = {
2775
+ name: NAME30,
2776
+ code: CODE30,
2777
+ description: "Flag typeof / instanceof on a decoded East value \u2014 dispatch on its East type (isValueOf) or its variant tag.",
2778
+ check(node, ctx) {
2779
+ const t = ctx.ts;
2780
+ let target;
2781
+ if (t.isTypeOfExpression(node))
2782
+ target = node.expression;
2783
+ else if (t.isBinaryExpression(node) && node.operatorToken.kind === t.SyntaxKind.InstanceOfKeyword)
2784
+ target = node.left;
2785
+ if (target === void 0)
2786
+ return;
2787
+ if (!importsEastPackage(ctx.sourceFile, t))
2788
+ return;
2789
+ if (!isEastValueExpression(target, ctx))
2790
+ return;
2791
+ const sf = ctx.sourceFile;
2792
+ const start = node.getStart(sf);
2793
+ ctx.report({
2794
+ ruleName: NAME30,
2795
+ code: CODE30,
2796
+ start,
2797
+ length: node.getEnd() - start,
2798
+ messageText: "`typeof` / `instanceof` asks JavaScript what this East value is, and loses its East type. Dispatch on its East type (`isValueOf(v, T)`, or the type it already has) or on its variant tag (`v.type`).",
2799
+ category: "warning"
2800
+ });
2801
+ }
2802
+ };
2803
+
2804
+ // ../east-diagnostics/dist/src/rules/no-js-collection-for-east-collection.js
2805
+ var NAME31 = "no-js-collection-for-east-collection";
2806
+ var CODE31 = 990036;
2807
+ function keyTypeOf(node, ctx) {
2808
+ const t = ctx.ts;
2809
+ const type = ctx.checker.getTypeAtLocation(node);
2810
+ if ((type.flags & t.TypeFlags.Object) === 0 || (type.objectFlags & t.ObjectFlags.Reference) === 0)
2811
+ return void 0;
2812
+ return ctx.checker.getTypeArguments(type)[0];
2813
+ }
2814
+ function keyedByIdentity(type, t) {
2815
+ const primitive = t.TypeFlags.StringLike | t.TypeFlags.NumberLike | t.TypeFlags.BigIntLike | t.TypeFlags.BooleanLike | t.TypeFlags.EnumLike | t.TypeFlags.ESSymbolLike | t.TypeFlags.Null | t.TypeFlags.Undefined;
2816
+ const members = type.isUnion() ? type.types : [type];
2817
+ return members.some((m) => {
2818
+ if (m.isIntersection())
2819
+ return m.types.every((part) => (part.flags & primitive) === 0);
2820
+ return (m.flags & (t.TypeFlags.Object | t.TypeFlags.NonPrimitive)) !== 0;
2821
+ });
2822
+ }
2823
+ var noJsCollectionForEastCollection = {
2824
+ name: NAME31,
2825
+ code: CODE31,
2826
+ description: "Flag new Set()/new Map() of object keys (structs, variants, DateTimes, Blobs) landing in an East Set or Dict \u2014 build SortedSet/SortedMap with compareFor(K).",
2827
+ check(node, ctx) {
2828
+ const t = ctx.ts;
2829
+ if (!t.isNewExpression(node) || !t.isIdentifier(node.expression))
2830
+ return;
2831
+ const kind = node.expression.text;
2832
+ if (kind !== "Set" && kind !== "Map")
2833
+ return;
2834
+ if (!importsEastPackage(ctx.sourceFile, t))
2835
+ return;
2836
+ if (!isGlobalBuiltin(node.expression, ctx))
2837
+ return;
2838
+ const key = keyTypeOf(node, ctx);
2839
+ if (key === void 0 || !keyedByIdentity(key, t))
2840
+ return;
2841
+ if (!landsInEastSlot(node, ctx))
2842
+ return;
2843
+ const sf = ctx.sourceFile;
2844
+ const start = node.getStart(sf);
2845
+ ctx.report({
2846
+ ruleName: NAME31,
2847
+ code: CODE31,
2848
+ start,
2849
+ length: node.getEnd() - start,
2850
+ messageText: kind === "Set" ? "A JavaScript `Set` finds a struct, variant, DateTime or Blob member by identity, so an equal value built elsewhere misses it. Build `new SortedSet(values, compareFor(K))`." : "A JavaScript `Map` finds a struct, variant, DateTime or Blob key by identity, so an equal key built elsewhere misses its entry. Build `new SortedMap(entries, compareFor(K))`.",
2851
+ category: "warning"
2852
+ });
2853
+ }
2854
+ };
2855
+
2243
2856
  // ../east-diagnostics/dist/src/rules/index.js
2244
2857
  var allRules = [
2245
2858
  // East-side idiom hygiene (original set)
@@ -2274,7 +2887,14 @@ var allRules = [
2274
2887
  requireExampleReturns,
2275
2888
  noDuplicateDefinitionName,
2276
2889
  // secrets hygiene: IR is content-addressed and replicated — no literal creds
2277
- noInlineCredentials
2890
+ noInlineCredentials,
2891
+ // host code holding DECODED East values: print, read, dispatch and collect
2892
+ // them through East (#963) — with noHostComparisonOnEastValues and
2893
+ // noHandrolledValueTypeMirror above
2894
+ noHostPrintOfEastValues,
2895
+ noHostParseToEastValues,
2896
+ noJsTypeDispatchOnEastValues,
2897
+ noJsCollectionForEastCollection
2278
2898
  ];
2279
2899
 
2280
2900
  // ../east-diagnostics/dist/src/run.js
@@ -2291,7 +2911,8 @@ function runEastRules(tsModule, program, sourceFile, checker, options = {}, rule
2291
2911
  report: (d) => diagnostics.push(d)
2292
2912
  };
2293
2913
  const disabled = new Set(options.disabled ?? []);
2294
- const active = rules.filter((rule) => !disabled.has(rule.name));
2914
+ const only = options.only === void 0 ? void 0 : new Set(options.only);
2915
+ const active = rules.filter((rule) => !disabled.has(rule.name) && (only === void 0 || only.has(rule.name)));
2295
2916
  const visit = (node) => {
2296
2917
  for (const rule of active)
2297
2918
  rule.check(node, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elaraai/tsserver-plugin-east",
3
- "version": "1.0.80",
3
+ "version": "1.0.81",
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.80",
36
- "@elaraai/east-diagnostics": "1.0.80"
35
+ "@elaraai/east": "1.0.81",
36
+ "@elaraai/east-diagnostics": "1.0.81"
37
37
  },
38
38
  "scripts": {
39
39
  "build": "node scripts/build.mjs",