@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
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { insideBlockScope } from "../block-scope.js";
|
|
2
|
+
const NAME = "no-compile-time-seed-data";
|
|
3
|
+
const CODE = 990021;
|
|
4
|
+
function fire(ctx, target, messageText) {
|
|
5
|
+
const sf = ctx.sourceFile;
|
|
6
|
+
const start = target.getStart(sf);
|
|
7
|
+
ctx.report({ ruleName: NAME, code: CODE, start, length: target.getEnd() - start, messageText, category: "warning" });
|
|
8
|
+
}
|
|
9
|
+
/** The `ImportDeclaration` a symbol's (local, un-aliased) declaration belongs to. */
|
|
10
|
+
function importDeclOfSymbol(sym, t) {
|
|
11
|
+
for (const d of sym?.declarations ?? []) {
|
|
12
|
+
let n = d;
|
|
13
|
+
// ImportSpecifier -> NamedImports -> ImportClause -> ImportDeclaration; a
|
|
14
|
+
// NamespaceImport sits one level higher; a DEFAULT import binds the
|
|
15
|
+
// ImportClause itself (`import e3 from "@elaraai/e3"`).
|
|
16
|
+
if (t.isImportSpecifier(n))
|
|
17
|
+
n = n.parent.parent.parent;
|
|
18
|
+
else if (t.isNamespaceImport(n))
|
|
19
|
+
n = n.parent.parent;
|
|
20
|
+
else if (t.isImportClause(n))
|
|
21
|
+
n = n.parent;
|
|
22
|
+
else
|
|
23
|
+
continue;
|
|
24
|
+
if (t.isImportDeclaration(n))
|
|
25
|
+
return n;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
/** Does `id` resolve to a binding imported from any `@elaraai/*` package? (Keyed by
|
|
30
|
+
* SYMBOL → import specifier, like the other host-vs-East rules — never the text.) */
|
|
31
|
+
function resolvesToEastImport(id, ctx) {
|
|
32
|
+
const t = ctx.ts;
|
|
33
|
+
const imp = importDeclOfSymbol(ctx.checker.getSymbolAtLocation(id), t);
|
|
34
|
+
return imp !== undefined && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text.startsWith("@elaraai/");
|
|
35
|
+
}
|
|
36
|
+
/** Is `node` a call `<e3>.input(...)` where `<e3>` is the DEFAULT import of `@elaraai/e3`? */
|
|
37
|
+
function isE3InputCall(node, ctx) {
|
|
38
|
+
const t = ctx.ts;
|
|
39
|
+
const callee = node.expression;
|
|
40
|
+
if (!t.isPropertyAccessExpression(callee) || callee.name.text !== "input")
|
|
41
|
+
return false;
|
|
42
|
+
if (!t.isIdentifier(callee.expression))
|
|
43
|
+
return false;
|
|
44
|
+
const imp = importDeclOfSymbol(ctx.checker.getSymbolAtLocation(callee.expression), t);
|
|
45
|
+
return imp !== undefined && t.isStringLiteral(imp.moduleSpecifier) && imp.moduleSpecifier.text === "@elaraai/e3";
|
|
46
|
+
}
|
|
47
|
+
/** The root identifier a call/member chain is rooted on (`a.b.c(...)` -> `a`). */
|
|
48
|
+
function rootIdentifier(node, t) {
|
|
49
|
+
let cur = node;
|
|
50
|
+
for (;;) {
|
|
51
|
+
if (t.isPropertyAccessExpression(cur) || t.isElementAccessExpression(cur))
|
|
52
|
+
cur = cur.expression;
|
|
53
|
+
else if (t.isCallExpression(cur))
|
|
54
|
+
cur = cur.expression;
|
|
55
|
+
else
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
return t.isIdentifier(cur) ? cur : undefined;
|
|
59
|
+
}
|
|
60
|
+
// The host constructors that REPRESENT a constant East value (per east's
|
|
61
|
+
// `ValueTypeOf`): `Map` (DictType), `Set` (SetType), `Date` (DateTimeType), the
|
|
62
|
+
// typed arrays + `ArrayBuffer` (BlobType / VectorType). Constructing one is
|
|
63
|
+
// authoring a constant value, not computing data — its arguments are still walked,
|
|
64
|
+
// so `new Map(readCsv(...))` still fires on the inner host call.
|
|
65
|
+
const VALUE_CTORS = new Set([
|
|
66
|
+
"Map", "Set", "Date", "ArrayBuffer",
|
|
67
|
+
"Uint8Array", "Int8Array", "Uint8ClampedArray", "Int16Array", "Uint16Array",
|
|
68
|
+
"Int32Array", "Uint32Array", "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array",
|
|
69
|
+
]);
|
|
70
|
+
/**
|
|
71
|
+
* Does `expr` embed HOST COMPUTATION — a call to a non-`@elaraai` function (`num`,
|
|
72
|
+
* `BigInt`, `Number`, `readCsv`, a JS Array method, …), or a `new` of something
|
|
73
|
+
* other than a value-representation constructor (`Map`/`Set`/`Date`) or an
|
|
74
|
+
* `@elaraai` one? East value constructors (`variant`/`some`/`none`/`East.value`),
|
|
75
|
+
* primitive literals, `Map`/`Set`/array/object literals, constant concatenation and
|
|
76
|
+
* template labels are NOT host computation — they author a constant East value.
|
|
77
|
+
*/
|
|
78
|
+
function embedsHostComputation(expr, ctx) {
|
|
79
|
+
const t = ctx.ts;
|
|
80
|
+
let bad = false;
|
|
81
|
+
const visit = (n) => {
|
|
82
|
+
if (bad)
|
|
83
|
+
return;
|
|
84
|
+
if (t.isCallExpression(n)) {
|
|
85
|
+
const root = rootIdentifier(n.expression, t);
|
|
86
|
+
if (root === undefined || !resolvesToEastImport(root, ctx)) {
|
|
87
|
+
bad = true;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (t.isNewExpression(n)) {
|
|
92
|
+
const ctor = n.expression;
|
|
93
|
+
const ok = t.isIdentifier(ctor) && (VALUE_CTORS.has(ctor.text) || resolvesToEastImport(ctor, ctx));
|
|
94
|
+
if (!ok) {
|
|
95
|
+
bad = true;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
t.forEachChild(n, visit);
|
|
100
|
+
};
|
|
101
|
+
visit(expr);
|
|
102
|
+
return bad;
|
|
103
|
+
}
|
|
104
|
+
const MUTATORS = new Set(["set", "add", "push", "unshift", "splice", "delete", "clear", "fill", "sort", "copyWithin", "pop", "shift"]);
|
|
105
|
+
function isAssignmentOp(kind, t) {
|
|
106
|
+
const k = t.SyntaxKind;
|
|
107
|
+
return (kind === k.EqualsToken || kind === k.PlusEqualsToken || kind === k.MinusEqualsToken ||
|
|
108
|
+
kind === k.AsteriskEqualsToken || kind === k.SlashEqualsToken || kind === k.PercentEqualsToken ||
|
|
109
|
+
kind === k.AmpersandEqualsToken || kind === k.BarEqualsToken || kind === k.CaretEqualsToken ||
|
|
110
|
+
kind === k.LessThanLessThanEqualsToken || kind === k.GreaterThanGreaterThanEqualsToken ||
|
|
111
|
+
kind === k.GreaterThanGreaterThanGreaterThanEqualsToken || kind === k.AsteriskAsteriskEqualsToken ||
|
|
112
|
+
kind === k.QuestionQuestionEqualsToken || kind === k.BarBarEqualsToken || kind === k.AmpersandAmpersandEqualsToken);
|
|
113
|
+
}
|
|
114
|
+
/** Is `node` lexically inside a host loop (`for`/`for-of`/`for-in`/`while`/`do`)? */
|
|
115
|
+
function insideLoop(node, t) {
|
|
116
|
+
let cur = node.parent;
|
|
117
|
+
while (cur !== undefined) {
|
|
118
|
+
if (t.isForStatement(cur) || t.isForOfStatement(cur) || t.isForInStatement(cur) || t.isWhileStatement(cur) || t.isDoStatement(cur)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
cur = cur.parent;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
/** Is the binding `sym` HOST-FILLED anywhere in the file — mutated in place
|
|
126
|
+
* (`sym.set(...)` / `.push(...)` / `sym[k] = …`) EITHER inside a host loop (the
|
|
127
|
+
* Cartesian-product / CSV-overlay fill pattern) OR from a host-computed value? A
|
|
128
|
+
* handful of literal `.set("a", 1n)` calls outside any loop is just an imperatively
|
|
129
|
+
* authored constant and is NOT flagged. */
|
|
130
|
+
function isHostFilled(sym, ctx) {
|
|
131
|
+
const t = ctx.ts;
|
|
132
|
+
let filled = false;
|
|
133
|
+
const isSym = (n) => t.isIdentifier(n) && ctx.checker.getSymbolAtLocation(n) === sym;
|
|
134
|
+
const visit = (n) => {
|
|
135
|
+
if (filled)
|
|
136
|
+
return;
|
|
137
|
+
if (t.isCallExpression(n) &&
|
|
138
|
+
t.isPropertyAccessExpression(n.expression) &&
|
|
139
|
+
MUTATORS.has(n.expression.name.text) &&
|
|
140
|
+
isSym(n.expression.expression)) {
|
|
141
|
+
if (insideLoop(n, t) || n.arguments.some((a) => embedsHostComputation(a, ctx))) {
|
|
142
|
+
filled = true;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (t.isBinaryExpression(n) && isAssignmentOp(n.operatorToken.kind, t)) {
|
|
147
|
+
const root = rootIdentifier(n.left, t);
|
|
148
|
+
if (root !== undefined && isSym(root) && (insideLoop(n, t) || embedsHostComputation(n.right, ctx))) {
|
|
149
|
+
filled = true;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
t.forEachChild(n, visit);
|
|
154
|
+
};
|
|
155
|
+
visit(ctx.sourceFile);
|
|
156
|
+
return filled;
|
|
157
|
+
}
|
|
158
|
+
// `e3.input(name, type, seed?)` declares a WRITABLE dataset; the optional 3rd arg
|
|
159
|
+
// is only a default/genesis value, overwritten the moment anything writes to the
|
|
160
|
+
// dataset. It must therefore be a small AUTHORED CONSTANT — a literal, an
|
|
161
|
+
// empty/literal Map/Set/array/struct, or an East value (`variant`/`some`/`none`/
|
|
162
|
+
// `East.value`) — or omitted. Computing it from build-time data (a `new Map()`
|
|
163
|
+
// filled by host `for`-loops over parsed CSV, or an object literal of `num(cfg.x)`
|
|
164
|
+
// calls) bakes a non-portable, non-reactive snapshot into the deployed program.
|
|
165
|
+
// Real/bulk data belongs at RUNTIME: a `BlobType` input parsed with
|
|
166
|
+
// `blob.decodeCsv(...)` inside an `e3.task`, a platform `FileSystem.readFile` in a
|
|
167
|
+
// task, or `e3.record(...)` + `e3.mutation` for set-once root state.
|
|
168
|
+
export const noCompileTimeSeedData = {
|
|
169
|
+
name: NAME,
|
|
170
|
+
code: CODE,
|
|
171
|
+
description: "Flag host-computed data passed as the seed (3rd arg) of e3.input — the default must be a small authored constant; load real data at runtime.",
|
|
172
|
+
check(node, ctx) {
|
|
173
|
+
const t = ctx.ts;
|
|
174
|
+
if (!t.isCallExpression(node) || !isE3InputCall(node, ctx))
|
|
175
|
+
return;
|
|
176
|
+
if (insideBlockScope(node, ctx))
|
|
177
|
+
return; // e3.input only legitimately appears at module scope
|
|
178
|
+
const seedArg = node.arguments[2];
|
|
179
|
+
if (seedArg === undefined)
|
|
180
|
+
return; // no default — value arrives at runtime (correct)
|
|
181
|
+
// Resolve an identifier seed to its initializer; keep the symbol so we can see
|
|
182
|
+
// whether an authored-empty collection is then host-filled. An opaque seed
|
|
183
|
+
// (imported const, parameter, no initializer) is left silent — we only judge
|
|
184
|
+
// what we can see.
|
|
185
|
+
let expr = seedArg;
|
|
186
|
+
let sym;
|
|
187
|
+
if (t.isIdentifier(seedArg)) {
|
|
188
|
+
sym = ctx.checker.getSymbolAtLocation(seedArg);
|
|
189
|
+
const decl = sym?.valueDeclaration;
|
|
190
|
+
if (decl === undefined || !t.isVariableDeclaration(decl) || decl.initializer === undefined)
|
|
191
|
+
return;
|
|
192
|
+
expr = decl.initializer;
|
|
193
|
+
}
|
|
194
|
+
while (t.isAsExpression(expr) || t.isSatisfiesExpression(expr) || t.isParenthesizedExpression(expr)) {
|
|
195
|
+
expr = expr.expression;
|
|
196
|
+
}
|
|
197
|
+
const hostComputed = embedsHostComputation(expr, ctx);
|
|
198
|
+
const hostFilled = sym !== undefined && isHostFilled(sym, ctx);
|
|
199
|
+
if (!hostComputed && !hostFilled)
|
|
200
|
+
return;
|
|
201
|
+
const nameArg = node.arguments[0];
|
|
202
|
+
const name = nameArg !== undefined && t.isStringLiteralLike(nameArg) ? nameArg.text : "…";
|
|
203
|
+
const reason = hostFilled
|
|
204
|
+
? "this seed is an authored-empty collection then filled in place by host code (a `for`-loop / `.set(...)`)"
|
|
205
|
+
: "this seed is assembled by host calls (`num(...)`, `BigInt(...)`, parsed config) at module-evaluation time";
|
|
206
|
+
fire(ctx, seedArg, `Host-computed data passed as the \`e3.input("${name}", …)\` seed bakes a build-time snapshot into the deployed program — ${reason}. The default (3rd arg) 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: put the bytes in a \`BlobType\` input and parse with \`blob.decodeCsv(...)\` inside an \`e3.task\`, read files in a task via a platform \`FileSystem.readFile\`, or use \`e3.record(...)\` + \`e3.mutation\` for set-once root state.`);
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=no-compile-time-seed-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-compile-time-seed-data.js","sourceRoot":"","sources":["../../../src/rules/no-compile-time-seed-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-host-in-east-block.d.ts","sourceRoot":"","sources":["../../../src/rules/no-host-in-east-block.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAyB,MAAM,aAAa,CAAC;AAyJnE,eAAO,MAAM,iBAAiB,EAAE,QAuH/B,CAAC"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { isEastExprType, isBlockBuilderType } from "../east-type.js";
|
|
2
|
+
import { insideBlockScope } from "../block-scope.js";
|
|
3
|
+
import { chainRootReceiver, bodyBuildsEastIr } from "../east-ir.js";
|
|
4
|
+
const NAME = "no-host-in-east-block";
|
|
5
|
+
const CODE = 990020;
|
|
6
|
+
// ── East-vs-host classification ─────────────────────────────────────────────
|
|
7
|
+
/** Does `id` resolve to a binding imported from an `@elaraai/*` package? (The
|
|
8
|
+
* whole East ecosystem API — `East`, `Expr`, `variant`/`some`, `ArrayType`/
|
|
9
|
+
* `StructType`/`DictType`, `GoogleOr`, `Data`, … — is recognised by SYMBOL, not a
|
|
10
|
+
* brittle name list.) */
|
|
11
|
+
function resolvesToEastImport(id, ctx) {
|
|
12
|
+
const t = ctx.ts;
|
|
13
|
+
// Use the LOCAL import symbol (its declaration is the ImportSpecifier/clause) —
|
|
14
|
+
// do NOT resolve the alias, which would jump to the declaration inside
|
|
15
|
+
// @elaraai/east and lose the import-specifier we key on.
|
|
16
|
+
const sym = ctx.checker.getSymbolAtLocation(id);
|
|
17
|
+
for (const d of sym?.declarations ?? []) {
|
|
18
|
+
let n = d;
|
|
19
|
+
if (t.isImportSpecifier(n))
|
|
20
|
+
n = n.parent.parent.parent;
|
|
21
|
+
else if (t.isNamespaceImport(n))
|
|
22
|
+
n = n.parent.parent;
|
|
23
|
+
else if (t.isImportClause(n))
|
|
24
|
+
n = n.parent;
|
|
25
|
+
else
|
|
26
|
+
continue;
|
|
27
|
+
if (t.isImportDeclaration(n) && t.isStringLiteral(n.moduleSpecifier) && n.moduleSpecifier.text.startsWith("@elaraai/")) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Does `id` resolve to a binding LOCAL to an East block whose runtime value is an
|
|
35
|
+
* East `Expr` typed loosely as `any` — an in-block TS macro (`g`/`sdiv`/`roundI`/…,
|
|
36
|
+
* itself reported by clause E) or one of its loosely-typed parameters? East methods
|
|
37
|
+
* chained off such a receiver (`sdiv(a, b).multiply(…)`, or `a.divide(b)` inside the
|
|
38
|
+
* macro body) are East methods, not separate host calls: the macro is already
|
|
39
|
+
* flagged, so re-reporting the East ops on its result/operands is a false positive.
|
|
40
|
+
* (We must NOT exempt all `any` receivers — only these block-local East bindings.)
|
|
41
|
+
*/
|
|
42
|
+
function resolvesToInBlockEastBinding(id, ctx) {
|
|
43
|
+
const t = ctx.ts;
|
|
44
|
+
const sym = ctx.checker.getSymbolAtLocation(id);
|
|
45
|
+
for (const d of sym?.declarations ?? []) {
|
|
46
|
+
// An in-block TS macro: `const f = (…) => …` / `function f(…) {…}`.
|
|
47
|
+
if (t.isFunctionDeclaration(d) && d.body !== undefined && insideBlockScope(d, ctx))
|
|
48
|
+
return true;
|
|
49
|
+
if (t.isVariableDeclaration(d) &&
|
|
50
|
+
d.initializer !== undefined &&
|
|
51
|
+
(t.isArrowFunction(d.initializer) || t.isFunctionExpression(d.initializer)) &&
|
|
52
|
+
insideBlockScope(d, ctx)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// A parameter of an in-block TS macro (its loosely-typed East operands). A
|
|
56
|
+
// `$`-callback's params are already East-typed (clause A2 handles them), so
|
|
57
|
+
// only non-`$` macro params reach here.
|
|
58
|
+
if (t.isParameter(d)) {
|
|
59
|
+
const fn = d.parent;
|
|
60
|
+
if ((t.isArrowFunction(fn) || t.isFunctionExpression(fn) || t.isFunctionDeclaration(fn)) &&
|
|
61
|
+
insideBlockScope(fn, ctx)) {
|
|
62
|
+
const first = fn.parameters[0];
|
|
63
|
+
if (first === undefined || !isBlockBuilderType(ctx.checker.getTypeAtLocation(first.name)))
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/** Is a CallExpression an EAST call (allowed), vs a HOST call (the violation)? */
|
|
71
|
+
function isEastCall(call, ctx) {
|
|
72
|
+
const t = ctx.ts;
|
|
73
|
+
const f = call.expression;
|
|
74
|
+
// A0 — the callee is itself an East value (a bound `East.function`, a
|
|
75
|
+
// function-typed param, a curried/higher-order East fn).
|
|
76
|
+
if (isEastExprType(ctx.checker.getTypeAtLocation(f)))
|
|
77
|
+
return true;
|
|
78
|
+
const root = chainRootReceiver(f, ctx);
|
|
79
|
+
// A1 — rooted on the block builder `$` (`$.let`/`$.const`/`$(…)`/`$.if`/…).
|
|
80
|
+
if (isBlockBuilderType(ctx.checker.getTypeAtLocation(root)))
|
|
81
|
+
return true;
|
|
82
|
+
// A2 — a method on an East `Expr` receiver (`.add`/`.get`/`.map`/`.match`/…).
|
|
83
|
+
// Read the immediate receiver's own type (survives an `: any` return).
|
|
84
|
+
if (t.isPropertyAccessExpression(f) && isEastExprType(ctx.checker.getTypeAtLocation(f.expression)))
|
|
85
|
+
return true;
|
|
86
|
+
// A5 — rooted on an `@elaraai/*` import (`East.*`, `Expr.*`, `variant`/`some`,
|
|
87
|
+
// `ArrayType`/`StructType`/`DictType`, `GoogleOr.*`, …).
|
|
88
|
+
if (t.isIdentifier(root) && resolvesToEastImport(root, ctx))
|
|
89
|
+
return true;
|
|
90
|
+
// A6 — a method chained off an in-block TS macro or its loosely-typed (`any`)
|
|
91
|
+
// operand, whose type-info is lost as `any`. The macro is reported elsewhere
|
|
92
|
+
// (clause E / its bare call); the East methods on its East-`Expr` result are
|
|
93
|
+
// East, not additional host calls.
|
|
94
|
+
if (t.isPropertyAccessExpression(f) && t.isIdentifier(root) && resolvesToInBlockEastBinding(root, ctx))
|
|
95
|
+
return true;
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
function isEast(expr, ctx) {
|
|
99
|
+
return isEastExprType(ctx.checker.getTypeAtLocation(expr));
|
|
100
|
+
}
|
|
101
|
+
/** Is `node` inside JSX (UI composition is out of scope — `prefer-jsx-…` owns it)? */
|
|
102
|
+
function insideJsx(node, t) {
|
|
103
|
+
let cur = node.parent;
|
|
104
|
+
while (cur !== undefined) {
|
|
105
|
+
if (t.isJsxElement(cur) || t.isJsxSelfClosingElement(cur) || t.isJsxFragment(cur) || t.isJsxExpression(cur) || t.isJsxAttribute(cur)) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
cur = cur.parent;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
function isJsx(node, t) {
|
|
113
|
+
return t.isJsxElement(node) || t.isJsxFragment(node) || t.isJsxSelfClosingElement(node) || (t.isParenthesizedExpression(node) && isJsx(node.expression, t));
|
|
114
|
+
}
|
|
115
|
+
/** The expressions a function/arrow returns, not descending into nested functions. */
|
|
116
|
+
function returnExpressions(fn, t) {
|
|
117
|
+
if (fn.body === undefined)
|
|
118
|
+
return [];
|
|
119
|
+
if (!t.isBlock(fn.body))
|
|
120
|
+
return [fn.body];
|
|
121
|
+
const out = [];
|
|
122
|
+
const visit = (n) => {
|
|
123
|
+
if (t.isFunctionDeclaration(n) || t.isFunctionExpression(n) || t.isArrowFunction(n))
|
|
124
|
+
return;
|
|
125
|
+
if (t.isReturnStatement(n) && n.expression !== undefined)
|
|
126
|
+
out.push(n.expression);
|
|
127
|
+
t.forEachChild(n, visit);
|
|
128
|
+
};
|
|
129
|
+
t.forEachChild(fn.body, visit);
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
const REPORT = (ctx, target, messageText, fix) => {
|
|
133
|
+
const sf = ctx.sourceFile;
|
|
134
|
+
const start = target.getStart(sf);
|
|
135
|
+
const length = target.getEnd() - start;
|
|
136
|
+
ctx.report({
|
|
137
|
+
ruleName: NAME,
|
|
138
|
+
code: CODE,
|
|
139
|
+
start,
|
|
140
|
+
length,
|
|
141
|
+
messageText,
|
|
142
|
+
category: "warning",
|
|
143
|
+
...(fix !== undefined ? { fix: { description: fix.description, changes: [{ start, length, newText: fix.newText }] } } : {}),
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
// Inside an East block the code must be East all the way down — only East
|
|
147
|
+
// expressions and East statements (`$.let`/`$.const`/`$(…)`/`$.if`/`$.for`/`$.assign`,
|
|
148
|
+
// East `Expr` method chains, `East.*`/`Expr.*`/`variant`/`some`/`none`, `East.str`,
|
|
149
|
+
// and `return <East expr>`). ANY host-language construct is an authoring-time macro
|
|
150
|
+
// over East: a call to a host function (a local TS helper, a JS builtin, a JS Array
|
|
151
|
+
// method), a host operator on East operands, a host `for`/`while`/`if` that emits
|
|
152
|
+
// IR, or host string interpolation. Express it in East instead.
|
|
153
|
+
export const noHostInEastBlock = {
|
|
154
|
+
name: NAME,
|
|
155
|
+
code: CODE,
|
|
156
|
+
description: "Flag host-language constructs (host calls, operators on East operands, JS control-flow, host string interpolation) inside an East block — express them in East.",
|
|
157
|
+
check(node, ctx) {
|
|
158
|
+
const t = ctx.ts;
|
|
159
|
+
if (!insideBlockScope(node, ctx))
|
|
160
|
+
return;
|
|
161
|
+
if (insideJsx(node, t))
|
|
162
|
+
return;
|
|
163
|
+
// Clause E — a TS closure/function DECLARED inside an East block (a `const`
|
|
164
|
+
// arrow, a function-expression, or a `function` declaration). It is an
|
|
165
|
+
// authoring-time macro: it can't be serialized/recursed and expands inline at
|
|
166
|
+
// each call. `$`-callbacks (`($, x) => …`) and JSX/UI helpers are excluded.
|
|
167
|
+
{
|
|
168
|
+
let fn;
|
|
169
|
+
let reportNode;
|
|
170
|
+
if (t.isFunctionDeclaration(node) && node.body !== undefined) {
|
|
171
|
+
fn = node;
|
|
172
|
+
reportNode = node.name ?? node;
|
|
173
|
+
}
|
|
174
|
+
else if (t.isVariableDeclaration(node) &&
|
|
175
|
+
node.initializer !== undefined &&
|
|
176
|
+
(t.isArrowFunction(node.initializer) || t.isFunctionExpression(node.initializer))) {
|
|
177
|
+
fn = node.initializer;
|
|
178
|
+
reportNode = node.name;
|
|
179
|
+
}
|
|
180
|
+
if (fn !== undefined && reportNode !== undefined) {
|
|
181
|
+
const first = fn.parameters[0];
|
|
182
|
+
if (first !== undefined && isBlockBuilderType(ctx.checker.getTypeAtLocation(first.name)))
|
|
183
|
+
return; // East `$`-callback
|
|
184
|
+
if (returnExpressions(fn, t).some((r) => isJsx(r, t)))
|
|
185
|
+
return; // UI-composition helper
|
|
186
|
+
REPORT(ctx, reportNode, "TS closure/function declared inside an East block — an authoring-time macro (it can't be serialized or recursed and expands inline at each call). Make it a real `East.function` (`$.const(East.function(...))`) or inline it.");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Clause C — host control-flow statements that emit East IR.
|
|
191
|
+
if (t.isForStatement(node) || t.isWhileStatement(node) || t.isForOfStatement(node)) {
|
|
192
|
+
if (t.isForOfStatement(node) && isEast(node.expression, ctx))
|
|
193
|
+
return; // for-of over an East Expr is fine
|
|
194
|
+
if (!bodyBuildsEastIr(node.statement, ctx))
|
|
195
|
+
return;
|
|
196
|
+
REPORT(ctx, node.getChildAt(0, ctx.sourceFile), "Host loop building East IR — bind the data with `$.const([...], ArrayType(...))` and use an East collection op (`data.map(($, x) => …)`) or `$.for(data, ($, x) => …)`.");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (t.isIfStatement(node)) {
|
|
200
|
+
const emits = bodyBuildsEastIr(node.thenStatement, ctx) || (node.elseStatement !== undefined && bodyBuildsEastIr(node.elseStatement, ctx));
|
|
201
|
+
if (!emits)
|
|
202
|
+
return;
|
|
203
|
+
REPORT(ctx, node.getChildAt(0, ctx.sourceFile), "Host `if` building East IR — use East's `$.if(cond, …)` so the branch is chosen at East runtime.");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Clause B — host operators on East operands.
|
|
207
|
+
if (t.isConditionalExpression(node)) {
|
|
208
|
+
if (isEast(node.condition, ctx) && isEast(node.whenTrue, ctx) && isEast(node.whenFalse, ctx)) {
|
|
209
|
+
const sf = ctx.sourceFile;
|
|
210
|
+
REPORT(ctx, node, "Host `?:` selecting between East values — use `cond.ifElse(() => a, () => b)`.", {
|
|
211
|
+
description: "Rewrite as cond.ifElse(...)",
|
|
212
|
+
newText: `(${node.condition.getText(sf)}).ifElse(() => ${node.whenTrue.getText(sf)}, () => ${node.whenFalse.getText(sf)})`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (t.isBinaryExpression(node)) {
|
|
218
|
+
const op = node.operatorToken.kind;
|
|
219
|
+
const k = t.SyntaxKind;
|
|
220
|
+
const logical = op === k.AmpersandAmpersandToken || op === k.BarBarToken;
|
|
221
|
+
const arith = op === k.PlusToken || op === k.MinusToken || op === k.AsteriskToken || op === k.SlashToken ||
|
|
222
|
+
op === k.PercentToken || op === k.EqualsEqualsEqualsToken || op === k.ExclamationEqualsEqualsToken ||
|
|
223
|
+
op === k.EqualsEqualsToken || op === k.LessThanToken || op === k.LessThanEqualsToken ||
|
|
224
|
+
op === k.GreaterThanToken || op === k.GreaterThanEqualsToken;
|
|
225
|
+
if (logical && isEast(node.left, ctx) && isEast(node.right, ctx)) {
|
|
226
|
+
REPORT(ctx, node, "Host `&&`/`||` on East booleans — use East's `.and(() => …)` / `.or(() => …)`.");
|
|
227
|
+
}
|
|
228
|
+
else if (arith && (isEast(node.left, ctx) || isEast(node.right, ctx))) {
|
|
229
|
+
REPORT(ctx, node, "Host operator on an East value — use the East method (`.add`/`.subtract`/`.multiply`/`.divide`) or `East.equal`/`East.less`/`East.greater`.");
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (t.isPrefixUnaryExpression(node) && (node.operator === t.SyntaxKind.MinusToken || node.operator === t.SyntaxKind.ExclamationToken)) {
|
|
234
|
+
if (isEast(node.operand, ctx)) {
|
|
235
|
+
REPORT(ctx, node, "Host unary operator on an East value — use `.negate()` / `East.not`.");
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// Clause F — host index access `x[i]` on a JS value (an East collection is
|
|
240
|
+
// read with `.get(...)`, never `[i]`, so a non-`Expr` receiver here is a host
|
|
241
|
+
// array/object being indexed — `adopt[ti]`, `BUSINESS_UNITS[oi]`).
|
|
242
|
+
if (t.isElementAccessExpression(node)) {
|
|
243
|
+
if (isEast(node.expression, ctx))
|
|
244
|
+
return; // (an Expr has no index signature anyway)
|
|
245
|
+
REPORT(ctx, node, "Host index access on a JS value inside an East block — model the data as an East collection and read it with `.get(...)` / East ops, not `[i]`.");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
// Clause D — host string interpolation (not an `East.str`/`str` tagged template).
|
|
249
|
+
if (t.isTemplateExpression(node) && !(node.parent !== undefined && t.isTaggedTemplateExpression(node.parent))) {
|
|
250
|
+
REPORT(ctx, node, "Host string interpolation inside an East block — build the string in East with `East.str`…`` (or `str`…``).");
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
// Clause A — host call.
|
|
254
|
+
if (t.isCallExpression(node)) {
|
|
255
|
+
if (isEastCall(node, ctx))
|
|
256
|
+
return;
|
|
257
|
+
// Specialised message for the host-key-into-East-collection sub-case.
|
|
258
|
+
const callee = node.expression;
|
|
259
|
+
const KEY_ACCESSORS = new Set(["get", "tryGet", "has", "insert", "insertOrUpdate", "update", "remove"]);
|
|
260
|
+
REPORT(ctx, node, t.isPropertyAccessExpression(callee) && KEY_ACCESSORS.has(callee.name.text)
|
|
261
|
+
? "Host call inside an East block — make it a real `East.function` (`$.const(East.function(...))`) or inline it as East."
|
|
262
|
+
: "Host call inside an East block — this is an authoring-time macro over East. Make it a real `East.function` (`$.const(East.function(...))`), inline it as East, or use the East stdlib.");
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
//# sourceMappingURL=no-host-in-east-block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-host-in-east-block.js","sourceRoot":"","sources":["../../../src/rules/no-host-in-east-block.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-let-const-in-expression.d.ts","sourceRoot":"","sources":["../../../src/rules/no-let-const-in-expression.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAW5C,eAAO,MAAM,sBAAsB,EAAE,
|
|
1
|
+
{"version":3,"file":"no-let-const-in-expression.d.ts","sourceRoot":"","sources":["../../../src/rules/no-let-const-in-expression.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAW5C,eAAO,MAAM,sBAAsB,EAAE,QA6CpC,CAAC"}
|
|
@@ -25,16 +25,17 @@ export const noLetConstInExpression = {
|
|
|
25
25
|
}
|
|
26
26
|
if (parent === undefined)
|
|
27
27
|
return;
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
(t.
|
|
36
|
-
(t.
|
|
37
|
-
|
|
28
|
+
// Allow-list: `$.let`/`$.const` is only valid as a JS `const`/`let`
|
|
29
|
+
// initializer, a bare statement, a `return`, or a concise arrow body. ANY
|
|
30
|
+
// other position buries the declaration in an expression — a struct-field
|
|
31
|
+
// value (`field: $.let(...)`), an array element, a call argument
|
|
32
|
+
// (`$.if($.let(...))`), a chain target (`$.let(...).add(1n)`), an operator
|
|
33
|
+
// operand, a ternary branch, etc. Flag everything that is not allowed.
|
|
34
|
+
const allowed = (t.isVariableDeclaration(parent) && parent.initializer === current) ||
|
|
35
|
+
(t.isExpressionStatement(parent) && parent.expression === current) ||
|
|
36
|
+
(t.isReturnStatement(parent) && parent.expression === current) ||
|
|
37
|
+
(t.isArrowFunction(parent) && parent.body === current);
|
|
38
|
+
if (allowed)
|
|
38
39
|
return;
|
|
39
40
|
const sf = ctx.sourceFile;
|
|
40
41
|
const start = call.getStart(sf);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-let-const-in-expression.js","sourceRoot":"","sources":["../../../src/rules/no-let-const-in-expression.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,IAAI,GAAG,4BAA4B,CAAC;AAC1C,MAAM,IAAI,GAAG,MAAM,CAAC;AAEpB,gFAAgF;AAChF,iFAAiF;AACjF,mFAAmF;AACnF,iFAAiF;AACjF,yEAAyE;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAa;IAC9C,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,WAAW,EACT,kGAAkG;IACpG,KAAK,CAAC,IAAI,EAAE,GAAG;QACb,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAEhC,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QAExB,oCAAoC;QACpC,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC5B,OAAO,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,GAAG,MAAM,CAAC;YACjB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QACzB,CAAC;QACD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO;QAEjC
|
|
1
|
+
{"version":3,"file":"no-let-const-in-expression.js","sourceRoot":"","sources":["../../../src/rules/no-let-const-in-expression.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,IAAI,GAAG,4BAA4B,CAAC;AAC1C,MAAM,IAAI,GAAG,MAAM,CAAC;AAEpB,gFAAgF;AAChF,iFAAiF;AACjF,mFAAmF;AACnF,iFAAiF;AACjF,yEAAyE;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAa;IAC9C,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,WAAW,EACT,kGAAkG;IACpG,KAAK,CAAC,IAAI,EAAE,GAAG;QACb,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAEhC,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QAExB,oCAAoC;QACpC,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC5B,OAAO,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,GAAG,MAAM,CAAC;YACjB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QACzB,CAAC;QACD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO;QAEjC,oEAAoE;QACpE,0EAA0E;QAC1E,0EAA0E;QAC1E,iEAAiE;QACjE,2EAA2E;QAC3E,uEAAuE;QACvE,MAAM,OAAO,GACX,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,KAAK,OAAO,CAAC;YACnE,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC;YAClE,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC;YAC9D,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACzD,IAAI,OAAO;YAAE,OAAO;QAEpB,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,MAAM,CAAC;YACT,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,IAAI;YACV,KAAK;YACL,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK;YAC7B,WAAW,EAAE,OAAO,KAAK,CAAC,MAAM,wEAAwE,KAAK,CAAC,MAAM,uGAAuG;YAC3N,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-module-scope-east-macro.d.ts","sourceRoot":"","sources":["../../../src/rules/no-module-scope-east-macro.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAyB,MAAM,aAAa,CAAC;AA+FnE,eAAO,MAAM,sBAAsB,EAAE,QAwDpC,CAAC"}
|