@elaraai/east-diagnostics 1.0.13 → 1.0.15
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 +21 -4
- package/dist/src/east-ir.d.ts +23 -0
- package/dist/src/east-ir.d.ts.map +1 -0
- package/dist/src/east-ir.js +55 -0
- package/dist/src/east-ir.js.map +1 -0
- package/dist/src/east-source.d.ts +18 -0
- package/dist/src/east-source.d.ts.map +1 -0
- package/dist/src/east-source.js +68 -0
- package/dist/src/east-source.js.map +1 -0
- package/dist/src/rules/index.d.ts +4 -1
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +16 -3
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/no-compile-time-data-injection.d.ts +3 -0
- package/dist/src/rules/no-compile-time-data-injection.d.ts.map +1 -0
- package/dist/src/rules/no-compile-time-data-injection.js +107 -0
- package/dist/src/rules/no-compile-time-data-injection.js.map +1 -0
- package/dist/src/rules/no-compile-time-seed-data.d.ts +3 -0
- package/dist/src/rules/no-compile-time-seed-data.d.ts.map +1 -0
- package/dist/src/rules/no-compile-time-seed-data.js +209 -0
- package/dist/src/rules/no-compile-time-seed-data.js.map +1 -0
- package/dist/src/rules/no-host-in-east-block.d.ts +3 -0
- package/dist/src/rules/no-host-in-east-block.d.ts.map +1 -0
- package/dist/src/rules/no-host-in-east-block.js +266 -0
- package/dist/src/rules/no-host-in-east-block.js.map +1 -0
- package/dist/src/rules/no-let-const-in-expression.d.ts.map +1 -1
- package/dist/src/rules/no-let-const-in-expression.js +11 -10
- package/dist/src/rules/no-let-const-in-expression.js.map +1 -1
- package/dist/src/rules/no-module-scope-east-macro.d.ts +3 -0
- package/dist/src/rules/no-module-scope-east-macro.d.ts.map +1 -0
- package/dist/src/rules/no-module-scope-east-macro.js +150 -0
- package/dist/src/rules/no-module-scope-east-macro.js.map +1 -0
- package/dist/src/rules/no-redundant-east-cast.d.ts.map +1 -1
- package/dist/src/rules/no-redundant-east-cast.js +62 -24
- package/dist/src/rules/no-redundant-east-cast.js.map +1 -1
- package/dist/src/rules/no-relative-src-import.d.ts.map +1 -1
- package/dist/src/rules/no-relative-src-import.js +9 -2
- package/dist/src/rules/no-relative-src-import.js.map +1 -1
- package/dist/src/rules/no-unexecuted-east-expression.d.ts +4 -0
- package/dist/src/rules/no-unexecuted-east-expression.d.ts.map +1 -1
- package/dist/src/rules/no-unexecuted-east-expression.js +2 -12
- package/dist/src/rules/no-unexecuted-east-expression.js.map +1 -1
- package/dist/src/tsserver-plugin.d.ts +4 -0
- package/dist/src/tsserver-plugin.d.ts.map +1 -1
- package/dist/src/tsserver-plugin.js +15 -42
- package/dist/src/tsserver-plugin.js.map +1 -1
- package/package.json +3 -2
- package/dist/src/rules/no-east-data-builder-helper.d.ts +0 -3
- package/dist/src/rules/no-east-data-builder-helper.d.ts.map +0 -1
- package/dist/src/rules/no-east-data-builder-helper.js +0 -90
- package/dist/src/rules/no-east-data-builder-helper.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,6 +11,12 @@ write-time (the Claude plugin daemon) and to developers in the editor and CI
|
|
|
11
11
|
([`@elaraai/eslint-plugin-east`](../eslint-plugin-east)). The rules run against a
|
|
12
12
|
real `ts.Program`, so they are type-aware, not regex heuristics.
|
|
13
13
|
|
|
14
|
+
Every rule **self-gates on East-ness** — it fires only where there is genuine East
|
|
15
|
+
code (an East type/block, an `e3` construct, or an `@elaraai/*` import), so the set
|
|
16
|
+
is opt-in by installation and inert on plain TypeScript. There is no
|
|
17
|
+
package-identity allow/deny list; per-project suppression is the `disabled` option,
|
|
18
|
+
like any linter.
|
|
19
|
+
|
|
14
20
|
## Features
|
|
15
21
|
|
|
16
22
|
- **Shared rule set** - One engine, `runEastRules(ts, program, sourceFile, checker)`, reused across every surface.
|
|
@@ -23,18 +29,29 @@ real `ts.Program`, so they are type-aware, not regex heuristics.
|
|
|
23
29
|
|
|
24
30
|
## Rules
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
### East-side idiom hygiene
|
|
33
|
+
|
|
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.
|
|
27
35
|
- **`prefer-explicit-east-type`** - One-arg `$.let`/`$.const` on an under-determined value (`[]`, `{}`, `new Map()`).
|
|
28
36
|
- **`prefer-some-none`** - `variant("some"/"none", …)` instead of `some()` / `none`.
|
|
29
37
|
- **`no-handrolled-variant`** - A plain object literal where an East variant/option is expected.
|
|
30
38
|
- **`no-east-namespaced-type`** - `East.IntegerType` etc. instead of a bare import.
|
|
31
39
|
- **`prefer-let-const-over-east-value`** - `East.value(…)` declared or returned inside an `East.function` block.
|
|
32
|
-
- **`no-relative-src-import`** - Importing `../src/…` instead of
|
|
33
|
-
- **`no-let-const-in-expression`** -
|
|
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.)
|
|
41
|
+
- **`no-let-const-in-expression`** - `$.let`/`$.const` used anywhere other than a `const`/`let` initializer, a bare statement, a `return`, or a concise arrow body (e.g. a struct-field value, array element, call argument, or chain target buries the declaration in an expression).
|
|
34
42
|
- **`no-unexecuted-east-expression`** - A bare East expression statement that is never executed with `$( … )` or bound.
|
|
35
43
|
- **`no-reinlined-east-binding`** - An East `Expr` bound to a JS `const`/`let` and reused inside a block is re-inlined per use — bind it once with `$.let`/`$.const`.
|
|
36
|
-
- **`no-east-data-builder-helper`** - A TS helper whose only job is to return a hand-built East value — inline it or make it a real `East.function`.
|
|
37
44
|
- **`prefer-jsx-over-factory-call`** - In a `.tsx` file, a factory's `Foo.Root(...)` whose result is a JSX element — author it with the `<Foo>` tag instead.
|
|
45
|
+
- **`no-untracked-east-data`** - A bare JS `const` literal consumed in an East-typed position inside a block — bind it with `$.const`/`$.let`.
|
|
46
|
+
|
|
47
|
+
### Host-vs-East
|
|
48
|
+
|
|
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
|
+
|
|
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.
|
|
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
|
+
- **`no-compile-time-seed-data`** - Host-computed data passed as the seed (3rd arg) of `e3.input(name, type, 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`).
|
|
38
55
|
|
|
39
56
|
## Usage
|
|
40
57
|
|
|
@@ -0,0 +1,23 @@
|
|
|
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 } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Walk a call/member chain down to its base receiver — `a.b().c[d]` -> `a`. Used
|
|
9
|
+
* to find the thing a chained expression is ultimately rooted on (e.g. to ask
|
|
10
|
+
* whether a `$.if(...).else(...)` chain is rooted on the block builder `$`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function chainRootReceiver(node: ts.Node, ctx: RuleContext): ts.Node;
|
|
13
|
+
/**
|
|
14
|
+
* Does `body` EMIT East IR into the enclosing block — i.e. contain a call rooted
|
|
15
|
+
* on the block builder `$` (`$.let`/`$.const`/`$(…)`/`$.assign`/`$.if`/…)? This
|
|
16
|
+
* is the discriminator between a host loop that BUILDS East IR (abuse) and one
|
|
17
|
+
* that only assembles a plain JS array/object (legitimate — the array is bound
|
|
18
|
+
* once afterwards). It deliberately does NOT count mere East-`Expr` reads
|
|
19
|
+
* (`p.x.get(k)` inside a `jsArray.push({...})`), and does not descend into a
|
|
20
|
+
* nested East block callback (`data.map(($, x) => …)`) — that is its own scope.
|
|
21
|
+
*/
|
|
22
|
+
export declare function bodyBuildsEastIr(body: ts.Node, ctx: RuleContext): boolean;
|
|
23
|
+
//# sourceMappingURL=east-ir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"east-ir.d.ts","sourceRoot":"","sources":["../../src/east-ir.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,GAAG,EAAE,CAAC,IAAI,CAW1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAsBzE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { isBlockBuilderType } from "./east-type.js";
|
|
2
|
+
import { matchBlockBuilderCall } from "./block-builder.js";
|
|
3
|
+
import { isBlockBuilderCallback } from "./block-scope.js";
|
|
4
|
+
/**
|
|
5
|
+
* Walk a call/member chain down to its base receiver — `a.b().c[d]` -> `a`. Used
|
|
6
|
+
* to find the thing a chained expression is ultimately rooted on (e.g. to ask
|
|
7
|
+
* whether a `$.if(...).else(...)` chain is rooted on the block builder `$`).
|
|
8
|
+
*/
|
|
9
|
+
export function chainRootReceiver(node, ctx) {
|
|
10
|
+
const t = ctx.ts;
|
|
11
|
+
let root = node;
|
|
12
|
+
for (;;) {
|
|
13
|
+
if (t.isCallExpression(root))
|
|
14
|
+
root = root.expression;
|
|
15
|
+
else if (t.isPropertyAccessExpression(root) || t.isElementAccessExpression(root)) {
|
|
16
|
+
root = root.expression;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
return root;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Does `body` EMIT East IR into the enclosing block — i.e. contain a call rooted
|
|
25
|
+
* on the block builder `$` (`$.let`/`$.const`/`$(…)`/`$.assign`/`$.if`/…)? This
|
|
26
|
+
* is the discriminator between a host loop that BUILDS East IR (abuse) and one
|
|
27
|
+
* that only assembles a plain JS array/object (legitimate — the array is bound
|
|
28
|
+
* once afterwards). It deliberately does NOT count mere East-`Expr` reads
|
|
29
|
+
* (`p.x.get(k)` inside a `jsArray.push({...})`), and does not descend into a
|
|
30
|
+
* nested East block callback (`data.map(($, x) => …)`) — that is its own scope.
|
|
31
|
+
*/
|
|
32
|
+
export function bodyBuildsEastIr(body, ctx) {
|
|
33
|
+
const t = ctx.ts;
|
|
34
|
+
let found = false;
|
|
35
|
+
const visit = (n) => {
|
|
36
|
+
if (found)
|
|
37
|
+
return;
|
|
38
|
+
// A nested East block callback (`($, x) => …`) is its own scope — emissions
|
|
39
|
+
// inside it belong to that East collection op, not to the host loop.
|
|
40
|
+
if (isBlockBuilderCallback(n, ctx))
|
|
41
|
+
return;
|
|
42
|
+
if (t.isCallExpression(n)) {
|
|
43
|
+
// `$.let(...)` / `$.const(...)`, or anything rooted on the builder `$`.
|
|
44
|
+
if (matchBlockBuilderCall(n, ctx) !== undefined ||
|
|
45
|
+
isBlockBuilderType(ctx.checker.getTypeAtLocation(chainRootReceiver(n.expression, ctx)))) {
|
|
46
|
+
found = true;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
t.forEachChild(n, visit);
|
|
51
|
+
};
|
|
52
|
+
visit(body);
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=east-ir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"east-ir.js","sourceRoot":"","sources":["../../src/east-ir.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa,EAAE,GAAgB;IAC/D,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;IACjB,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,SAAS,CAAC;QACR,IAAI,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;aAChD,IAAI,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC;YACjF,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa,EAAE,GAAgB;IAC9D,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;IACjB,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,KAAK,GAAG,CAAC,CAAU,EAAQ,EAAE;QACjC,IAAI,KAAK;YAAE,OAAO;QAClB,4EAA4E;QAC5E,qEAAqE;QACrE,IAAI,sBAAsB,CAAC,CAAC,EAAE,GAAG,CAAC;YAAE,OAAO;QAC3C,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1B,wEAAwE;YACxE,IACE,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,SAAS;gBAC3C,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,EACvF,CAAC;gBACD,KAAK,GAAG,IAAI,CAAC;gBACb,OAAO;YACT,CAAC;QACH,CAAC;QACD,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
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 { TsModule } from "./types.js";
|
|
7
|
+
/** Does this source file statically import or re-export from any `@elaraai/*`
|
|
8
|
+
* package? — the signal that it is East/e3 source rather than plain TypeScript.
|
|
9
|
+
* Cached per source file. */
|
|
10
|
+
export declare function importsEastPackage(sf: ts.SourceFile, t: TsModule): boolean;
|
|
11
|
+
/** Does a relative `../src`-style import specifier resolve WITHIN the importing
|
|
12
|
+
* file's own package? A package's own spec/example importing `../src/index.js` is
|
|
13
|
+
* the one legitimate relative-`src` import — it cannot import its own published
|
|
14
|
+
* name — whereas reaching into ANOTHER package's `src` should use that package's
|
|
15
|
+
* published name. Conservative (treats as own-package, i.e. allowed) if the
|
|
16
|
+
* filesystem can't be consulted. */
|
|
17
|
+
export declare function resolvesWithinOwnPackage(sourceFileName: string, specifierText: string): boolean;
|
|
18
|
+
//# sourceMappingURL=east-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"east-source.d.ts","sourceRoot":"","sources":["../../src/east-source.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C;;6BAE6B;AAC7B,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAc1E;AAuBD;;;;;oCAKoC;AACpC,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAS/F"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
// File-level "is this East/e3 source?" detection. Several rules describe abuses
|
|
4
|
+
// that only make sense inside an East/e3 program (baking build-time data, building
|
|
5
|
+
// East IR in a module-scope macro); gating them on a real `@elaraai/*` import keeps
|
|
6
|
+
// them from firing on ordinary TypeScript, so the rule set is opt-in by install AND
|
|
7
|
+
// self-gating by East-ness — no package-identity allow/deny list needed.
|
|
8
|
+
const importsCache = new WeakMap();
|
|
9
|
+
/** Does this source file statically import or re-export from any `@elaraai/*`
|
|
10
|
+
* package? — the signal that it is East/e3 source rather than plain TypeScript.
|
|
11
|
+
* Cached per source file. */
|
|
12
|
+
export function importsEastPackage(sf, t) {
|
|
13
|
+
const cached = importsCache.get(sf);
|
|
14
|
+
if (cached !== undefined)
|
|
15
|
+
return cached;
|
|
16
|
+
let found = false;
|
|
17
|
+
for (const stmt of sf.statements) {
|
|
18
|
+
if (!t.isImportDeclaration(stmt) && !t.isExportDeclaration(stmt))
|
|
19
|
+
continue;
|
|
20
|
+
const spec = stmt.moduleSpecifier;
|
|
21
|
+
if (spec !== undefined && t.isStringLiteral(spec) && spec.text.startsWith("@elaraai/")) {
|
|
22
|
+
found = true;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
importsCache.set(sf, found);
|
|
27
|
+
return found;
|
|
28
|
+
}
|
|
29
|
+
const pkgDirCache = new Map();
|
|
30
|
+
/** The nearest ancestor directory of `p` containing a `package.json`, or undefined. */
|
|
31
|
+
function packageDirOf(p) {
|
|
32
|
+
const start = dirname(resolve(p));
|
|
33
|
+
if (pkgDirCache.has(start))
|
|
34
|
+
return pkgDirCache.get(start);
|
|
35
|
+
let dir = start;
|
|
36
|
+
let result;
|
|
37
|
+
for (;;) {
|
|
38
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
39
|
+
result = dir;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
const parent = dirname(dir);
|
|
43
|
+
if (parent === dir)
|
|
44
|
+
break;
|
|
45
|
+
dir = parent;
|
|
46
|
+
}
|
|
47
|
+
pkgDirCache.set(start, result);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/** Does a relative `../src`-style import specifier resolve WITHIN the importing
|
|
51
|
+
* file's own package? A package's own spec/example importing `../src/index.js` is
|
|
52
|
+
* the one legitimate relative-`src` import — it cannot import its own published
|
|
53
|
+
* name — whereas reaching into ANOTHER package's `src` should use that package's
|
|
54
|
+
* published name. Conservative (treats as own-package, i.e. allowed) if the
|
|
55
|
+
* filesystem can't be consulted. */
|
|
56
|
+
export function resolvesWithinOwnPackage(sourceFileName, specifierText) {
|
|
57
|
+
try {
|
|
58
|
+
const own = packageDirOf(sourceFileName);
|
|
59
|
+
if (own === undefined)
|
|
60
|
+
return false;
|
|
61
|
+
const targetAbs = resolve(dirname(sourceFileName), specifierText);
|
|
62
|
+
return packageDirOf(targetAbs) === own;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=east-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"east-source.js","sourceRoot":"","sources":["../../src/east-source.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGnD,gFAAgF;AAChF,mFAAmF;AACnF,oFAAoF;AACpF,oFAAoF;AACpF,yEAAyE;AAEzE,MAAM,YAAY,GAAG,IAAI,OAAO,EAA0B,CAAC;AAE3D;;6BAE6B;AAC7B,MAAM,UAAU,kBAAkB,CAAC,EAAiB,EAAE,CAAW;IAC/D,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC;YAAE,SAAS;QAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACvF,KAAK,GAAG,IAAI,CAAC;YACb,MAAM;QACR,CAAC;IACH,CAAC;IACD,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAA8B,CAAC;AAE1D,uFAAuF;AACvF,SAAS,YAAY,CAAC,CAAS;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,IAAI,MAA0B,CAAC;IAC/B,SAAS,CAAC;QACR,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,CAAC;YACb,MAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;oCAKoC;AACpC,MAAM,UAAU,wBAAwB,CAAC,cAAsB,EAAE,aAAqB;IACpF,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;QACzC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,CAAC;QAClE,OAAO,YAAY,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -13,8 +13,11 @@ export { noRelativeSrcImport } from "./no-relative-src-import.js";
|
|
|
13
13
|
export { noLetConstInExpression } from "./no-let-const-in-expression.js";
|
|
14
14
|
export { noUnexecutedEastExpression } from "./no-unexecuted-east-expression.js";
|
|
15
15
|
export { noReinlinedEastBinding } from "./no-reinlined-east-binding.js";
|
|
16
|
-
export { noEastDataBuilderHelper } from "./no-east-data-builder-helper.js";
|
|
17
16
|
export { preferJsxOverFactoryCall } from "./prefer-jsx-over-factory-call.js";
|
|
18
17
|
export { noUntrackedEastData } from "./no-untracked-east-data.js";
|
|
18
|
+
export { noCompileTimeDataInjection } from "./no-compile-time-data-injection.js";
|
|
19
|
+
export { noCompileTimeSeedData } from "./no-compile-time-seed-data.js";
|
|
20
|
+
export { noHostInEastBlock } from "./no-host-in-east-block.js";
|
|
21
|
+
export { noModuleScopeEastMacro } from "./no-module-scope-east-macro.js";
|
|
19
22
|
export declare const allRules: readonly EastRule[];
|
|
20
23
|
//# 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;AAkB5C,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;AAEzE,eAAO,MAAM,QAAQ,EAAE,SAAS,QAAQ,EAqBvC,CAAC"}
|
package/dist/src/rules/index.js
CHANGED
|
@@ -8,9 +8,12 @@ import { noRelativeSrcImport } from "./no-relative-src-import.js";
|
|
|
8
8
|
import { noLetConstInExpression } from "./no-let-const-in-expression.js";
|
|
9
9
|
import { noUnexecutedEastExpression } from "./no-unexecuted-east-expression.js";
|
|
10
10
|
import { noReinlinedEastBinding } from "./no-reinlined-east-binding.js";
|
|
11
|
-
import { noEastDataBuilderHelper } from "./no-east-data-builder-helper.js";
|
|
12
11
|
import { preferJsxOverFactoryCall } from "./prefer-jsx-over-factory-call.js";
|
|
13
12
|
import { noUntrackedEastData } from "./no-untracked-east-data.js";
|
|
13
|
+
import { noCompileTimeDataInjection } from "./no-compile-time-data-injection.js";
|
|
14
|
+
import { noCompileTimeSeedData } from "./no-compile-time-seed-data.js";
|
|
15
|
+
import { noHostInEastBlock } from "./no-host-in-east-block.js";
|
|
16
|
+
import { noModuleScopeEastMacro } from "./no-module-scope-east-macro.js";
|
|
14
17
|
export { noRedundantEastCast } from "./no-redundant-east-cast.js";
|
|
15
18
|
export { preferExplicitEastType } from "./prefer-explicit-east-type.js";
|
|
16
19
|
export { preferSomeNone } from "./prefer-some-none.js";
|
|
@@ -21,10 +24,14 @@ export { noRelativeSrcImport } from "./no-relative-src-import.js";
|
|
|
21
24
|
export { noLetConstInExpression } from "./no-let-const-in-expression.js";
|
|
22
25
|
export { noUnexecutedEastExpression } from "./no-unexecuted-east-expression.js";
|
|
23
26
|
export { noReinlinedEastBinding } from "./no-reinlined-east-binding.js";
|
|
24
|
-
export { noEastDataBuilderHelper } from "./no-east-data-builder-helper.js";
|
|
25
27
|
export { preferJsxOverFactoryCall } from "./prefer-jsx-over-factory-call.js";
|
|
26
28
|
export { noUntrackedEastData } from "./no-untracked-east-data.js";
|
|
29
|
+
export { noCompileTimeDataInjection } from "./no-compile-time-data-injection.js";
|
|
30
|
+
export { noCompileTimeSeedData } from "./no-compile-time-seed-data.js";
|
|
31
|
+
export { noHostInEastBlock } from "./no-host-in-east-block.js";
|
|
32
|
+
export { noModuleScopeEastMacro } from "./no-module-scope-east-macro.js";
|
|
27
33
|
export const allRules = [
|
|
34
|
+
// East-side idiom hygiene (original set)
|
|
28
35
|
noRedundantEastCast,
|
|
29
36
|
preferExplicitEastType,
|
|
30
37
|
preferSomeNone,
|
|
@@ -35,8 +42,14 @@ export const allRules = [
|
|
|
35
42
|
noLetConstInExpression,
|
|
36
43
|
noUnexecutedEastExpression,
|
|
37
44
|
noReinlinedEastBinding,
|
|
38
|
-
noEastDataBuilderHelper,
|
|
39
45
|
preferJsxOverFactoryCall,
|
|
40
46
|
noUntrackedEastData,
|
|
47
|
+
// host-vs-East family: the general block rule + the module-scope macro rule,
|
|
48
|
+
// plus the separate build-time-data concerns (ingestion primitives, and
|
|
49
|
+
// host-computed e3.input seed data)
|
|
50
|
+
noHostInEastBlock,
|
|
51
|
+
noModuleScopeEastMacro,
|
|
52
|
+
noCompileTimeDataInjection,
|
|
53
|
+
noCompileTimeSeedData,
|
|
41
54
|
];
|
|
42
55
|
//# 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,
|
|
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;AAEzE,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;AAEzE,MAAM,CAAC,MAAM,QAAQ,GAAwB;IAC3C,yCAAyC;IACzC,mBAAmB;IACnB,sBAAsB;IACtB,cAAc;IACd,mBAAmB;IACnB,oBAAoB;IACpB,2BAA2B;IAC3B,mBAAmB;IACnB,sBAAsB;IACtB,0BAA0B;IAC1B,sBAAsB;IACtB,wBAAwB;IACxB,mBAAmB;IACnB,6EAA6E;IAC7E,wEAAwE;IACxE,oCAAoC;IACpC,iBAAiB;IACjB,sBAAsB;IACtB,0BAA0B;IAC1B,qBAAqB;CACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-compile-time-data-injection.d.ts","sourceRoot":"","sources":["../../../src/rules/no-compile-time-data-injection.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAyB,MAAM,aAAa,CAAC;AA6DnE,eAAO,MAAM,0BAA0B,EAAE,QAyDxC,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { insideBlockScope } from "../block-scope.js";
|
|
2
|
+
import { importsEastPackage } from "../east-source.js";
|
|
3
|
+
const NAME = "no-compile-time-data-injection";
|
|
4
|
+
const CODE = 990015;
|
|
5
|
+
const FS_MODULES = new Set(["node:fs", "fs", "node:fs/promises", "fs/promises"]);
|
|
6
|
+
function fire(ctx, target, messageText) {
|
|
7
|
+
const sf = ctx.sourceFile;
|
|
8
|
+
const start = target.getStart(sf);
|
|
9
|
+
ctx.report({ ruleName: NAME, code: CODE, start, length: target.getEnd() - start, messageText, category: "warning" });
|
|
10
|
+
}
|
|
11
|
+
/** The `ImportDeclaration` a symbol's declaration belongs to, if it is imported. */
|
|
12
|
+
function importOfSymbol(sym, t) {
|
|
13
|
+
for (const d of sym?.declarations ?? []) {
|
|
14
|
+
let n = d;
|
|
15
|
+
// ImportSpecifier -> NamedImports -> ImportClause -> ImportDeclaration; a
|
|
16
|
+
// NamespaceImport / ImportClause sit one level higher.
|
|
17
|
+
if (t.isImportSpecifier(n))
|
|
18
|
+
n = n.parent.parent.parent;
|
|
19
|
+
else if (t.isNamespaceImport(n))
|
|
20
|
+
n = n.parent.parent;
|
|
21
|
+
else if (t.isImportClause(n))
|
|
22
|
+
n = n.parent;
|
|
23
|
+
else
|
|
24
|
+
continue;
|
|
25
|
+
if (t.isImportDeclaration(n))
|
|
26
|
+
return n;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** Does `id` resolve to a binding imported from a Node `fs` module? (Type-grounded
|
|
31
|
+
* — follows the symbol to its import, so aliases and namespace imports are caught
|
|
32
|
+
* and an unrelated local `readFileSync` is not.) */
|
|
33
|
+
function resolvesToFsImport(id, ctx) {
|
|
34
|
+
const t = ctx.ts;
|
|
35
|
+
const imp = importOfSymbol(ctx.checker.getSymbolAtLocation(id), t);
|
|
36
|
+
return (imp !== undefined &&
|
|
37
|
+
t.isStringLiteral(imp.moduleSpecifier) &&
|
|
38
|
+
FS_MODULES.has(imp.moduleSpecifier.text));
|
|
39
|
+
}
|
|
40
|
+
function isProcessEnv(node, t) {
|
|
41
|
+
return (t.isPropertyAccessExpression(node) &&
|
|
42
|
+
t.isIdentifier(node.expression) &&
|
|
43
|
+
node.expression.text === "process" &&
|
|
44
|
+
node.name.text === "env");
|
|
45
|
+
}
|
|
46
|
+
// East/e3 source is COMPILED to IR and deployed; importing Node's `fs`, reading
|
|
47
|
+
// files, parsing JSON, or probing `process.env` at module-evaluation time bakes
|
|
48
|
+
// build/deploy-time data into the program. Data belongs at runtime — via
|
|
49
|
+
// `e3.input` / datasets, or an `east-node-io` platform task (`FileSystem.readFile`,
|
|
50
|
+
// `SQL.*`). Detection is type-grounded: a call is flagged when it resolves to a
|
|
51
|
+
// `node:fs` import (so the runtime `FileSystem.readFile(...)` platform form is not
|
|
52
|
+
// matched), and the global `JSON.parse` / `process.env` are matched syntactically.
|
|
53
|
+
// Some seed-time bootstrap (no East-side reader) is unavoidable — then it is an
|
|
54
|
+
// accepted warning, documented at the call site.
|
|
55
|
+
export const noCompileTimeDataInjection = {
|
|
56
|
+
name: NAME,
|
|
57
|
+
code: CODE,
|
|
58
|
+
description: "Flag build-time data ingestion (a node:fs import or call, JSON.parse, process.env) at module scope — load data at runtime via e3.input / datasets / platform tasks.",
|
|
59
|
+
check(node, ctx) {
|
|
60
|
+
const t = ctx.ts;
|
|
61
|
+
// Only an East/e3 source file (one importing `@elaraai/*`) is subject to this —
|
|
62
|
+
// a plain Node script reading files at module scope is none of our business.
|
|
63
|
+
if (!importsEastPackage(ctx.sourceFile, t))
|
|
64
|
+
return;
|
|
65
|
+
// The `import … from "node:fs"` itself.
|
|
66
|
+
if (t.isImportDeclaration(node)) {
|
|
67
|
+
const spec = node.moduleSpecifier;
|
|
68
|
+
if (t.isStringLiteral(spec) && FS_MODULES.has(spec.text)) {
|
|
69
|
+
fire(ctx, node, `Importing \`${spec.text}\` into East/e3 source bakes build-time file I/O into the deployed program. Read data at runtime via \`e3.input\` / a dataset, or an \`east-node-io\` platform task.`);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// All remaining forms are abuse only at module scope (not inside an East
|
|
74
|
+
// block, where the runtime platform forms legitimately run).
|
|
75
|
+
if (insideBlockScope(node, ctx))
|
|
76
|
+
return;
|
|
77
|
+
// `process.env` probe — fire once on the bare `process.env` access (the outer
|
|
78
|
+
// `process.env.X` / `process.env["X"]` has it as its receiver, so reporting the
|
|
79
|
+
// base fires exactly once per occurrence).
|
|
80
|
+
if (isProcessEnv(node, t)) {
|
|
81
|
+
fire(ctx, node, "Reading `process.env` at module scope couples the deployed program to its build environment. Make it an `e3.input` / dataset parameter.");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!t.isCallExpression(node))
|
|
85
|
+
return;
|
|
86
|
+
const callee = node.expression;
|
|
87
|
+
// A call to a binding imported from `node:fs` — `readFileSync(...)`,
|
|
88
|
+
// `fs.readFileSync(...)`, `existsSync(...)`, an aliased import, etc.
|
|
89
|
+
const base = t.isIdentifier(callee)
|
|
90
|
+
? callee
|
|
91
|
+
: t.isPropertyAccessExpression(callee) && t.isIdentifier(callee.expression)
|
|
92
|
+
? callee.expression
|
|
93
|
+
: undefined;
|
|
94
|
+
if (base !== undefined && resolvesToFsImport(base, ctx)) {
|
|
95
|
+
fire(ctx, node, "This `node:fs` call reads/probes the filesystem at build/deploy time and bakes the result into the program. Ingest at runtime via `e3.input` / a dataset / an `east-node-io` task.");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// `JSON.parse(...)` — an unambiguous global.
|
|
99
|
+
if (t.isPropertyAccessExpression(callee) &&
|
|
100
|
+
t.isIdentifier(callee.expression) &&
|
|
101
|
+
callee.expression.text === "JSON" &&
|
|
102
|
+
callee.name.text === "parse") {
|
|
103
|
+
fire(ctx, node, "`JSON.parse(...)` at module scope bakes parsed data into the program. Load it at runtime via `e3.input` / a dataset.");
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=no-compile-time-data-injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-compile-time-data-injection.js","sourceRoot":"","sources":["../../../src/rules/no-compile-time-data-injection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-compile-time-seed-data.d.ts","sourceRoot":"","sources":["../../../src/rules/no-compile-time-seed-data.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAyB,MAAM,aAAa,CAAC;AA4KnE,eAAO,MAAM,qBAAqB,EAAE,QA4CnC,CAAC"}
|