lanekeep 0.9.0 → 0.11.0
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 +1 -0
- package/index.d.ts +67 -9
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -89,6 +89,7 @@ actual rule.
|
|
|
89
89
|
lanekeep check # the whole project
|
|
90
90
|
lanekeep check --staged # only what is about to be committed
|
|
91
91
|
lanekeep check --since main # only what changed against a ref
|
|
92
|
+
lanekeep check --file src/a.ts # exactly these files, repeatable, no git involved
|
|
92
93
|
lanekeep check --watch # re-check on every change, until Ctrl-C
|
|
93
94
|
lanekeep check --fix # apply the safe fixes, report what is left
|
|
94
95
|
lanekeep check --profile # per rule: where the time went, and what it looked at
|
package/index.d.ts
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* The world is the single source of truth for every member the renderer emits straight from it.
|
|
11
11
|
* Three members deviate from the world on purpose, and all three are QuickJS-shaped: `today` is
|
|
12
12
|
* omitted from `RuleContext` because QuickJS exposes it as a conditional property rather than a
|
|
13
|
-
* callable, a shape this renderer cannot state honestly from the world; `
|
|
14
|
-
* `RuleContext` because
|
|
15
|
-
* `reduce-context`; and `types` is added to `RuleContext` because `ctx.types` — the bounded
|
|
13
|
+
* callable, a shape this renderer cannot state honestly from the world; `types` is added
|
|
14
|
+
* to `RuleContext` because `ctx.types` — the bounded
|
|
16
15
|
* type oracle — is QuickJS-only and has no presence in `world.wit` at all: a component rule
|
|
17
|
-
* cannot declare `requires`, so there is nothing for the world to say about it
|
|
16
|
+
* cannot declare `requires`, so there is nothing for the world to say about it; and `flow` is
|
|
17
|
+
* added to `RuleContext` for the same reason — `ctx.flow`, the taint-analysis completeness
|
|
18
|
+
* surface, is QuickJS-only too and has no presence in `world.wit` either. Nothing else is
|
|
18
19
|
* added or omitted by hand.
|
|
19
20
|
*/
|
|
20
21
|
|
|
@@ -136,7 +137,13 @@ export interface Gates {
|
|
|
136
137
|
fileNotContains?: string[]
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* A replacement a rule offers for a violation.
|
|
142
|
+
*
|
|
143
|
+
* A per-file offer alone: a fix names a node, and the reduce phase consumes facts and the
|
|
144
|
+
* file list and nothing else — there is no parse tree there for `node` to name, which is why
|
|
145
|
+
* a reduce report's options carry a message and never a fix.
|
|
146
|
+
*/
|
|
140
147
|
export interface Fix {
|
|
141
148
|
/** The node whose text is replaced. */
|
|
142
149
|
node: Node
|
|
@@ -160,6 +167,20 @@ export interface ReportOptions {
|
|
|
160
167
|
fix?: Fix
|
|
161
168
|
}
|
|
162
169
|
|
|
170
|
+
/** Options for a single reduce report. */
|
|
171
|
+
export interface ReduceReportOptions {
|
|
172
|
+
/** Overrides the card's `message` for this one violation. */
|
|
173
|
+
message?: string
|
|
174
|
+
/**
|
|
175
|
+
* Never present. A fix replaces a node's text, and the reduce phase has no parse tree —
|
|
176
|
+
* `node` has nothing to name, and both hosts throw on a supplied fix rather than drop it.
|
|
177
|
+
* Typed `never` rather than left absent so offering one fails to compile even for an
|
|
178
|
+
* object built before the call, which a fresh literal's excess-property check alone would
|
|
179
|
+
* admit.
|
|
180
|
+
*/
|
|
181
|
+
fix?: never
|
|
182
|
+
}
|
|
183
|
+
|
|
163
184
|
/**
|
|
164
185
|
* A fact a rule emits for the reduce phase.
|
|
165
186
|
*
|
|
@@ -355,6 +376,18 @@ export interface TypeApi {
|
|
|
355
376
|
complete(): boolean
|
|
356
377
|
}
|
|
357
378
|
|
|
379
|
+
/**
|
|
380
|
+
* The taint-analysis completeness surface, present on `ctx.flow` for a rule that declares
|
|
381
|
+
* `flow`. Answers whether the analysis saw through every construct in the file being checked
|
|
382
|
+
* — so a rule can say "I could not verify this file" rather than nothing.
|
|
383
|
+
*/
|
|
384
|
+
export interface FlowApi {
|
|
385
|
+
/** `true` iff the analysis dropped no construct in this file (`dropped === 0`). */
|
|
386
|
+
complete(): boolean
|
|
387
|
+
/** How many constructs the analysis could not see through in this file. */
|
|
388
|
+
readonly dropped: number
|
|
389
|
+
}
|
|
390
|
+
|
|
358
391
|
/** A rule's RuleContext surface. */
|
|
359
392
|
export interface RuleContext {
|
|
360
393
|
readonly filePath: string
|
|
@@ -381,8 +414,6 @@ export interface RuleContext {
|
|
|
381
414
|
emitFact(fact: Fact): void
|
|
382
415
|
loc(n: Node): NodeLocation | undefined
|
|
383
416
|
report(at: Node, message?: string | ReportOptions): void
|
|
384
|
-
/** Facts emitted so far, optionally filtered by `kind`. */
|
|
385
|
-
facts(kind?: string): EmittedFact[]
|
|
386
417
|
/**
|
|
387
418
|
* The type oracle, present only for a rule that declared `requires: ['types']`.
|
|
388
419
|
* Bounded by a fixed depth rather than by file: it follows an import into the
|
|
@@ -396,6 +427,11 @@ export interface RuleContext {
|
|
|
396
427
|
* deliberate.
|
|
397
428
|
*/
|
|
398
429
|
types: TypeApi
|
|
430
|
+
/**
|
|
431
|
+
* The taint-analysis completeness surface, present only in the flow phase
|
|
432
|
+
* of a rule that declares `flow` (inside `checkFlow` / `checkFile`).
|
|
433
|
+
*/
|
|
434
|
+
flow: FlowApi
|
|
399
435
|
}
|
|
400
436
|
|
|
401
437
|
/** A violation the reduce phase reports, which has no node to point at. */
|
|
@@ -412,7 +448,8 @@ export interface ReduceLocation {
|
|
|
412
448
|
export interface ReduceContext {
|
|
413
449
|
readonly files: string[]
|
|
414
450
|
facts(kind?: string): EmittedFact[]
|
|
415
|
-
|
|
451
|
+
/** Takes a message; a supplied `fix` throws — there is no node to attach one to. */
|
|
452
|
+
report(at: ReduceLocation, message?: string | ReduceReportOptions): void
|
|
416
453
|
}
|
|
417
454
|
|
|
418
455
|
/** Queries whose named captures drive the taint analysis. */
|
|
@@ -445,8 +482,18 @@ export type ObligationSpec = {
|
|
|
445
482
|
/**
|
|
446
483
|
* `'function'` — every path out of the enclosing function, `return`/`throw` included.
|
|
447
484
|
* `'block'` — every path out of the block the acquire is in.
|
|
485
|
+
* `'module'` — a matching-`@key` release must exist somewhere in the file.
|
|
486
|
+
* `'class'` — a matching-`@key` release must exist in the same class.
|
|
487
|
+
* `'component'` — a matching-`@key` release must exist in the same React function component.
|
|
448
488
|
*/
|
|
449
|
-
scope: 'function' | 'block'
|
|
489
|
+
scope: 'function' | 'block' | 'module' | 'class' | 'component'
|
|
490
|
+
/**
|
|
491
|
+
* How a `@key` correlates an acquire with a release. `'text'` (default) — exact captured
|
|
492
|
+
* text. `'binding'` — shared value origin (follows copies/wrappers/ternaries); requires
|
|
493
|
+
* `@key`. Note: `'binding'` does not correlate distinct per-frame parameters — use `'text'`
|
|
494
|
+
* for the sibling-callback pattern.
|
|
495
|
+
*/
|
|
496
|
+
keyBy?: 'text' | 'binding'
|
|
450
497
|
}
|
|
451
498
|
|
|
452
499
|
/** An acquire some path leaves undischarged, passed to `checkObligation`. */
|
|
@@ -456,6 +503,11 @@ export type UnmetObligation = {
|
|
|
456
503
|
readonly exit: Node
|
|
457
504
|
/** Whether any path *did* discharge it: partial coverage reads differently to none. */
|
|
458
505
|
readonly partial: boolean
|
|
506
|
+
/**
|
|
507
|
+
* The acquire's `@key` capture, when the rule's acquire/release queries bind one — so a
|
|
508
|
+
* report can name the value. Absent for an un-keyed obligation.
|
|
509
|
+
*/
|
|
510
|
+
readonly key?: Node
|
|
459
511
|
}
|
|
460
512
|
|
|
461
513
|
/** A rule, as `defineRule` takes it. */
|
|
@@ -539,6 +591,12 @@ export interface Rule {
|
|
|
539
591
|
obligation?: ObligationSpec
|
|
540
592
|
/** Called once per value left with an unmet obligation at the end of its scope. */
|
|
541
593
|
checkObligation?(ctx: RuleContext, unmet: UnmetObligation): void
|
|
594
|
+
/**
|
|
595
|
+
* Called once per file the rule's flow phase examined, including files with no flow.
|
|
596
|
+
* Read `ctx.flow.complete()` / `ctx.flow.dropped` and report at `ctx.root` when the taint
|
|
597
|
+
* analysis could not see through every construct. Requires `flow`.
|
|
598
|
+
*/
|
|
599
|
+
checkFile?(ctx: RuleContext): void
|
|
542
600
|
}
|
|
543
601
|
|
|
544
602
|
/** A lanekeep configuration, as `defineConfig` takes it. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lanekeep",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Deterministic, AST-based architectural conformance checking",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"node": ">=18"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
|
-
"@lanekeep/darwin-arm64": "0.
|
|
27
|
-
"@lanekeep/linux-arm64": "0.
|
|
28
|
-
"@lanekeep/linux-x64": "0.
|
|
29
|
-
"@lanekeep/win32-x64": "0.
|
|
26
|
+
"@lanekeep/darwin-arm64": "0.11.0",
|
|
27
|
+
"@lanekeep/linux-arm64": "0.11.0",
|
|
28
|
+
"@lanekeep/linux-x64": "0.11.0",
|
|
29
|
+
"@lanekeep/win32-x64": "0.11.0"
|
|
30
30
|
},
|
|
31
31
|
"main": "index.js",
|
|
32
32
|
"types": "index.d.ts",
|