@mittwald/flow-codemods 1.1.0-next.10 → 1.1.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +3 -2
  3. package/dist/checks/context.d.ts +0 -16
  4. package/dist/checks/context.d.ts.map +0 -1
  5. package/dist/checks/context.js +0 -72
  6. package/dist/checks/load.d.ts +0 -13
  7. package/dist/checks/load.d.ts.map +0 -1
  8. package/dist/checks/load.js +0 -53
  9. package/dist/checks/types.d.ts +0 -49
  10. package/dist/checks/types.d.ts.map +0 -1
  11. package/dist/checks/types.js +0 -0
  12. package/dist/cli/detect.d.ts +0 -35
  13. package/dist/cli/detect.d.ts.map +0 -1
  14. package/dist/cli/detect.js +0 -62
  15. package/dist/cli/verify.d.ts +0 -77
  16. package/dist/cli/verify.d.ts.map +0 -1
  17. package/dist/cli/verify.js +0 -148
  18. package/dist/detect/align-to-combine.d.ts +0 -8
  19. package/dist/detect/align-to-combine.d.ts.map +0 -1
  20. package/dist/detect/align-to-combine.js +0 -9
  21. package/dist/detect/overlay-controller-add-on-close-return-type.d.ts +0 -9
  22. package/dist/detect/overlay-controller-add-on-close-return-type.d.ts.map +0 -1
  23. package/dist/detect/overlay-controller-add-on-close-return-type.js +0 -10
  24. package/dist/detect/tooltip-trigger-delay-type.d.ts +0 -11
  25. package/dist/detect/tooltip-trigger-delay-type.d.ts.map +0 -1
  26. package/dist/detect/tooltip-trigger-delay-type.js +0 -12
  27. package/dist/tsconfig.tsbuildinfo +0 -1
  28. package/dist/verify/align-to-combine.d.ts +0 -11
  29. package/dist/verify/align-to-combine.d.ts.map +0 -1
  30. package/dist/verify/align-to-combine.js +0 -22
  31. package/dist/verify/overlay-controller-add-on-close-return-type.d.ts +0 -14
  32. package/dist/verify/overlay-controller-add-on-close-return-type.d.ts.map +0 -1
  33. package/dist/verify/overlay-controller-add-on-close-return-type.js +0 -21
  34. package/dist/verify/tooltip-trigger-delay-type.d.ts +0 -13
  35. package/dist/verify/tooltip-trigger-delay-type.d.ts.map +0 -1
  36. package/dist/verify/tooltip-trigger-delay-type.js +0 -18
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Mittwald CM Service GmbH & Co. KG and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mittwald/flow-codemods",
3
- "version": "1.1.0-next.10",
3
+ "version": "1.1.0-next.11",
4
4
  "type": "module",
5
5
  "description": "Codemods and an upgrade CLI for consumers of Flow, mittwald's design system",
6
6
  "homepage": "https://flow.mittwald.de",
@@ -37,5 +37,6 @@
37
37
  "typescript": "^6.0.3",
38
38
  "vitest": "^4.1.11",
39
39
  "yaml": "^2.8.1"
40
- }
40
+ },
41
+ "gitHead": "bc0ae71617e1e8da950269f0c5a0e765fae2c7aa"
41
42
  }
