@elaraai/east-diagnostics 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 (47) hide show
  1. package/README.md +26 -5
  2. package/dist/src/east-value.d.ts +42 -0
  3. package/dist/src/east-value.d.ts.map +1 -0
  4. package/dist/src/east-value.js +223 -0
  5. package/dist/src/east-value.js.map +1 -0
  6. package/dist/src/rules/index.d.ts +18 -0
  7. package/dist/src/rules/index.d.ts.map +1 -1
  8. package/dist/src/rules/index.js +38 -0
  9. package/dist/src/rules/index.js.map +1 -1
  10. package/dist/src/rules/no-handrolled-value-type-mirror.d.ts.map +1 -1
  11. package/dist/src/rules/no-handrolled-value-type-mirror.js +91 -18
  12. package/dist/src/rules/no-handrolled-value-type-mirror.js.map +1 -1
  13. package/dist/src/rules/no-handrolled-variant.d.ts.map +1 -1
  14. package/dist/src/rules/no-handrolled-variant.js +60 -3
  15. package/dist/src/rules/no-handrolled-variant.js.map +1 -1
  16. package/dist/src/rules/no-host-comparison-on-east-values.d.ts.map +1 -1
  17. package/dist/src/rules/no-host-comparison-on-east-values.js +78 -33
  18. package/dist/src/rules/no-host-comparison-on-east-values.js.map +1 -1
  19. package/dist/src/rules/no-host-parse-to-east-values.d.ts +3 -0
  20. package/dist/src/rules/no-host-parse-to-east-values.d.ts.map +1 -0
  21. package/dist/src/rules/no-host-parse-to-east-values.js +84 -0
  22. package/dist/src/rules/no-host-parse-to-east-values.js.map +1 -0
  23. package/dist/src/rules/no-host-print-of-east-values.d.ts +3 -0
  24. package/dist/src/rules/no-host-print-of-east-values.d.ts.map +1 -0
  25. package/dist/src/rules/no-host-print-of-east-values.js +92 -0
  26. package/dist/src/rules/no-host-print-of-east-values.js.map +1 -0
  27. package/dist/src/rules/no-js-collection-for-east-collection.d.ts +3 -0
  28. package/dist/src/rules/no-js-collection-for-east-collection.d.ts.map +1 -0
  29. package/dist/src/rules/no-js-collection-for-east-collection.js +70 -0
  30. package/dist/src/rules/no-js-collection-for-east-collection.js.map +1 -0
  31. package/dist/src/rules/no-js-type-dispatch-on-east-values.d.ts +7 -0
  32. package/dist/src/rules/no-js-type-dispatch-on-east-values.d.ts.map +1 -0
  33. package/dist/src/rules/no-js-type-dispatch-on-east-values.js +40 -0
  34. package/dist/src/rules/no-js-type-dispatch-on-east-values.js.map +1 -0
  35. package/dist/src/rules/no-module-scope-east-macro.d.ts.map +1 -1
  36. package/dist/src/rules/no-module-scope-east-macro.js +105 -17
  37. package/dist/src/rules/no-module-scope-east-macro.js.map +1 -1
  38. package/dist/src/rules/prefer-some-none.d.ts +0 -4
  39. package/dist/src/rules/prefer-some-none.d.ts.map +1 -1
  40. package/dist/src/rules/prefer-some-none.js +75 -4
  41. package/dist/src/rules/prefer-some-none.js.map +1 -1
  42. package/dist/src/run.d.ts.map +1 -1
  43. package/dist/src/run.js +2 -1
  44. package/dist/src/run.js.map +1 -1
  45. package/dist/src/types.d.ts +3 -0
  46. package/dist/src/types.d.ts.map +1 -1
  47. package/package.json +3 -3
package/README.md CHANGED
@@ -34,7 +34,7 @@ like any linter.
34
34
  - **`no-redundant-east-cast`** - Redundant TS type info on the value of `$.let`/`$.const` that the East type argument already governs — a cast (`as …`/`<…>`), `new Map<K,V>()` generics, or an `East.value(x, T)` wrapper.
35
35
  - **`prefer-explicit-east-type`** - One-arg `$.let`/`$.const` on an under-determined value (`[]`, `{}`, `new Map()`).
36
36
  - **`prefer-some-none`** - `variant("some"/"none", …)` instead of `some()` / `none`.
37
- - **`no-handrolled-variant`** - A plain object literal where an East variant/option is expected.
37
+ - **`no-handrolled-variant`** - A plain object literal where an East variant/option is expected — or, in a file that imports East, a `{ type, value }` literal with a string tag in any slot but a published API's own type (a declaration file's, like East's `Resolution`). A literal lacks the brand East tells a variant by.
38
38
  - **`no-east-namespaced-type`** - `East.IntegerType` etc. instead of a bare import.
39
39
  - **`prefer-let-const-over-east-value`** - `East.value(…)` declared or returned inside an `East.function` block.
40
40
  - **`no-relative-src-import`** - Importing *another* package's internals via `../src/…` or a deep `@elaraai/x/src` path instead of its published name. (A package importing its **own** `src` relatively — e.g. a spec's `../src/index.js` — is exempt; it cannot import its own published name.)
@@ -49,7 +49,7 @@ like any linter.
49
49
  These share one principle: **inside an East block the code must be East all the way down, and the host language may *declare* an East/e3 program but never *compute* its data-dependent IR, keys, or values.**
