no-mistakes 0.8.0 → 0.9.1

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 CHANGED
@@ -11,6 +11,73 @@ npx no-mistakes symbols src/utils.mts --json
11
11
  npx no-mistakes check --json
12
12
  ```
13
13
 
14
+ Programmatic Node usage loads the same Rust analysis through N-API:
15
+
16
+ ```js
17
+ const {
18
+ dependencies,
19
+ dependents,
20
+ check,
21
+ fetches,
22
+ playwrightRelated,
23
+ symbols,
24
+ testsPlan,
25
+ queueEdges,
26
+ queueRelated,
27
+ queueCheck,
28
+ serverRouteList,
29
+ serverRouteEdges,
30
+ serverRouteRelated,
31
+ reactAnalyze,
32
+ reactCheck,
33
+ } = require("no-mistakes");
34
+
35
+ (async () => {
36
+ const deps = await dependencies({
37
+ root: process.cwd(),
38
+ files: ["src/main.mts"],
39
+ relationships: ["import"],
40
+ });
41
+ const tests = await dependents({
42
+ root: process.cwd(),
43
+ files: ["src/utils.mts"],
44
+ tests: ["vitest"],
45
+ });
46
+ const symbolFacts = await symbols({
47
+ root: process.cwd(),
48
+ files: ["src/utils.mts"],
49
+ include: "both",
50
+ });
51
+ const plan = await testsPlan({
52
+ root: process.cwd(),
53
+ framework: "vitest",
54
+ changedFiles: ["src/utils.mts"],
55
+ });
56
+ const projectCheck = await check({
57
+ root: process.cwd(),
58
+ tsconfig: "tsconfig.json",
59
+ });
60
+ const coveredByPlaywright = await playwrightRelated({
61
+ root: process.cwd(),
62
+ files: ["web/app/users/page.tsx"],
63
+ });
64
+
65
+ const queueHops = await queueRelated({
66
+ root: process.cwd(),
67
+ files: ["src/jobs/enqueue.ts"],
68
+ direction: "both",
69
+ });
70
+ const routeEdges = await serverRouteEdges({
71
+ root: process.cwd(),
72
+ roots: ["src/server.ts"],
73
+ });
74
+ const components = await reactAnalyze({
75
+ root: process.cwd(),
76
+ targets: ["app/**/*.tsx"],
77
+ });
78
+ })();
79
+ ```
80
+
14
81
  External `no-mistakes-*` executables on `PATH` can be invoked as subcommands.
15
82
  For example, after installing `no-mistakes-scripts`:
16
83
 
@@ -0,0 +1 @@
1
+ Native binary placeholder. Replaced by scripts/install.js during npm postinstall.
package/index.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ import type {
2
+ CheckReport,
3
+ DependencyResult,
4
+ FetchesOptions,
5
+ GraphEdge,
6
+ PlaywrightOptions,
7
+ PlaywrightRelatedOptions,
8
+ ProjectOptions,
9
+ QueueReport,
10
+ ReactComponentFacts,
11
+ ReactViolation,
12
+ ServerRoutesReport,
13
+ SymbolsOptions,
14
+ SymbolsResult,
15
+ TestGraph,
16
+ TestPlan,
17
+ TestsPlanDocumentOptions,
18
+ TestsPlanOptions,
19
+ TestsWhyOptions,
20
+ TraverseOptions,
21
+ WhyStep,
22
+ } from "./types";
23
+
24
+ export * from "./types";
25
+
26
+ export function dependencies(options: TraverseOptions): Promise<DependencyResult>;
27
+ export function dependents(options: TraverseOptions): Promise<DependencyResult>;
28
+ export function related(options: TraverseOptions): Promise<DependencyResult>;
29
+ export function symbols(options: SymbolsOptions): Promise<SymbolsResult>;
30
+ export function fetches(options?: FetchesOptions): Promise<unknown>;
31
+ export function check(options?: ProjectOptions): Promise<CheckReport>;
32
+ export function testsPlan(options: TestsPlanOptions): Promise<TestPlan>;
33
+ export function testsWhy(options: TestsWhyOptions): Promise<Record<string, WhyStep[]>>;
34
+ export function testsComment(options: TestsPlanDocumentOptions): Promise<string>;
35
+ export function testsGraph(options: TestsPlanDocumentOptions): Promise<TestGraph>;
36
+ export function testsGraphMermaid(options: TestsPlanDocumentOptions): Promise<string>;
37
+ export function playwrightCheck(options?: PlaywrightOptions): Promise<unknown>;
38
+ export function playwrightEdges(options?: PlaywrightOptions): Promise<unknown>;
39
+ export function playwrightRelated(options: PlaywrightRelatedOptions): Promise<unknown>;
40
+ export function playwrightTests(options?: PlaywrightOptions): Promise<unknown>;
41
+ export function queues(options?: ProjectOptions): Promise<QueueReport>;
42
+ export function queueEdges(options?: ProjectOptions): Promise<GraphEdge[]>;
43
+ export function queueRelated(options: ProjectOptions): Promise<GraphEdge[]>;
44
+ export function queueCheck(options?: ProjectOptions): Promise<unknown[]>;
45
+ export function serverRoutes(options?: ProjectOptions): Promise<ServerRoutesReport>;
46
+ export function serverRouteList(options?: ProjectOptions): Promise<unknown[]>;
47
+ export function serverRouteEdges(options?: ProjectOptions): Promise<GraphEdge[]>;
48
+ export function serverRouteRelated(options: ProjectOptions): Promise<GraphEdge[]>;
49
+ export function reactAnalyze(options?: ProjectOptions): Promise<ReactComponentFacts[]>;
50
+ export function reactCheck(options?: ProjectOptions): Promise<ReactViolation[]>;
51
+ export function version(): Promise<string>;
package/index.js ADDED
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+
3
+ const native = require("./bin/no-mistakes.node");
4
+
5
+ async function callJson(fn, options) {
6
+ return JSON.parse(await fn(JSON.stringify(options || {})));
7
+ }
8
+
9
+ async function dependencies(options) {
10
+ return callJson(native.dependenciesJson, options);
11
+ }
12
+
13
+ async function dependents(options) {
14
+ return callJson(native.dependentsJson, options);
15
+ }
16
+
17
+ async function related(options) {
18
+ return callJson(native.relatedJson, options);
19
+ }
20
+
21
+ async function symbols(options) {
22
+ return callJson(native.symbolsJson, options);
23
+ }
24
+
25
+ async function fetches(options) {
26
+ return callJson(native.fetchesJson, options);
27
+ }
28
+
29
+ async function check(options) {
30
+ return callJson(native.checkJson, options);
31
+ }
32
+
33
+ async function testsPlan(options) {
34
+ return callJson(native.testsPlanJson, options);
35
+ }
36
+
37
+ async function testsWhy(options) {
38
+ return callJson(native.testsWhyJson, options);
39
+ }
40
+
41
+ async function testsComment(options) {
42
+ return native.testsCommentMarkdown(JSON.stringify(options || {}));
43
+ }
44
+
45
+ async function testsGraph(options) {
46
+ return callJson(native.testsGraphJson, options);
47
+ }
48
+
49
+ async function testsGraphMermaid(options) {
50
+ return native.testsGraphMermaid(JSON.stringify(options || {}));
51
+ }
52
+
53
+ async function playwrightCheck(options) {
54
+ return callJson(native.playwrightCheckJson, options);
55
+ }
56
+
57
+ async function playwrightEdges(options) {
58
+ return callJson(native.playwrightEdgesJson, options);
59
+ }
60
+
61
+ async function playwrightRelated(options) {
62
+ return callJson(native.playwrightRelatedJson, options);
63
+ }
64
+
65
+ async function playwrightTests(options) {
66
+ return callJson(native.playwrightTestsJson, options);
67
+ }
68
+
69
+ async function queues(options) {
70
+ return callJson(native.queuesJson, options);
71
+ }
72
+
73
+ async function queueEdges(options) {
74
+ return callJson(native.queueEdgesJson, options);
75
+ }
76
+
77
+ async function queueRelated(options) {
78
+ return callJson(native.queueRelatedJson, options);
79
+ }
80
+
81
+ async function queueCheck(options) {
82
+ return callJson(native.queueCheckJson, options);
83
+ }
84
+
85
+ async function serverRoutes(options) {
86
+ return callJson(native.serverRoutesJson, options);
87
+ }
88
+
89
+ async function serverRouteList(options) {
90
+ return callJson(native.serverRouteListJson, options);
91
+ }
92
+
93
+ async function serverRouteEdges(options) {
94
+ return callJson(native.serverRouteEdgesJson, options);
95
+ }
96
+
97
+ async function serverRouteRelated(options) {
98
+ return callJson(native.serverRouteRelatedJson, options);
99
+ }
100
+
101
+ async function reactAnalyze(options) {
102
+ return callJson(native.reactAnalyzeJson, options);
103
+ }
104
+
105
+ async function reactCheck(options) {
106
+ return callJson(native.reactCheckJson, options);
107
+ }
108
+
109
+ async function version() {
110
+ return native.version();
111
+ }
112
+
113
+ module.exports = {
114
+ check,
115
+ dependencies,
116
+ dependents,
117
+ fetches,
118
+ playwrightCheck,
119
+ playwrightEdges,
120
+ playwrightRelated,
121
+ playwrightTests,
122
+ queues,
123
+ queueCheck,
124
+ queueEdges,
125
+ queueRelated,
126
+ reactAnalyze,
127
+ reactCheck,
128
+ related,
129
+ serverRouteEdges,
130
+ serverRouteList,
131
+ serverRouteRelated,
132
+ serverRoutes,
133
+ symbols,
134
+ testsComment,
135
+ testsGraph,
136
+ testsGraphMermaid,
137
+ testsPlan,
138
+ testsWhy,
139
+ version,
140
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "no-mistakes",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Static codebase analysis tools for TS/JS dependencies, dependents, and symbols",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,11 +13,15 @@
13
13
  },
14
14
  "files": [
15
15
  "bin/",
16
+ "*.d.ts",
17
+ "index.js",
16
18
  "scripts/install.js",
17
19
  "scripts/install/",
18
20
  "README.md",
19
21
  "LICENSE"
20
22
  ],
23
+ "main": "index.js",
24
+ "types": "index.d.ts",
21
25
  "publishConfig": {
22
26
  "access": "public"
23
27
  },
@@ -0,0 +1,73 @@
1
+ export interface PlaywrightOptions {
2
+ root?: string;
3
+ config?: string;
4
+ playwrightConfig?: string[];
5
+ project?: string;
6
+ files?: string[];
7
+ assertConditionalTests?: boolean;
8
+ allowSkippedTests?: boolean;
9
+ assertUniqueTestIds?: boolean;
10
+ assertUniqueHtmlIds?: boolean;
11
+ assertUniqueSelectors?: boolean;
12
+ }
13
+
14
+ export interface PlaywrightRelatedOptions extends PlaywrightOptions {
15
+ files: string[];
16
+ }
17
+
18
+ export interface CheckReport {
19
+ react: ReactViolation[];
20
+ queues: unknown[];
21
+ rules: unknown[];
22
+ integration: unknown[];
23
+ codebase: unknown[];
24
+ }
25
+
26
+ export interface QueueReport {
27
+ producers: unknown[];
28
+ workers: unknown[];
29
+ jobs: unknown[];
30
+ edges: unknown[];
31
+ diagnostics: unknown[];
32
+ check: unknown[];
33
+ }
34
+
35
+ export interface GraphEdge {
36
+ from: string;
37
+ to: string;
38
+ kind: string;
39
+ }
40
+
41
+ export interface ServerRoutesReport {
42
+ summary: {
43
+ totalRoutes: number;
44
+ totalFiles: number;
45
+ dynamicRoutes: number;
46
+ };
47
+ routes: unknown[];
48
+ edges: unknown[];
49
+ diagnostics: unknown[];
50
+ }
51
+
52
+ export interface ReactComponentFacts {
53
+ name: string;
54
+ file: string;
55
+ environment: "server" | "client" | "shared" | "unknown";
56
+ hasState: boolean;
57
+ hasProps: boolean;
58
+ passesProps: boolean;
59
+ usesMemo: boolean;
60
+ usesContextProvider: boolean;
61
+ usesSuspense: boolean;
62
+ fetches: unknown[];
63
+ dependencies: string[];
64
+ children: unknown[];
65
+ inheritedFromChildren?: unknown;
66
+ }
67
+
68
+ export interface ReactViolation {
69
+ component: string;
70
+ file: string;
71
+ rule: string;
72
+ detail?: string;
73
+ }
@@ -2,8 +2,8 @@
2
2
 
3
3
  const { basename } = require("node:path");
4
4
 
5
- function assetName(binName, version, target) {
6
- const ext = target.endsWith("windows-msvc") ? ".exe" : "";
5
+ function assetName(binName, version, target, assetExtension) {
6
+ const ext = assetExtension ?? (target.endsWith("windows-msvc") ? ".exe" : "");
7
7
  return `${binName}-v${version}-${target}${ext}`;
8
8
  }
9
9
 
@@ -52,7 +52,7 @@ async function install(binName, repository, options = {}) {
52
52
  return destination;
53
53
  }
54
54
 
55
- const asset = assetName(binName, version, target);
55
+ const asset = assetName(binName, version, target, options.assetExtension);
56
56
  const baseUrl = options.baseUrl || releaseBaseUrl(repository, version, options.envVar);
57
57
  const temp = `${destination}.tmp-${process.pid}`;
58
58
 
@@ -9,14 +9,24 @@ const PACKAGE_ROOT = join(__dirname, "..");
9
9
  async function main(installFn = install, io = process, logger = console) {
10
10
  try {
11
11
  const pkg = require(join(PACKAGE_ROOT, "package.json"));
12
- const destination = await installFn("no-mistakes", "jonathanong/no-mistakes", {
12
+ const binDir = join(PACKAGE_ROOT, "bin");
13
+ const binaryDestination = await installFn("no-mistakes", "jonathanong/no-mistakes", {
13
14
  version: pkg.version,
14
- vendorDir: join(PACKAGE_ROOT, "bin"),
15
+ vendorDir: binDir,
15
16
  destinationName: "no-mistakes",
16
17
  envVar: "NO_MISTAKES_RELEASE_BASE_URL",
17
18
  checkExisting: true,
18
19
  });
19
- logger.log(`Installed no-mistakes native binary to ${destination}`);
20
+ const addonDestination = await installFn("no-mistakes-napi", "jonathanong/no-mistakes", {
21
+ version: pkg.version,
22
+ vendorDir: binDir,
23
+ destinationName: "no-mistakes.node",
24
+ assetExtension: ".node",
25
+ envVar: "NO_MISTAKES_RELEASE_BASE_URL",
26
+ checkExisting: true,
27
+ });
28
+ logger.log(`Installed no-mistakes native binary to ${binaryDestination}`);
29
+ logger.log(`Installed no-mistakes N-API addon to ${addonDestination}`);
20
30
  } catch (error) {
21
31
  logger.error(error instanceof Error ? error.message : String(error));
22
32
  io.exit(1);
@@ -0,0 +1,70 @@
1
+ export interface TestsPlanOptions {
2
+ framework?: "vitest" | "playwright";
3
+ root?: string;
4
+ config?: string;
5
+ tsconfig?: string;
6
+ base?: string;
7
+ head?: string;
8
+ changedFiles?: string[];
9
+ changedFilesFile?: string;
10
+ environment?: string;
11
+ limitPercent?: number;
12
+ limitFiles?: number;
13
+ }
14
+
15
+ export interface TestPlan {
16
+ selected_tests: SelectedTest[];
17
+ groups?: TestPlanGroup[];
18
+ warnings: TestPlanWarning[];
19
+ fallback_triggered: boolean;
20
+ fallback_reason?: string | null;
21
+ }
22
+
23
+ export interface SelectedTest {
24
+ test_file: string;
25
+ confidence: "low" | "medium" | "high";
26
+ reasons: ImpactReason[];
27
+ }
28
+
29
+ export interface ImpactReason {
30
+ changed_file: string;
31
+ path: string[];
32
+ via: string[];
33
+ }
34
+
35
+ export interface TestPlanGroup {
36
+ type: string;
37
+ selected: string[];
38
+ remaining: number;
39
+ limit?: number | null;
40
+ }
41
+
42
+ export interface TestPlanWarning {
43
+ type: string;
44
+ message: string;
45
+ file: string;
46
+ }
47
+
48
+ export interface TestsWhyOptions {
49
+ root?: string;
50
+ config?: string;
51
+ tsconfig?: string;
52
+ test: string;
53
+ changed?: string;
54
+ plan?: string;
55
+ }
56
+
57
+ export interface WhyStep {
58
+ node: string;
59
+ via?: string | null;
60
+ }
61
+
62
+ export interface TestsPlanDocumentOptions {
63
+ plan?: string;
64
+ planJson?: TestPlan | string;
65
+ }
66
+
67
+ export interface TestGraph {
68
+ nodes: Array<{ name: string; type: "changed" | "test" | "intermediate" }>;
69
+ edges: Array<{ from: string; to: string; via: string }>;
70
+ }
@@ -0,0 +1,113 @@
1
+ export type Relationship =
2
+ | "import"
3
+ | "import-static"
4
+ | "import-dynamic"
5
+ | "import-type"
6
+ | "import-require"
7
+ | "workspace"
8
+ | "package"
9
+ | "test"
10
+ | "route"
11
+ | "queue"
12
+ | "md"
13
+ | "ci"
14
+ | "http"
15
+ | "process"
16
+ | "asset"
17
+ | "react"
18
+ | "all";
19
+
20
+ export interface TraverseOptions {
21
+ files: string[];
22
+ root?: string;
23
+ tsconfig?: string;
24
+ depth?: number;
25
+ filters?: string[];
26
+ targetModules?: string[];
27
+ tests?: string[];
28
+ relationships?: Relationship[];
29
+ }
30
+
31
+ export interface DependencyFile {
32
+ path?: string;
33
+ queueFile?: string;
34
+ job?: string;
35
+ module?: string;
36
+ depth: number;
37
+ via?: string[];
38
+ }
39
+
40
+ export interface DependencyResult {
41
+ roots: string[];
42
+ files: DependencyFile[];
43
+ }
44
+
45
+ export type ExportKind =
46
+ | "function"
47
+ | "class"
48
+ | "const"
49
+ | "let"
50
+ | "var"
51
+ | "type"
52
+ | "interface"
53
+ | "enum"
54
+ | "default"
55
+ | "re-export";
56
+
57
+ export interface SymbolsOptions {
58
+ files: string[];
59
+ root?: string;
60
+ tsconfig?: string;
61
+ kinds?: ExportKind[];
62
+ include?: "exports" | "imports" | "both";
63
+ }
64
+
65
+ export interface SymbolExport {
66
+ name: string;
67
+ kind: string;
68
+ line: number;
69
+ reExport?: {
70
+ source: string;
71
+ imported: string;
72
+ resolved?: string;
73
+ };
74
+ }
75
+
76
+ export interface SymbolImport {
77
+ source: string;
78
+ imported: string;
79
+ local: string;
80
+ line: number;
81
+ typeOnly: boolean;
82
+ resolved?: string;
83
+ }
84
+
85
+ export interface SymbolFile {
86
+ path: string;
87
+ exports?: SymbolExport[];
88
+ imports?: SymbolImport[];
89
+ }
90
+
91
+ export interface SymbolsResult {
92
+ roots: string[];
93
+ files: SymbolFile[];
94
+ }
95
+
96
+ export interface ProjectOptions {
97
+ root?: string;
98
+ tsconfig?: string;
99
+ config?: string;
100
+ filters?: string[];
101
+ targets?: string[];
102
+ files?: string[];
103
+ roots?: string[];
104
+ depth?: number;
105
+ assertNoFetch?: boolean;
106
+ direction?: "deps" | "dependents" | "both";
107
+ }
108
+
109
+ export interface FetchesOptions {
110
+ root?: string;
111
+ config?: string;
112
+ targets?: string[];
113
+ }
package/types.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./traversal-types";
2
+ export * from "./test-types";
3
+ export * from "./report-types";