@elaraai/east-diagnostics 1.0.80 → 1.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -5
- package/dist/src/east-value.d.ts +42 -0
- package/dist/src/east-value.d.ts.map +1 -0
- package/dist/src/east-value.js +223 -0
- package/dist/src/east-value.js.map +1 -0
- package/dist/src/rules/index.d.ts +18 -0
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +38 -0
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/no-handrolled-value-type-mirror.d.ts.map +1 -1
- package/dist/src/rules/no-handrolled-value-type-mirror.js +91 -18
- package/dist/src/rules/no-handrolled-value-type-mirror.js.map +1 -1
- package/dist/src/rules/no-handrolled-variant.d.ts.map +1 -1
- package/dist/src/rules/no-handrolled-variant.js +60 -3
- package/dist/src/rules/no-handrolled-variant.js.map +1 -1
- package/dist/src/rules/no-host-comparison-on-east-values.d.ts.map +1 -1
- package/dist/src/rules/no-host-comparison-on-east-values.js +78 -33
- package/dist/src/rules/no-host-comparison-on-east-values.js.map +1 -1
- package/dist/src/rules/no-host-parse-to-east-values.d.ts +3 -0
- package/dist/src/rules/no-host-parse-to-east-values.d.ts.map +1 -0
- package/dist/src/rules/no-host-parse-to-east-values.js +84 -0
- package/dist/src/rules/no-host-parse-to-east-values.js.map +1 -0
- package/dist/src/rules/no-host-print-of-east-values.d.ts +3 -0
- package/dist/src/rules/no-host-print-of-east-values.d.ts.map +1 -0
- package/dist/src/rules/no-host-print-of-east-values.js +92 -0
- package/dist/src/rules/no-host-print-of-east-values.js.map +1 -0
- package/dist/src/rules/no-js-collection-for-east-collection.d.ts +3 -0
- package/dist/src/rules/no-js-collection-for-east-collection.d.ts.map +1 -0
- package/dist/src/rules/no-js-collection-for-east-collection.js +70 -0
- package/dist/src/rules/no-js-collection-for-east-collection.js.map +1 -0
- package/dist/src/rules/no-js-type-dispatch-on-east-values.d.ts +7 -0
- package/dist/src/rules/no-js-type-dispatch-on-east-values.d.ts.map +1 -0
- package/dist/src/rules/no-js-type-dispatch-on-east-values.js +40 -0
- package/dist/src/rules/no-js-type-dispatch-on-east-values.js.map +1 -0
- package/dist/src/rules/no-module-scope-east-macro.d.ts.map +1 -1
- package/dist/src/rules/no-module-scope-east-macro.js +105 -17
- package/dist/src/rules/no-module-scope-east-macro.js.map +1 -1
- package/dist/src/rules/prefer-some-none.d.ts +0 -4
- package/dist/src/rules/prefer-some-none.d.ts.map +1 -1
- package/dist/src/rules/prefer-some-none.js +75 -4
- package/dist/src/rules/prefer-some-none.js.map +1 -1
- package/dist/src/run.d.ts.map +1 -1
- package/dist/src/run.js +2 -1
- package/dist/src/run.js.map +1 -1
- package/dist/src/types.d.ts +3 -0
- package/dist/src/types.d.ts.map +1 -1
- 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
|
|
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
|
|
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;
|
|
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"}
|
package/dist/src/rules/index.js
CHANGED
|
@@ -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":"AAKA,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;
|
|
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,
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
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
|
-
|
|
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
|