50
50
 
51
51
  - **`no-host-in-east-block`** - Inside an East block, any host-language construct: a host call (a local TS helper, a JS builtin, a JS Array method), a TS closure/function *declaration*, a host operator on East operands (`a + b`, `cond ? a : b`, `&&`/`||`), host index access (`arr[i]` on a JS value), a JS `for`/`while`/`if` that emits IR, or host string interpolation. (East method chains, `$.*`, `East.*`/`Expr.*`, `variant`/`some`/`none`, `East.str`, and any `@elaraai/*` call are East and never flagged.)
52
- - **`no-module-scope-east-macro`** - A module-scope TS helper whose every return builds East values/IR (`variant`/`some`/`none`/`East.value`/an `Expr` chain) or a composite string key (`(o, l) => `${o}|${l}``) — make it a real `East.function`, or model the data with typed keys / nested East structures.
52
+ - **`no-module-scope-east-macro`** - A module-scope TS helper whose every return builds East IR (an `Expr` chain, `East.value`, `variant`/`some` over an `Expr`), or a composite string key (`(o, l) => `${o}|${l}``) that feeds East data — make it a real `East.function`, or model the data with typed keys / nested East structures. A helper building decoded values over host data (a renderer's handler, a test's fixture) and a host storage key are host code, and pass.
53
53
  - **`no-compile-time-data-injection`** - Build-time data ingestion (a `node:fs` import/call, `JSON.parse`, `process.env`) at module scope — load data at runtime via `e3.input` / datasets / platform tasks. (A genuine seed-time bootstrap with no East-side reader is an accepted warning.)
54
54
  - **`no-compile-time-seed-data`** - Host-computed data passed as the seed (3rd arg) of `e3.input(name, type, variant('value', seed))` — a `new Map()`/array filled in place by host `for`-loops, or an object literal of host calls (`num(cfg.x)`, `BigInt(...)`) — bakes a build-time snapshot into the deployed program. The default must be a small *authored constant* (a literal, an empty/literal `Map`/`Set`/array/struct, or an East value `variant`/`some`/`none`/`East.value`) or omitted; load real/bulk data at runtime (a `BlobType` input parsed with `blob.decodeCsv(…)` in an `e3.task`, a platform `FileSystem.readFile`, or `e3.record` + `e3.mutation`).
55
55
 
@@ -61,21 +61,42 @@ These share one principle: **inside an East block the code must be East all the
61
61
  - **`prefer-const-ui-callbacks`** - An `East.function` handler written inline in a JSX prop — rebuilt each render, and `equalFor` can't distinguish function values, so memoized renderers miss the swap. Bind once with `$.const`.
62
62
  - **`no-dynamic-bind-path`** - A `Data.bind` / `State.bind` / `Navigation.bind` key computed from an East value — bind keys must be IR-build constants or the binding is missing from the `ui()` manifest.
63
63
  - **`no-build-time-clock`** - `Date.now()` / argless `new Date()` at module scope of East/e3 source — the BUILD clock gets baked into the deployed program.
64
- - **`no-handrolled-value-type-mirror`** - A hand-authored `interface Foo {…}` mirroring an in-scope East type value `FooType` — derive it with `ValueTypeOf<typeof FooType>` so it can't drift.
65
- - **`no-host-comparison-on-east-values`** - `===`/`<` on decoded East values (variants/options, `SortedMap`/`SortedSet`) — use `equalFor(T)` / `compareFor(T)`.
64
+ - **`no-handrolled-value-type-mirror`** - A hand-authored `interface Foo {…}` mirroring an in-scope East type value `FooType`, an `as { type: …; value: … }` assertion, or a `*Like` interface or type literal over East types — derive it with `ValueTypeOf<typeof FooType>` so it can't drift, and narrow a decoded union on its tag. A factory's options interface (`SubtypeExprOrValue<…>` members) is an input, not a mirror, and passes.
65
+ - **`no-host-comparison-on-east-values`** - `===`/`<` on decoded East values, and a sort comparator that subtracts them — use `equalFor(T)` / `compareFor(T)`, or `Object.is(a, b)` where you mean the same object (a memo, a cache).
66
66
  - **`require-example-returns`** - An `example()` without `returns` (for a non-`NullType`/`UIComponentType` output) — the harness runs the fn as a bare statement and the assertion false-passes.
67
67
  - **`no-duplicate-definition-name`** - Two same-kind e3 definitions sharing a name string in one file — they collide at deploy time.
68
68
  - **`no-inline-credentials`** - A literal string credential (`password`, `secretAccessKey`, `token`, …, directly or wrapped in `some(…)`/`variant("some", …)`) in East/e3 source — the IR is content-addressed, exported, and replicated, so a secret in it is effectively unredactable. Use `Env.get("NAME")` (east-node-std) and supply the value per environment. Credentials paired with a localhost host/endpoint (test containers) are exempt.
69
69
 