@@ -1,16 +0,0 @@
1
- import type { CheckContext } from "./types.js";
2
- /**
3
- * Ripgrep's `-t ts` type: `.ts`, `.tsx`, `.cts`, `.mts`. Named once here so the
4
- * 21 detect/verify modules that translate a `rg -t ts '...'` field do not each
5
- * repeat the list.
6
- */
7
- export declare const tsExtensions: string[];
8
- /**
9
- * The shared `CheckContext` implementation — the only place under `src/checks`,
10
- * `src/detect` or `src/verify` that touches the filesystem. Pure Node
11
- * (`node:fs/promises`, regexes): no `rg`, `grep`, `tsc`, or any other
12
- * subprocess, so this runs the same on Windows, in a minimal CI container, or
13
- * without ripgrep installed.
14
- */
15
- export declare const createCheckContext: (path: string) => CheckContext;
16
- //# sourceMappingURL=context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/checks/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,YAAY,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,YAAY,UAAkC,CAAC;AA0B5D;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,SAAU,MAAM,KAAG,YA0CjD,CAAC"}
@@ -1,72 +0,0 @@
1
- import { readFile, readdir } from "node:fs/promises";
2
- import { extname, join } from "node:path";
3
- /**
4
- * Ripgrep's `-t ts` type: `.ts`, `.tsx`, `.cts`, `.mts`. Named once here so the
5
- * 21 detect/verify modules that translate a `rg -t ts '...'` field do not each
6
- * repeat the list.
7
- */
8
- export const tsExtensions = [".ts", ".tsx", ".cts", ".mts"];
9
- /**
10
- * Directories a check must never walk into.
11
- *
12
- * Not optional: `upgrade` runs `verify` after an install, so a walk without
13
- * this excludes a freshly populated `node_modules` — the exact omission that
14
- * was a Critical on this branch for the codemod runner (see `ignorePattern` in
15
- * `src/run/jscodeshift.ts`). `dist` and `.git` are excluded for the same
16
- * reason: build output and VCS internals are not the consumer's code.
17
- */
18
- const excludedDirs = new Set(["node_modules", "dist", ".git"]);
19
- const walk = async (dir) => {
20
- const entries = await readdir(dir, { withFileTypes: true });
21
- const found = await Promise.all(entries.map(async (entry) => {
22
- if (entry.isDirectory()) {
23
- return excludedDirs.has(entry.name) ? [] : walk(join(dir, entry.name));
24
- }
25
- return entry.isFile() ? [join(dir, entry.name)] : [];
26
- }));
27
- return found.flat();
28
- };
29
- /**
30
- * The shared `CheckContext` implementation — the only place under `src/checks`,
31
- * `src/detect` or `src/verify` that touches the filesystem. Pure Node
32
- * (`node:fs/promises`, regexes): no `rg`, `grep`, `tsc`, or any other
33
- * subprocess, so this runs the same on Windows, in a minimal CI container, or
34
- * without ripgrep installed.
35
- */
36
- export const createCheckContext = (path) => {
37
- const files = async (extensions) => {
38
- const all = await walk(path);
39
- return extensions === undefined
40
- ? all
41
- : all.filter((file) => extensions.includes(extname(file)));
42
- };
43
- const read = (file) => readFile(file, "utf8");
44
- const search = async (pattern, extensions) => {
45
- const candidates = await files(extensions);
46
- // A fresh, non-global copy of `pattern`: `.test()` on a `g`-flagged regex
47
- // is stateful (it advances `lastIndex`), which would silently skip matches
48
- // on later lines of the same file, or later files, depending on what the
49
- // caller passed in.
50
- const matcher = new RegExp(pattern.source, pattern.flags.replace("g", ""));
51
- const findings = [];
52
- for (const file of candidates) {
53
- let content;
54
- try {
55
- content = await read(file);
56
- }
57
- catch {
58
- // Unreadable — permissions, a broken symlink, binary content a strict
59
- // decode chokes on. A check skips that one file rather than failing
60
- // the whole run over it.
61
- continue;
62
- }
63
- content.split("\n").forEach((line, index) => {
64
- if (matcher.test(line)) {
65
- findings.push({ file, line: index + 1, text: line.trim() });
66
- }
67
- });
68
- }
69
- return findings;
70
- };
71
- return { path, files, read, search };
72
- };
@@ -1,13 +0,0 @@
1
- import type { Detector, Verifier } from "./types.js";
2
- /**
3
- * Loads the detector for a catalogue id, or `undefined` when none exists yet.
4
- *
5
- * Only a fraction of the catalogue has a module so far — the rest follow in
6
- * later work. `detect`/`verify` (the CLI commands) must treat a missing module
7
- * as "nothing to run for this id" rather than a failure, so callers can loop
8
- * over the whole catalogue without special-casing which ids are covered.
9
- */
10
- export declare const loadDetector: (id: string) => Promise<Detector | undefined>;
11
- /** The `verify` counterpart of {@link loadDetector}. */
12
- export declare const loadVerifier: (id: string) => Promise<Verifier | undefined>;
13
- //# sourceMappingURL=load.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/checks/load.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAuBrD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,OACnB,MAAM,KACT,OAAO,CAAC,QAAQ,GAAG,SAAS,CAiB9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,YAAY,OACnB,MAAM,KACT,OAAO,CAAC,QAAQ,GAAG,SAAS,CAW9B,CAAC"}
@@ -1,53 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { fileURLToPath } from "node:url";
3
- /**
4
- * `<packageRoot>/{src,dist}/detect` and `.../verify`, resolved from wherever
5
- * this module itself runs — `src/checks/load.ts` under vitest (the `.ts`
6
- * sources), `dist/checks/load.js` from the built binary (the compiled `.js`).
7
- * Both mirror the same directory depth, so one relative path serves both.
8
- *
9
- * Unlike `src/transforms` (see the equivalent comment on `transformsDir` in
10
- * `src/run/jscodeshift.ts`), detect and verify modules compile into `dist`
11
- * normally: nothing here needs jscodeshift's babel pipeline, so there is no
12
- * reason to keep them as raw `.ts`.
13
- */
14
- const detectDir = fileURLToPath(new URL("../detect", import.meta.url));
15
- const verifyDir = fileURLToPath(new URL("../verify", import.meta.url));
16
- /**
17
- * Whether `<dir>/<id>` exists as either a compiled `.js` (the built binary) or
18
- * a source `.ts` (running under vitest, straight from `src`).
19
- */
20
- const exists = (dir, id) => existsSync(`${dir}/${id}.js`) || existsSync(`${dir}/${id}.ts`);
21
- /**
22
- * Loads the detector for a catalogue id, or `undefined` when none exists yet.
23
- *
24
- * Only a fraction of the catalogue has a module so far — the rest follow in
25
- * later work. `detect`/`verify` (the CLI commands) must treat a missing module
26
- * as "nothing to run for this id" rather than a failure, so callers can loop
27
- * over the whole catalogue without special-casing which ids are covered.
28
- */
29
- export const loadDetector = async (id) => {
30
- if (!exists(detectDir, id)) {
31
- return undefined;
32
- }
33
- // `@vite-ignore`: the id is only known at runtime, so this can never be a
34
- // static specifier a bundler could pre-resolve — under plain Node (the
35
- // built binary) that is a non-issue, but vitest runs test files through
36
- // Vite's own module graph, and without the comment Vite tries to rewrite
37
- // this into a glob import and fails with "Unknown variable dynamic
38
- // import". The comment tells it to leave the import alone and let Node's
39
- // loader resolve it, same as the built binary does.
40
- const detectModule = (await import(
41
- /* @vite-ignore */ `../detect/${id}.js`));
42
- return detectModule.detector;
43
- };
44
- /** The `verify` counterpart of {@link loadDetector}. */
45
- export const loadVerifier = async (id) => {
46
- if (!exists(verifyDir, id)) {
47
- return undefined;
48
- }
49
- // See the matching comment in `loadDetector` above.
50
- const verifyModule = (await import(
51
- /* @vite-ignore */ `../verify/${id}.js`));
52
- return verifyModule.verifier;
53
- };
@@ -1,49 +0,0 @@
1
- /** Where a check found something, so the reader can go look. */
2
- export interface Finding {
3
- file: string;
4
- line: number;
5
- text: string;
6
- }
7
- /**
8
- * What a check gets. Pure Node — no subprocess, so this works on Windows, in a
9
- * minimal container, and without ripgrep installed.
10
- */
11
- export interface CheckContext {
12
- /** Absolute path to the consumer's sources. */
13
- path: string;
14
- /** Files under `path`, with node_modules / dist / .git excluded. */
15
- files(extensions?: string[]): Promise<string[]>;
16
- read(file: string): Promise<string>;
17
- /** Every match across those files. Most checks need only this. */
18
- search(pattern: RegExp, extensions?: string[]): Promise<Finding[]>;
19
- }
20
- export interface Detector {
21
- detect(context: CheckContext): Promise<Finding[]>;
22
- }
23
- export interface VerifyResult {
24
- /** False when something the check _can_ decide is still wrong. */
25
- ok: boolean;
26
- findings: Finding[];
27
- /**
28
- * What a person must still judge — beyond just running the typechecker.
29
- * Printed under the migration's name. An empty array means this module's own
30
- * check is the whole story (aside from the typecheck below): nothing further
31
- * for a person to weigh.
32
- */
33
- hints: string[];
34
- /**
35
- * The `tsc --noEmit` reminder, kept separate from `hints` so a command can
36
- * tell "still needs a person's judgement" apart from "still needs the routine
37
- * typecheck" instead of string-sniffing prose. Running it is a global check
38
- * and this CLI wraps no commands, so it never becomes a `Finding`. Present
39
- * whenever this migration's correctness depends in some way on the
40
- * typechecker — including to explain that it does _not_ catch a particular
41
- * class of mistake here, which is itself worth telling a person running `tsc
42
- * --noEmit` out of habit.
43
- */
44
- typecheckHint?: string;
45
- }
46
- export interface Verifier {
47
- verify(context: CheckContext): Promise<VerifyResult>;
48
- }
49
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/checks/types.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,kEAAkE;IAClE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACtD"}
File without changes
@@ -1,35 +0,0 @@
1
- import { type CatalogEntry } from "../catalog/entries.js";
2
- import { loadDetector } from "../checks/load.js";
3
- import type { Finding } from "../checks/types.js";
4
- export interface DetectEntryResult {
5
- entry: CatalogEntry;
6
- findings: Finding[];
7
- }
8
- export interface RunDetectDeps {
9
- /** Which entries to try. Defaults to the whole catalogue. */
10
- entries?: CatalogEntry[];
11
- /** Injectable for tests — defaults to the real module loader. */
12
- load?: typeof loadDetector;
13
- }
14
- /**
15
- * Runs every available detector over `path` and returns only the entries that
16
- * found something.
17
- *
18
- * Only a fraction of the catalogue has a detector module so far (see
19
- * `checks/load.ts`); an id with none is skipped rather than treated as a
20
- * failure — the remaining detectors are mechanical follow-up work, not a bug in
21
- * this command.
22
- */
23
- export declare const runDetect: (path: string, { entries, load }?: RunDetectDeps) => Promise<DetectEntryResult[]>;
24
- /**
25
- * Renders `runDetect`'s result as text — the presentation half kept separate
26
- * from the async file-reading half, the same split `renderList` uses, so
27
- * formatting is testable without touching a file. Reuses `renderList`'s
28
- * vocabulary (`painter`, `wrap`, `indent`) rather than a second
29
- * implementation.
30
- */
31
- export declare const renderDetect: (results: DetectEntryResult[], path: string, { color, width }?: {
32
- color?: boolean;
33
- width?: number;
34
- }) => string;
35
- //# sourceMappingURL=detect.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/cli/detect.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,iEAAiE;IACjE,IAAI,CAAC,EAAE,OAAO,YAAY,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,SACd,MAAM,sBACmC,aAAa,KAC3D,OAAO,CAAC,iBAAiB,EAAE,CAgB7B,CAAC;AAeF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,YACd,iBAAiB,EAAE,QACtB,MAAM,qBACmB;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KACjE,MAuBF,CAAC"}
@@ -1,62 +0,0 @@
1
- import colors from "picocolors";
2
- import { allEntries } from "../catalog/entries.js";
3
- import { createCheckContext } from "../checks/context.js";
4
- import { loadDetector } from "../checks/load.js";
5
- import { indent, painter, wrap } from "./list.js";
6
- /**
7
- * Runs every available detector over `path` and returns only the entries that
8
- * found something.
9
- *
10
- * Only a fraction of the catalogue has a detector module so far (see
11
- * `checks/load.ts`); an id with none is skipped rather than treated as a
12
- * failure — the remaining detectors are mechanical follow-up work, not a bug in
13
- * this command.
14
- */
15
- export const runDetect = async (path, { entries = allEntries, load = loadDetector } = {}) => {
16
- const context = createCheckContext(path);
17
- const results = [];
18
- for (const entry of entries) {
19
- const detector = await load(entry.id);
20
- if (detector === undefined) {
21
- continue;
22
- }
23
- const findings = await detector.detect(context);
24
- if (findings.length > 0) {
25
- results.push({ entry, findings });
26
- }
27
- }
28
- return results;
29
- };
30
- /** One `file:line text` row, wrapped and indented like `renderList`'s rows. */
31
- const findingLine = (finding, width, paint) => {
32
- const location = paint.dim(`${finding.file}:${finding.line}`);
33
- const body = wrap(finding.text, Math.max(width - indent.length, 20));
34
- return body.map((line, index) => index === 0 ? `${indent}${location} ${line}` : `${indent} ${line}`);
35
- };
36
- /**
37
- * Renders `runDetect`'s result as text — the presentation half kept separate
38
- * from the async file-reading half, the same split `renderList` uses, so
39
- * formatting is testable without touching a file. Reuses `renderList`'s
40
- * vocabulary (`painter`, `wrap`, `indent`) rather than a second
41
- * implementation.
42
- */
43
- export const renderDetect = (results, path, { color = false, width = 80 } = {}) => {
44
- const paint = painter(color);
45
- if (results.length === 0) {
46
- return `No migrations under ${path} were found by the available detectors.\n`;
47
- }
48
- const noun = results.length === 1 ? "migration" : "migrations";
49
- const verb = results.length === 1 ? "touches" : "touch";
50
- const header = `${paint.bold(`${results.length} ${noun}`)} ${verb} ${path}\n`;
51
- const body = results
52
- .map(({ entry, findings }) => {
53
- const mark = color ? colors.green("●") : "*";
54
- const lines = [
55
- `${mark} ${paint.bold(entry.id)}`,
56
- ...findings.flatMap((finding) => findingLine(finding, width, paint)),
57
- ];
58
- return lines.join("\n");
59
- })
60
- .join("\n\n");
61
- return `${header}\n${body}\n`;
62
- };
@@ -1,77 +0,0 @@
1
- import { type CatalogEntry } from "../catalog/entries.js";
2
- import { loadVerifier } from "../checks/load.js";
3
- import type { VerifyResult } from "../checks/types.js";
4
- export interface VerifyEntryResult {
5
- entry: CatalogEntry;
6
- result: VerifyResult;
7
- }
8
- export interface RunVerifyDeps {
9
- /** Which entries to try. Defaults to the whole catalogue. */
10
- entries?: CatalogEntry[];
11
- /** Injectable for tests — defaults to the real module loader. */
12
- load?: typeof loadVerifier;
13
- }
14
- /**
15
- * Runs every available verifier over `path`.
16
- *
17
- * Only a fraction of the catalogue has a verifier module so far (see
18
- * `checks/load.ts`); an id with none is skipped, not reported as a failure —
19
- * the remaining verifiers are follow-up work, not something this run got
20
- * wrong.
21
- */
22
- export declare const runVerify: (path: string, { entries, load }?: RunVerifyDeps) => Promise<VerifyEntryResult[]>;
23
- /**
24
- * Three counts, not one pass/fail verdict — conflating them is exactly the "23
25
- * entries still need a person" problem this replaces: with every verifier in
26
- * place, almost all of them would carry at least the typecheck reminder, so
27
- * counting "has a hint" swamps the entries that actually need a person's
28
- * judgement with the ones that only need the same routine `tsc --noEmit` run.
29
- *
30
- * - `failed` — `ok: false`: this run found something concretely wrong.
31
- * - `needsReview` — `ok: true` but `hints` is non-empty: nothing this module
32
- * could decide is wrong, but a person still has to judge something no
33
- * compiler check can catch.
34
- * - `verified` — `ok: true` and `hints` is empty: nothing left for a person to
35
- * judge here (the typecheck below may still apply). Deliberately not
36
- * "done"/"complete": see `checks/types.ts`'s doc comment on `VerifyResult`
37
- * for why `ok: true` never means the migration is finished.
38
- *
39
- * `typecheckCount` is tallied separately again: it is not a judgement call like
40
- * `needsReview`, and `tsc --noEmit` is one command a person runs once for the
41
- * whole project, not once per entry — so it is reported as a single closing
42
- * line, not folded into any of the three per-entry buckets.
43
- */
44
- export declare const summarize: (results: VerifyEntryResult[]) => {
45
- failed: number;
46
- needsReview: number;
47
- verified: number;
48
- typecheckCount: number;
49
- };
50
- /**
51
- * Renders `runVerify`'s result as text — the presentation half kept separate
52
- * from the async file-reading half, the same split `renderList` uses.
53
- *
54
- * Prints only what needs attention. An entry that is `ok: true` with no hints
55
- * has nothing left for a person to judge (the closing typecheck line still
56
- * covers it if it relies on one) — it swells the count in the header and
57
- * nothing else, the same way `verified` is counted but never itself printed.
58
- * That is the fix for the four problems the maintainer called out: a passing
59
- * entry whose only hint was the typecheck reminder no longer earns a block at
60
- * all, the reminder itself moves out of the loop to one line at the end,
61
- * hints stop repeating their own label, and findings show a path relative to
62
- * `path` instead of the absolute one the header already established.
63
- */
64
- export declare const renderVerify: (results: VerifyEntryResult[], path: string, { color, width }?: {
65
- color?: boolean;
66
- width?: number;
67
- }) => string;
68
- /**
69
- * Whether a `verify` run should exit non-zero: exactly when at least one
70
- * verifier decided `ok: false`. A hint alone — even every entry carrying one —
71
- * is the normal "a person still has to look" state, not a failure, so it must
72
- * never flip this. Kept as its own pure function (over `results`, not
73
- * `process.exitCode` directly) so a test can drive it with injected fakes
74
- * instead of spawning the CLI.
75
- */
76
- export declare const verifyExitCode: (results: VerifyEntryResult[]) => number;
77
- //# sourceMappingURL=verify.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/cli/verify.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,iEAAiE;IACjE,IAAI,CAAC,EAAE,OAAO,YAAY,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,SACd,MAAM,sBACmC,aAAa,KAC3D,OAAO,CAAC,iBAAiB,EAAE,CAa7B,CAAC;AA2DF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,SAAS,YACX,iBAAiB,EAAE,KAC3B;IACD,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CAqBxB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,YACd,iBAAiB,EAAE,QACtB,MAAM,qBACmB;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KACjE,MA8BF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,YAAa,iBAAiB,EAAE,KAAG,MACZ,CAAC"}
@@ -1,148 +0,0 @@
1
- import { relative } from "node:path";
2
- import colors from "picocolors";
3
- import { allEntries } from "../catalog/entries.js";
4
- import { createCheckContext } from "../checks/context.js";
5
- import { loadVerifier } from "../checks/load.js";
6
- import { indent, painter, wrap } from "./list.js";
7
- /**
8
- * Runs every available verifier over `path`.
9
- *
10
- * Only a fraction of the catalogue has a verifier module so far (see
11
- * `checks/load.ts`); an id with none is skipped, not reported as a failure —
12
- * the remaining verifiers are follow-up work, not something this run got
13
- * wrong.
14
- */
15
- export const runVerify = async (path, { entries = allEntries, load = loadVerifier } = {}) => {
16
- const context = createCheckContext(path);
17
- const results = [];
18
- for (const entry of entries) {
19
- const verifier = await load(entry.id);
20
- if (verifier === undefined) {
21
- continue;
22
- }
23
- results.push({ entry, result: await verifier.verify(context) });
24
- }
25
- return results;
26
- };
27
- /** One `path:line text` row, path shown relative to the search root. */
28
- const findingLine = (finding, width, paint, root) => {
29
- const location = paint.dim(`${relative(root, finding.file)}:${finding.line}`);
30
- const body = wrap(finding.text, Math.max(width - indent.length, 20));
31
- return body.map((line, index) => index === 0 ? `${indent}${location} ${line}` : `${indent} ${line}`);
32
- };
33
- /**
34
- * One hint, wrapped and indented under its migration. No repeated label — a
35
- * hint that wraps to several lines said "hint" once per line before this,
36
- * which is the label, not the content, taking up the repetition.
37
- */
38
- const hintLine = (hint, width) => wrap(hint, Math.max(width - indent.length, 20)).map((line) => `${indent}${line}`);
39
- /**
40
- * Renders one migration's block: `!` for `ok: false`, `?` for `ok: true` with
41
- * a hint — the only two states this function is ever called for, see
42
- * `renderVerify`'s filter. Findings first, then hints; the `typecheckHint`
43
- * never appears here — it is one global action, folded into the closing line
44
- * instead of repeated under every entry that relies on it.
45
- */
46
- const renderEntry = ({ entry, result }, width, color, root) => {
47
- const paint = painter(color);
48
- const mark = result.ok
49
- ? color
50
- ? colors.yellow("?")
51
- : "?"
52
- : color
53
- ? colors.red("!")
54
- : "!";
55
- const lines = [
56
- `${mark} ${paint.bold(entry.id)}`,
57
- ...result.findings.flatMap((finding) => findingLine(finding, width, paint, root)),
58
- ...result.hints.flatMap((hint) => hintLine(hint, width)),
59
- ];
60
- return lines.join("\n");
61
- };
62
- /**
63
- * Three counts, not one pass/fail verdict — conflating them is exactly the "23
64
- * entries still need a person" problem this replaces: with every verifier in
65
- * place, almost all of them would carry at least the typecheck reminder, so
66
- * counting "has a hint" swamps the entries that actually need a person's
67
- * judgement with the ones that only need the same routine `tsc --noEmit` run.
68
- *
69
- * - `failed` — `ok: false`: this run found something concretely wrong.
70
- * - `needsReview` — `ok: true` but `hints` is non-empty: nothing this module
71
- * could decide is wrong, but a person still has to judge something no
72
- * compiler check can catch.
73
- * - `verified` — `ok: true` and `hints` is empty: nothing left for a person to
74
- * judge here (the typecheck below may still apply). Deliberately not
75
- * "done"/"complete": see `checks/types.ts`'s doc comment on `VerifyResult`
76
- * for why `ok: true` never means the migration is finished.
77
- *
78
- * `typecheckCount` is tallied separately again: it is not a judgement call like
79
- * `needsReview`, and `tsc --noEmit` is one command a person runs once for the
80
- * whole project, not once per entry — so it is reported as a single closing
81
- * line, not folded into any of the three per-entry buckets.
82
- */
83
- export const summarize = (results) => {
84
- let failed = 0;
85
- let needsReview = 0;
86
- let verified = 0;
87
- let typecheckCount = 0;
88
- for (const { result } of results) {
89
- if (!result.ok) {
90
- failed++;
91
- }
92
- else if (result.hints.length > 0) {
93
- needsReview++;
94
- }
95
- else {
96
- verified++;
97
- }
98
- if (result.typecheckHint !== undefined) {
99
- typecheckCount++;
100
- }
101
- }
102
- return { failed, needsReview, verified, typecheckCount };
103
- };
104
- /**
105
- * Renders `runVerify`'s result as text — the presentation half kept separate
106
- * from the async file-reading half, the same split `renderList` uses.
107
- *
108
- * Prints only what needs attention. An entry that is `ok: true` with no hints
109
- * has nothing left for a person to judge (the closing typecheck line still
110
- * covers it if it relies on one) — it swells the count in the header and
111
- * nothing else, the same way `verified` is counted but never itself printed.
112
- * That is the fix for the four problems the maintainer called out: a passing
113
- * entry whose only hint was the typecheck reminder no longer earns a block at
114
- * all, the reminder itself moves out of the loop to one line at the end,
115
- * hints stop repeating their own label, and findings show a path relative to
116
- * `path` instead of the absolute one the header already established.
117
- */
118
- export const renderVerify = (results, path, { color = false, width = 80 } = {}) => {
119
- const paint = painter(color);
120
- if (results.length === 0) {
121
- return `No verifiers are available yet for anything under ${path}.\n`;
122
- }
123
- const { failed, needsReview, typecheckCount } = summarize(results);
124
- const header = [
125
- `${paint.bold(String(results.length))} checked`,
126
- `${paint.bold(String(failed))} failed`,
127
- `${paint.bold(String(needsReview))} needs review`,
128
- ].join(" · ");
129
- const needsAttention = results.filter(({ result }) => !result.ok || result.hints.length > 0);
130
- const body = needsAttention.length === 0
131
- ? "Nothing needs attention."
132
- : needsAttention
133
- .map((entryResult) => renderEntry(entryResult, width, color, path))
134
- .join("\n\n");
135
- const typecheckLine = typecheckCount === 0
136
- ? ""
137
- : `\n\nThen run \`tsc --noEmit\` once — ${typecheckCount} of these rely on it.`;
138
- return `${header}\n\n${body}${typecheckLine}\n`;
139
- };
140
- /**
141
- * Whether a `verify` run should exit non-zero: exactly when at least one
142
- * verifier decided `ok: false`. A hint alone — even every entry carrying one —
143
- * is the normal "a person still has to look" state, not a failure, so it must
144
- * never flip this. Kept as its own pure function (over `results`, not
145
- * `process.exitCode` directly) so a test can drive it with injected fakes
146
- * instead of spawning the CLI.
147
- */
148
- export const verifyExitCode = (results) => results.some(({ result }) => !result.ok) ? 1 : 0;
@@ -1,8 +0,0 @@
1
- import type { Detector } from "../checks/types.js";
2
- /**
3
- * Translated from the catalogue's `detect: rg -t ts '\bAlign(Props)?\b'` — see
4
- * the translation rule in the plan: `rg -t ts 'PATTERN'` becomes
5
- * `search(/PATTERN/, tsExtensions)`.
6
- */
7
- export declare const detector: Detector;
8
- //# sourceMappingURL=align-to-combine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"align-to-combine.d.ts","sourceRoot":"","sources":["../../src/detect/align-to-combine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,QAEtB,CAAC"}
@@ -1,9 +0,0 @@
1
- import { tsExtensions } from "../checks/context.js";
2
- /**
3
- * Translated from the catalogue's `detect: rg -t ts '\bAlign(Props)?\b'` — see
4
- * the translation rule in the plan: `rg -t ts 'PATTERN'` becomes
5
- * `search(/PATTERN/, tsExtensions)`.
6
- */
7
- export const detector = {
8
- detect: (context) => context.search(/\bAlign(Props)?\b/, tsExtensions),
9
- };
@@ -1,9 +0,0 @@
1
- import type { Detector } from "../checks/types.js";
2
- /**
3
- * Translated from the catalogue's `detect: rg -t ts 'addOnClose|addOnOpen'`.
4
- * Every call site needs a by-hand look at its handler — see
5
- * `src/verify/overlay-controller-add-on-close-return-type.ts` for why no
6
- * compiler check can narrow this list further.
7
- */
8
- export declare const detector: Detector;
9
- //# sourceMappingURL=overlay-controller-add-on-close-return-type.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"overlay-controller-add-on-close-return-type.d.ts","sourceRoot":"","sources":["../../src/detect/overlay-controller-add-on-close-return-type.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,QAEtB,CAAC"}
@@ -1,10 +0,0 @@
1
- import { tsExtensions } from "../checks/context.js";
2
- /**
3
- * Translated from the catalogue's `detect: rg -t ts 'addOnClose|addOnOpen'`.
4
- * Every call site needs a by-hand look at its handler — see
5
- * `src/verify/overlay-controller-add-on-close-return-type.ts` for why no
6
- * compiler check can narrow this list further.
7
- */
8
- export const detector = {
9
- detect: (context) => context.search(/addOnClose|addOnOpen/, tsExtensions),
10
- };