70
+ ### Host code holding decoded East values
71
+
72
+ A renderer, a runtime or a test holds East values once East has decoded them,
73
+ and each rule here flags a JavaScript stand-in for one of East's utilities.
74
+ Each stand-in type-checks clean, and several hid real bugs in the renderers
75
+ (#960, #962).
76
+ A value is recognised by where its type comes from — a `ValueTypeOf` struct, a
77
+ member carrying `[variant_symbol]`, a `SortedSet` / `SortedMap`, or a field,
78
+ payload or element read out of one — never by a name list. `hostValueRuleNames`
79
+ names the set (with `no-host-comparison-on-east-values`,
80
+ `no-handrolled-value-type-mirror`, `no-handrolled-variant` and
81
+ `prefer-some-none`), for a caller running only these with `only`.
82
+
83
+ - **`no-host-print-of-east-values`** - `String(x)`, `x.toString()`, `` `${x}` ``, `JSON.stringify(x)`, `x.toISOString()` on a value JavaScript prints differently from East — a Float, a DateTime, a Blob, a struct, a variant, a collection. Use `printFor(T)`, or the locale formatters for a person. A String, an Integer and a Boolean print the same either way, and a number written as a CSS length (`` `${w}px` ``) is style, not a print.
84
+ - **`no-host-parse-to-east-values`** - `BigInt(s)`, `Number(s)`, `parseFloat(s)`, `parseInt(s)`, `new Date(s)`, `Date.parse(s)` or `JSON.parse(s)` reading text into an East slot — an East function value's argument, a variant's payload, a struct's field. Use `parseFor(T)` and act on its `success`. Text written in the source is its author's, save a zoneless date-time, which `new Date` reads in local time.
85
+ - **`no-js-type-dispatch-on-east-values`** - `typeof x` or `x instanceof C` on an East value — dispatch on its East type (`isValueOf(x, T)`) or its variant tag.
86
+ - **`no-js-collection-for-east-collection`** - A JavaScript `Set` / `Map` keyed by structs, variants or DateTimes landing in an East Set, Dict or variant payload — it finds a key by identity, so an equal key never finds its entry. Use `SortedSet` / `SortedMap` with `compareFor(K)`. String, Integer, Float and Boolean keys are East's own idiom and pass.
87
+
70
88
  ## Usage
71
89
 
72
90
  ```typescript
73
91
  import * as ts from "typescript";
74
- import { runEastRules, createDiagnosticsService } from "@elaraai/east-diagnostics";
92
+ import { runEastRules, createDiagnosticsService, hostValueRuleNames } from "@elaraai/east-diagnostics";
75
93
 
76
94
  // Pure: run the rules over one source file you already have a program + checker for.
77
95
  const diagnostics = runEastRules(ts, program, sourceFile, checker, { disabled: ["prefer-some-none"] });
78
96
 
97
+ // Only the rules over host code holding decoded East values.
98
+ const hostValues = runEastRules(ts, program, sourceFile, checker, { only: hostValueRuleNames });
99
+
79
100
  // Or let the service resolve the project and merge native + rule diagnostics.
80
101
  const service = createDiagnosticsService();
81
102
  const text = service.diagnoseText("/path/to/file.ts"); // "" when clean
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import type * as ts from "typescript";
6
+ import type { RuleContext, TsModule } from "./types.js";
7
+ /** Is `type` (or one of its non-nullish members) a decoded East struct, variant
8
+ * or sorted collection? A type with an East `Expr` among its members — a factory's
9
+ * `SubtypeExprOrValue<…>` input — is authoring, not a decoded value. */
10
+ export declare function isEastValueShape(type: ts.Type, ctx: RuleContext): boolean;
11
+ /** Does JavaScript print a value of `type` differently from East? A String, an
12
+ * Integer (`bigint`) and a Boolean print the same either way; a Float (`5` for
13
+ * East's `5.0`), a DateTime, a Blob and every object do not. */
14
+ export declare function jsPrintDiffers(type: ts.Type, t: TsModule): boolean;
15
+ /** Is `id` JavaScript's own global (`String`, `BigInt`, `Set`, `JSON`, …) — declared
16
+ * by the default library, not shadowed by a local or an import? */
17
+ export declare function isGlobalBuiltin(id: ts.Identifier, ctx: RuleContext): boolean;
18
+ /** Strip the wrappers that leave a value as it is: parentheses, `!`, `as`,
19
+ * `satisfies` and `<T>` assertions. */
20
+ export declare function skipValueWrappers(e: ts.Expression, t: TsModule): ts.Expression;
21
+ /**
22
+ * Is `e` a decoded East value — typed as an East struct, variant or sorted
23
+ * collection, or read out of one (a field, a payload, an element), or a `const`
24
+ * bound to such a read?
25
+ *
26
+ * @param e - The expression
27
+ * @param ctx - The rule context
28
+ * @returns Whether the expression evaluates to a decoded East value
29
+ */
30
+ export declare function isEastValueExpression(e: ts.Expression, ctx: RuleContext): boolean;
31
+ /**
32
+ * Does `e` land in a decoded East value — an argument to an East function value
33
+ * or a utility over decoded values (an encoder, a comparer), a field of a decoded
34
+ * struct, a variant's payload — rather than in an East program (authored input
35
+ * East converts through its type) or in host code?
36
+ *
37
+ * @param e - The expression
38
+ * @param ctx - The rule context
39
+ * @returns Whether the value `e` produces becomes (part of) a decoded East value
40
+ */
41
+ export declare function landsInEastSlot(e: ts.Expression, ctx: RuleContext): boolean;
42
+ //# sourceMappingURL=east-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"east-value.d.ts","sourceRoot":"","sources":["../../src/east-value.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA2DxD;;wEAEwE;AACxE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAKzE;AAQD;;gEAEgE;AAChE,wBAAgB,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAGlE;AAED;mEACmE;AACnE,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAM5E;AAED;uCACuC;AACvC,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,GAAG,EAAE,CAAC,UAAU,CAS9E;AAKD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAEjF;AA4GD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAE3E"}
@@ -0,0 +1,223 @@
1
+ import { isEastExprType } from "./east-type.js";
2
+ import { insideBlockScope } from "./block-scope.js";
3
+ import { resolvesToEastImport } from "./east-source.js";
4
+ // DECODED East values — the host-side world of `ValueTypeOf<…>`: what a renderer,
5
+ // a runtime or a test holds once East has decoded a value. Their TypeScript types
6
+ // are mostly JavaScript's own (`bigint`, `number`, `string`, `Date`, `Set`, `Map`,
7
+ // arrays), so a value is recognised by where its type COMES FROM, never by a name
8
+ // list:
9
+ //
10
+ // - a struct is an object type declared by East's `ValueTypeOf` mapped type;
11
+ // - a variant or option is an object type carrying East's `[variant_symbol]`;
12
+ // - a `SortedSet` / `SortedMap` is East's own class;
13
+ // - and anything read out of one of those — a struct's field, a variant's
14
+ // `value`, an element of a collection read from one — is an East value too.
15
+ /** Is `decl` declared by the `@elaraai/east` package — its built declarations, or
16
+ * its source when a workspace links to it? */
17
+ function declaredByEast(decl) {
18
+ const file = decl.getSourceFile().fileName.replace(/\\/g, "/");
19
+ return /(?:@elaraai\/east|\/libs\/east)\/(?:dist\/)?src\//.test(file);
20
+ }
21
+ /** Is `decl` declared by an East-ecosystem package the file depends on — a built
22
+ * declaration file of `@elaraai/*` (east, east-ui, e3, …)? A package's own sources
23
+ * are not declaration files, so its local helpers never count. */
24
+ function declaredByEastPackage(decl) {
25
+ const sf = decl.getSourceFile();
26
+ return sf.isDeclarationFile && /(?:\/@elaraai\/|\/libs\/)/.test(sf.fileName.replace(/\\/g, "/"));
27
+ }
28
+ /** The non-nullish constituents of `type`. */
29
+ function constituents(type, t) {
30
+ const members = type.isUnion() ? type.types : [type];
31
+ return members.filter((m) => (m.flags & (t.TypeFlags.Null | t.TypeFlags.Undefined | t.TypeFlags.Void)) === 0);
32
+ }
33
+ /** A decoded East struct: an object type East's `ValueTypeOf` mapped type declares. */
34
+ function isStructConstituent(type, t) {
35
+ return (type.symbol?.declarations ?? []).some((d) => t.isMappedTypeNode(d) && declaredByEast(d));
36
+ }
37
+ /** A decoded East variant (an option is one): an object type carrying East's `[variant_symbol]`. */
38
+ function isVariantConstituent(type, checker) {
39
+ if ((type.flags & 1 /* Any */) !== 0)
40
+ return false;
41
+ for (const prop of checker.getPropertiesOfType(type)) {
42
+ if (!String(prop.escapedName).startsWith("__@variant_symbol"))
43
+ continue;
44
+ if ((prop.declarations ?? []).some(declaredByEast))
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ /** East's own sorted collections. */
50
+ function isSortedConstituent(type) {
51
+ const name = type.symbol?.name;
52
+ return (name === "SortedSet" || name === "SortedMap") && (type.symbol?.declarations ?? []).some(declaredByEast);
53
+ }
54
+ /** Is `type` (or one of its non-nullish members) a decoded East struct, variant
55
+ * or sorted collection? A type with an East `Expr` among its members — a factory's
56
+ * `SubtypeExprOrValue<…>` input — is authoring, not a decoded value. */
57
+ export function isEastValueShape(type, ctx) {
58
+ if (isEastExprType(type))
59
+ return false;
60
+ return constituents(type, ctx.ts).some((m) => isStructConstituent(m, ctx.ts) || isVariantConstituent(m, ctx.checker) || isSortedConstituent(m));
61
+ }
62
+ /** Is `type` a decoded East struct or variant — a value whose properties are its
63
+ * fields, or its tag and payload? */
64
+ function isRecordShape(type, ctx) {
65
+ return constituents(type, ctx.ts).some((m) => isStructConstituent(m, ctx.ts) || isVariantConstituent(m, ctx.checker));
66
+ }
67
+ /** Does JavaScript print a value of `type` differently from East? A String, an
68
+ * Integer (`bigint`) and a Boolean print the same either way; a Float (`5` for
69
+ * East's `5.0`), a DateTime, a Blob and every object do not. */
70
+ export function jsPrintDiffers(type, t) {
71
+ const same = t.TypeFlags.StringLike | t.TypeFlags.BigIntLike | t.TypeFlags.BooleanLike;
72
+ return constituents(type, t).some((m) => (m.flags & same) === 0);
73
+ }
74
+ /** Is `id` JavaScript's own global (`String`, `BigInt`, `Set`, `JSON`, …) — declared
75
+ * by the default library, not shadowed by a local or an import? */
76
+ export function isGlobalBuiltin(id, ctx) {
77
+ const declarations = ctx.checker.getSymbolAtLocation(id)?.declarations ?? [];
78
+ return declarations.length > 0 && declarations.every((d) => {
79
+ const file = d.getSourceFile();
80
+ return ctx.program?.isSourceFileDefaultLibrary(file) ?? /\/typescript\/lib\/lib\.[^/]*\.d\.ts$/.test(file.fileName.replace(/\\/g, "/"));
81
+ });
82
+ }
83
+ /** Strip the wrappers that leave a value as it is: parentheses, `!`, `as`,
84
+ * `satisfies` and `<T>` assertions. */
85
+ export function skipValueWrappers(e, t) {
86
+ let cur = e;
87
+ for (;;) {
88
+ if (t.isParenthesizedExpression(cur) || t.isNonNullExpression(cur) || t.isAsExpression(cur) || t.isTypeAssertionExpression(cur) || t.isSatisfiesExpression(cur)) {
89
+ cur = cur.expression;
90
+ }
91
+ else {
92
+ return cur;
93
+ }
94
+ }
95
+ }
96
+ /** Methods that read an element out of a collection. */
97
+ const ELEMENT_READS = new Set(["get", "at"]);
98
+ /**
99
+ * Is `e` a decoded East value — typed as an East struct, variant or sorted
100
+ * collection, or read out of one (a field, a payload, an element), or a `const`
101
+ * bound to such a read?
102
+ *
103
+ * @param e - The expression
104
+ * @param ctx - The rule context
105
+ * @returns Whether the expression evaluates to a decoded East value
106
+ */
107
+ export function isEastValueExpression(e, ctx) {
108
+ return eastValueExpression(e, ctx, 0);
109
+ }
110
+ function eastValueExpression(e, ctx, depth) {
111
+ const t = ctx.ts;
112
+ const expr = skipValueWrappers(e, t);
113
+ const type = ctx.checker.getTypeAtLocation(expr);
114
+ // An `Expr`, or a factory input that may be one, is authoring.
115
+ if (isEastExprType(type))
116
+ return false;
117
+ if (isEastValueShape(type, ctx))
118
+ return true;
119
+ // A field of a struct, or a variant's tag and payload.
120
+ if (t.isPropertyAccessExpression(expr)) {
121
+ return isRecordShape(ctx.checker.getTypeAtLocation(expr.expression), ctx);
122
+ }
123
+ // An element of a collection read from an East value.
124
+ if (t.isElementAccessExpression(expr)) {
125
+ return eastValueExpression(expr.expression, ctx, depth);
126
+ }
127
+ if (t.isCallExpression(expr) && t.isPropertyAccessExpression(expr.expression) && ELEMENT_READS.has(expr.expression.name.text)) {
128
+ return eastValueExpression(expr.expression.expression, ctx, depth);
129
+ }
130
+ // A `const` bound to one of the above.
131
+ if (t.isIdentifier(expr) && depth < 3) {
132
+ const decl = ctx.checker.getSymbolAtLocation(expr)?.valueDeclaration;
133
+ if (decl !== undefined && t.isVariableDeclaration(decl) && decl.initializer !== undefined &&
134
+ t.isVariableDeclarationList(decl.parent) && (decl.parent.flags & t.NodeFlags.Const) !== 0) {
135
+ return eastValueExpression(decl.initializer, ctx, depth + 1);
136
+ }
137
+ }
138
+ return false;
139
+ }
140
+ /** Is `call` East's `variant(…)` / `some(…)` — a value constructor its payload
141
+ * flows through? */
142
+ function isValueConstructorCall(call, ctx) {
143
+ const t = ctx.ts;
144
+ const callee = call.expression;
145
+ return t.isIdentifier(callee) && (callee.text === "variant" || callee.text === "some") &&
146
+ resolvesToEastImport(callee, ctx.checker, t);
147
+ }
148
+ /** The type of the parameter `call`'s argument `index` binds — a rest
149
+ * parameter's element type. */
150
+ function parameterTypeAt(signature, index, call, ctx) {
151
+ const t = ctx.ts;
152
+ const params = signature.getParameters();
153
+ if (params.length === 0)
154
+ return undefined;
155
+ const param = params[Math.min(index, params.length - 1)];
156
+ const type = ctx.checker.getTypeOfSymbolAtLocation(param, call);
157
+ const declaration = param.valueDeclaration;
158
+ if (declaration !== undefined && t.isParameter(declaration) && declaration.dotDotDotToken !== undefined) {
159
+ return ctx.checker.getTypeArguments(type)[0];
160
+ }
161
+ return type;
162
+ }
163
+ /** Follow the value `e` produces to where it lands. */
164
+ function flowOf(e, ctx) {
165
+ const t = ctx.ts;
166
+ if (insideBlockScope(e, ctx))
167
+ return "program";
168
+ let node = e;
169
+ // Whether the value has become part of a decoded East struct or variant.
170
+ let east = false;
171
+ for (;;) {
172
+ const parent = node.parent;
173
+ if (parent === undefined)
174
+ return east ? "value" : "host";
175
+ if (t.isParenthesizedExpression(parent) || t.isAsExpression(parent) || t.isSatisfiesExpression(parent) ||
176
+ t.isNonNullExpression(parent) || t.isTypeAssertionExpression(parent) ||
177
+ t.isArrayLiteralExpression(parent) || t.isSpreadElement(parent)) {
178
+ node = parent;
179
+ continue;
180
+ }
181
+ if ((t.isPropertyAssignment(parent) && parent.initializer === node) || t.isShorthandPropertyAssignment(parent)) {
182
+ const literal = parent.parent;
183
+ const contextual = ctx.checker.getContextualType(literal);
184
+ if (contextual !== undefined && isRecordShape(contextual, ctx))
185
+ east = true;
186
+ node = literal;
187
+ continue;
188
+ }
189
+ const args = (t.isCallExpression(parent) || t.isNewExpression(parent)) ? parent.arguments ?? [] : [];
190
+ if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && args.includes(node)) {
191
+ if (t.isCallExpression(parent) && isValueConstructorCall(parent, ctx)) {
192
+ east = true;
193
+ node = parent;
194
+ continue;
195
+ }
196
+ const signature = ctx.checker.getResolvedSignature(parent);
197
+ const declaration = signature?.getDeclaration();
198
+ if (signature !== undefined && declaration !== undefined && declaredByEastPackage(declaration)) {
199
+ // A parameter that takes an `Expr` takes authoring input; one that takes a
200
+ // decoded value — an East function value's, an encoder's — takes a value.
201
+ const index = args.indexOf(node);
202
+ const param = parameterTypeAt(signature, index, parent, ctx);
203
+ return param !== undefined && isEastExprType(param) ? "program" : "value";
204
+ }
205
+ return east ? "value" : "host";
206
+ }
207
+ return east ? "value" : "host";
208
+ }
209
+ }
210
+ /**
211
+ * Does `e` land in a decoded East value — an argument to an East function value
212
+ * or a utility over decoded values (an encoder, a comparer), a field of a decoded
213
+ * struct, a variant's payload — rather than in an East program (authored input
214
+ * East converts through its type) or in host code?
215
+ *
216
+ * @param e - The expression
217
+ * @param ctx - The rule context
218
+ * @returns Whether the value `e` produces becomes (part of) a decoded East value
219
+ */
220
+ export function landsInEastSlot(e, ctx) {
221
+ return flowOf(e, ctx) === "value";
222
+ }
223
+ //# sourceMappingURL=east-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"east-value.js","sourceRoot":"","sources":["../../src/east-value.ts"],"names":[],"mappings":"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"}
@@ -30,5 +30,23 @@ export { noHostComparisonOnEastValues } from "./no-host-comparison-on-east-value
30
30
  export { requireExampleReturns } from "./require-example-returns.js";
31
31
  export { noDuplicateDefinitionName } from "./no-duplicate-definition-name.js";
32
32
  export { noInlineCredentials } from "./no-inline-credentials.js";
33
+ export { noHostPrintOfEastValues } from "./no-host-print-of-east-values.js";
34
+ export { noHostParseToEastValues } from "./no-host-parse-to-east-values.js";
35
+ export { noJsTypeDispatchOnEastValues } from "./no-js-type-dispatch-on-east-values.js";
36
+ export { noJsCollectionForEastCollection } from "./no-js-collection-for-east-collection.js";
33
37
  export declare const allRules: readonly EastRule[];
38
+ /**
39
+ * The rules over host code that builds or holds DECODED East values (#963): build
40
+ * variants and options with East's constructors, and print, read, dispatch on,
41
+ * collect, compare and type values through East. The set the UI packages' source
42
+ * and tests run with `only`: their code handles values, and where it builds East
43
+ * programs (a factory, a handle builder) it is the library the IR-authoring rules
44
+ * are written for, not a program they check.
45
+ *
46
+ * Plain names, so a bundle importing anything else from this package leaves the
47
+ * rules out: mapped from the rule objects at load, the list is a call a bundler
48
+ * must keep, and every plugin hook carried all eight. The spec checks each name
49
+ * is a rule's.
50
+ */
51
+ export declare const hostValueRuleNames: readonly string[];
34
52
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA6B5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,eAAO,MAAM,QAAQ,EAAE,SAAS,QAAQ,EAkCvC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAiC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAE5F,eAAO,MAAM,QAAQ,EAAE,SAAS,QAAQ,EAyCvC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAS/C,CAAC"}
@@ -25,6 +25,10 @@ import { noHostComparisonOnEastValues } from "./no-host-comparison-on-east-value
25
25
  import { requireExampleReturns } from "./require-example-returns.js";
26
26
  import { noDuplicateDefinitionName } from "./no-duplicate-definition-name.js";
27
27
  import { noInlineCredentials } from "./no-inline-credentials.js";
28
+ import { noHostPrintOfEastValues } from "./no-host-print-of-east-values.js";
29
+ import { noHostParseToEastValues } from "./no-host-parse-to-east-values.js";
30
+ import { noJsTypeDispatchOnEastValues } from "./no-js-type-dispatch-on-east-values.js";
31
+ import { noJsCollectionForEastCollection } from "./no-js-collection-for-east-collection.js";
28
32
  export { noRedundantEastCast } from "./no-redundant-east-cast.js";
29
33
  export { preferExplicitEastType } from "./prefer-explicit-east-type.js";
30
34
  export { preferSomeNone } from "./prefer-some-none.js";
@@ -52,6 +56,10 @@ export { noHostComparisonOnEastValues } from "./no-host-comparison-on-east-value
52
56
  export { requireExampleReturns } from "./require-example-returns.js";
53
57
  export { noDuplicateDefinitionName } from "./no-duplicate-definition-name.js";
54
58
  export { noInlineCredentials } from "./no-inline-credentials.js";
59
+ export { noHostPrintOfEastValues } from "./no-host-print-of-east-values.js";
60
+ export { noHostParseToEastValues } from "./no-host-parse-to-east-values.js";
61
+ export { noJsTypeDispatchOnEastValues } from "./no-js-type-dispatch-on-east-values.js";
62
+ export { noJsCollectionForEastCollection } from "./no-js-collection-for-east-collection.js";
55
63
  export const allRules = [
56
64
  // East-side idiom hygiene (original set)
57
65
  noRedundantEastCast,
@@ -86,5 +94,35 @@ export const allRules = [
86
94
  noDuplicateDefinitionName,
87
95
  // secrets hygiene: IR is content-addressed and replicated — no literal creds
88
96
  noInlineCredentials,
97
+ // host code holding DECODED East values: print, read, dispatch and collect
98
+ // them through East (#963) — with noHostComparisonOnEastValues and
99
+ // noHandrolledValueTypeMirror above
100
+ noHostPrintOfEastValues,
101
+ noHostParseToEastValues,
102
+ noJsTypeDispatchOnEastValues,
103
+ noJsCollectionForEastCollection,
104
+ ];
105
+ /**
106
+ * The rules over host code that builds or holds DECODED East values (#963): build
107
+ * variants and options with East's constructors, and print, read, dispatch on,
108
+ * collect, compare and type values through East. The set the UI packages' source
109
+ * and tests run with `only`: their code handles values, and where it builds East
110
+ * programs (a factory, a handle builder) it is the library the IR-authoring rules
111
+ * are written for, not a program they check.
112
+ *
113
+ * Plain names, so a bundle importing anything else from this package leaves the
114
+ * rules out: mapped from the rule objects at load, the list is a call a bundler
115
+ * must keep, and every plugin hook carried all eight. The spec checks each name
116
+ * is a rule's.
117
+ */
118
+ export const hostValueRuleNames = [
119
+ "prefer-some-none",
120
+ "no-handrolled-variant",
121
+ "no-host-print-of-east-values",
122
+ "no-host-parse-to-east-values",
123
+ "no-js-type-dispatch-on-east-values",
124
+ "no-js-collection-for-east-collection",
125
+ "no-host-comparison-on-east-values",
126
+ "no-handrolled-value-type-mirror",
89
127
  ];
90
128
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-handrolled-value-type-mirror.d.ts","sourceRoot":"","sources":["../../../src/rules/no-handrolled-value-type-mirror.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,aAAa,CAAC;AAoCzD,eAAO,MAAM,2BAA2B,EAAE,QAiCzC,CAAC"}
1
+ {"version":3,"file":"no-handrolled-value-type-mirror.d.ts","sourceRoot":"","sources":["../../../src/rules/no-handrolled-value-type-mirror.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAyB,MAAM,aAAa,CAAC;AAyGnE,eAAO,MAAM,2BAA2B,EAAE,QAuCzC,CAAC"}
@@ -1,4 +1,5 @@
1
- import { importsEastPackage } from "../east-source.js";
1
+ import { importsEastPackage, resolvesToEastImport } from "../east-source.js";
2
+ import { isEastValueShape } from "../east-value.js";
2
3
  const NAME = "no-handrolled-value-type-mirror";
3
4
  const CODE = 990028;
4
5
  /** Is there a VALUE binding named `name` in this file (import or top-level
@@ -29,44 +30,116 @@ function eastTypeValueInFile(name, ctx) {
29
30
  }
30
31
  return false;
31
32
  }
32
- // A hand-authored TS `interface Foo { … }` next to an East type value `FooType`
33
- // is a parallel MIRROR of the decoded value shape — it drifts silently the
34
- // moment the East type gains a field, and no compiler complains (a renderer
35
- // shipped with three missing config fields exactly this way). Decoded shapes
36
- // must be DERIVED: `type Foo = ValueTypeOf<typeof FooType>`.
33
+ /** The member signatures of an interface or type literal. */
34
+ function membersOf(node) {
35
+ return node.members;
36
+ }
37
+ /** Does a type node mention an `@elaraai/*` import anywhere inside it? */
38
+ function mentionsEastImport(typeNode, ctx) {
39
+ const t = ctx.ts;
40
+ let found = false;
41
+ const visit = (n) => {
42
+ if (found)
43
+ return;
44
+ if (t.isTypeReferenceNode(n)) {
45
+ const name = t.isIdentifier(n.typeName) ? n.typeName : t.isQualifiedName(n.typeName) ? leftmost(n.typeName, t) : undefined;
46
+ if (name !== undefined && resolvesToEastImport(name, ctx.checker, t)) {
47
+ found = true;
48
+ return;
49
+ }
50
+ }
51
+ t.forEachChild(n, visit);
52
+ };
53
+ visit(typeNode);
54
+ return found;
55
+ }
56
+ function leftmost(q, t) {
57
+ let cur = q;
58
+ while (t.isQualifiedName(cur))
59
+ cur = cur.left;
60
+ return cur;
61
+ }
62
+ /** Is some member of `shape` typed as a decoded East value — a variant, a struct,
63
+ * a sorted collection — however its type is spelled? */
64
+ function holdsEastValue(shape, ctx) {
65
+ const t = ctx.ts;
66
+ return membersOf(shape).some((m) => t.isPropertySignature(m) && m.type !== undefined &&
67
+ isEastValueShape(ctx.checker.getTypeFromTypeNode(m.type), ctx));
68
+ }
69
+ /** A factory's options interface — members typed `SubtypeExprOrValue<…>` /
70
+ * `ExprType<…>` — describes what an author passes IN, not a decoded value. */
71
+ function isFactoryInput(node, ctx) {
72
+ const t = ctx.ts;
73
+ const sf = ctx.sourceFile;
74
+ return membersOf(node).some((m) => {
75
+ const type = t.isPropertySignature(m) ? m.type : undefined;
76
+ return type !== undefined && /\b(?:SubtypeExprOrValue|ExprType)</.test(type.getText(sf));
77
+ });
78
+ }
79
+ /** A `{ type: …; value: … }` type literal — a variant's shape written by hand. */
80
+ function isVariantShapedLiteral(node, t) {
81
+ if (!t.isTypeLiteralNode(node))
82
+ return false;
83
+ const names = new Set(node.members.flatMap((m) => (m.name !== undefined && t.isIdentifier(m.name) ? [m.name.text] : [])));
84
+ return names.has("type") && names.has("value");
85
+ }
86
+ function report(ctx, node, messageText) {
87
+ const start = node.getStart(ctx.sourceFile);
88
+ ctx.report({ ruleName: NAME, code: CODE, start, length: node.getEnd() - start, messageText, category: "suggestion" });
89
+ }
90
+ // A hand-authored TS type next to the East type it describes is a parallel
91
+ // MIRROR of the decoded value shape — it drifts silently the moment the East type
92
+ // gains a field, and no compiler complains (a renderer shipped with three missing
93
+ // config fields exactly this way). Decoded shapes must be DERIVED:
94
+ // `type Foo = ValueTypeOf<typeof FooType>`. Three spellings are caught:
95
+ //
96
+ // - `interface Foo` / `type FooValue = { … }` beside an in-scope `FooType`;
97
+ // - a `*Like` interface or type literal built from East types (`StateLike`);
98
+ // - an `as { type: …; value: … }` assertion — a variant's shape written by hand.
99
+ //
100
+ // A factory's options interface (`SubtypeExprOrValue<…>` members) is an input,
101
+ // not a decoded mirror, and is left alone.
37
102
  export const noHandrolledValueTypeMirror = {
38
103
  name: NAME,
39
104
  code: CODE,
40
- description: "A hand-authored interface mirroring an in-scope East type — derive it with ValueTypeOf<typeof XType> instead.",
105
+ description: "A hand-authored type mirroring an East type (Foo beside FooType, a *Like stand-in, an `as { type; value }` assertion) — derive it with ValueTypeOf<typeof XType> instead.",
41
106
  check(node, ctx) {
42
107
  const t = ctx.ts;
108
+ if (t.isAsExpression(node) || t.isTypeAssertionExpression(node)) {
109
+ if (!isVariantShapedLiteral(node.type, t))
110
+ return;
111
+ if (!importsEastPackage(ctx.sourceFile, t))
112
+ return;
113
+ report(ctx, node.type, "This `{ type, value }` assertion hand-mirrors an East variant — it hides the value's real type. Narrow the typed value on its tag (`v.type === …`), or type it with `ValueTypeOf<typeof XType>`.");
114
+ return;
115
+ }
43
116
  let name;
117
+ let shape;
44
118
  if (t.isInterfaceDeclaration(node)) {
45
119
  name = node.name;
120
+ shape = node;
46
121
  }
47
122
  else if (t.isTypeAliasDeclaration(node) && t.isTypeLiteralNode(node.type)) {
48
123
  name = node.name;
124
+ shape = node.type;
49
125
  }
50
- if (name === undefined)
126
+ if (name === undefined || shape === undefined)
51
127
  return;
52
128
  if (!importsEastPackage(ctx.sourceFile, t))
53
129
  return;
130
+ if (isFactoryInput(shape, ctx))
131
+ return;
132
+ if (name.text.length > "Like".length && name.text.endsWith("Like") && (mentionsEastImport(shape, ctx) || holdsEastValue(shape, ctx))) {
133
+ report(ctx, name, `\`${name.text}\` is a loose stand-in for an East value's type — it drifts silently when the East type changes. Type the value with \`ValueTypeOf<typeof XType>\` of the East type it holds.`);
134
+ return;
135
+ }
54
136
  const base = name.text.endsWith("Value") ? name.text.slice(0, -"Value".length) : name.text;
55
137
  const counterpart = `${base}Type`;
56
138
  if (counterpart === name.text)
57
139
  return;
58
140
  if (!eastTypeValueInFile(counterpart, ctx))
59
141
  return;
60
- const sf = ctx.sourceFile;
61
- const start = name.getStart(sf);
62
- ctx.report({
63
- ruleName: NAME,
64
- code: CODE,
65
- start,
66
- length: name.getEnd() - start,
67
- messageText: `\`${name.text}\` hand-mirrors the East type \`${counterpart}\` — it drifts silently when the East type gains a field. Derive it: \`type ${name.text} = ValueTypeOf<typeof ${counterpart}>\`.`,
68
- category: "suggestion",
69
- });
142
+ report(ctx, name, `\`${name.text}\` hand-mirrors the East type \`${counterpart}\` — it drifts silently when the East type gains a field. Derive it: \`type ${name.text} = ValueTypeOf<typeof ${counterpart}>\`.`);
70
143
  },
71
144
  };
72
145
  //# sourceMappingURL=no-handrolled-value-type-mirror.js.map