roto-rooter 0.0.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.
Files changed (62) hide show
  1. package/README.md +52 -0
  2. package/dist/analyzer.d.ts +6 -0
  3. package/dist/analyzer.d.ts.map +1 -0
  4. package/dist/analyzer.js +121 -0
  5. package/dist/analyzer.js.map +1 -0
  6. package/dist/checks/a11y-check.d.ts +6 -0
  7. package/dist/checks/a11y-check.d.ts.map +1 -0
  8. package/dist/checks/a11y-check.js +13 -0
  9. package/dist/checks/a11y-check.js.map +1 -0
  10. package/dist/checks/form-check.d.ts +6 -0
  11. package/dist/checks/form-check.d.ts.map +1 -0
  12. package/dist/checks/form-check.js +74 -0
  13. package/dist/checks/form-check.js.map +1 -0
  14. package/dist/checks/interactive-check.d.ts +6 -0
  15. package/dist/checks/interactive-check.d.ts.map +1 -0
  16. package/dist/checks/interactive-check.js +12 -0
  17. package/dist/checks/interactive-check.js.map +1 -0
  18. package/dist/checks/link-check.d.ts +6 -0
  19. package/dist/checks/link-check.d.ts.map +1 -0
  20. package/dist/checks/link-check.js +56 -0
  21. package/dist/checks/link-check.js.map +1 -0
  22. package/dist/checks/loader-check.d.ts +6 -0
  23. package/dist/checks/loader-check.d.ts.map +1 -0
  24. package/dist/checks/loader-check.js +41 -0
  25. package/dist/checks/loader-check.js.map +1 -0
  26. package/dist/checks/params-check.d.ts +6 -0
  27. package/dist/checks/params-check.d.ts.map +1 -0
  28. package/dist/checks/params-check.js +56 -0
  29. package/dist/checks/params-check.js.map +1 -0
  30. package/dist/cli.d.ts +3 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +151 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/index.d.ts +10 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +10 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/parsers/action-parser.d.ts +17 -0
  39. package/dist/parsers/action-parser.d.ts.map +1 -0
  40. package/dist/parsers/action-parser.js +53 -0
  41. package/dist/parsers/action-parser.js.map +1 -0
  42. package/dist/parsers/component-parser.d.ts +6 -0
  43. package/dist/parsers/component-parser.d.ts.map +1 -0
  44. package/dist/parsers/component-parser.js +354 -0
  45. package/dist/parsers/component-parser.js.map +1 -0
  46. package/dist/parsers/route-parser.d.ts +19 -0
  47. package/dist/parsers/route-parser.d.ts.map +1 -0
  48. package/dist/parsers/route-parser.js +275 -0
  49. package/dist/parsers/route-parser.js.map +1 -0
  50. package/dist/types.d.ts +123 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +2 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/ast-utils.d.ts +41 -0
  55. package/dist/utils/ast-utils.d.ts.map +1 -0
  56. package/dist/utils/ast-utils.js +114 -0
  57. package/dist/utils/ast-utils.js.map +1 -0
  58. package/dist/utils/suggestion.d.ts +10 -0
  59. package/dist/utils/suggestion.d.ts.map +1 -0
  60. package/dist/utils/suggestion.js +30 -0
  61. package/dist/utils/suggestion.js.map +1 -0
  62. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # react-router-analyzer
2
+
3
+ Static analysis tool for React Router 7 applications that catches runtime errors at build time.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install react-router-analyzer
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Check all files
15
+ npx react-router-analyzer
16
+
17
+ # Check specific file(s)
18
+ npx react-router-analyzer app/routes/employees.tsx
19
+
20
+ # Run specific checks only
21
+ npx react-router-analyzer --check links,forms
22
+
23
+ # Output as JSON
24
+ npx react-router-analyzer --format json
25
+
26
+ # Set root directory
27
+ npx react-router-analyzer --root ./my-app
28
+ ```
29
+
30
+ ## Checks
31
+
32
+ - **links**: Validates Link, redirect(), and navigate() targets exist as defined routes
33
+ - **forms**: Validates forms submit to routes with action exports
34
+ - **loader**: Validates useLoaderData() is only used in routes with loaders
35
+ - **params**: Validates useParams() accesses only params defined in the route
36
+ - **interactive**: Validates interactive elements have handlers (coming soon)
37
+ - **a11y**: Accessibility checks requiring cross-element analysis (coming soon)
38
+
39
+ ## Programmatic API
40
+
41
+ ```typescript
42
+ import { analyze } from "react-router-analyzer";
43
+
44
+ const result = analyze({
45
+ root: "./my-app",
46
+ files: [], // empty = all files
47
+ checks: [], // empty = all checks
48
+ format: "text",
49
+ });
50
+
51
+ console.log(result.issues);
52
+ ```
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerResult, CliOptions } from "./types.js";
2
+ /**
3
+ * Main analyzer - orchestrates parsing and checking
4
+ */
5
+ export declare function analyze(options: CliOptions): AnalyzerResult;
6
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EAId,UAAU,EACX,MAAM,YAAY,CAAC;AAUpB;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,cAAc,CAqF3D"}
@@ -0,0 +1,121 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { parseRoutes } from "./parsers/route-parser.js";
4
+ import { parseComponent } from "./parsers/component-parser.js";
5
+ import { checkLinks } from "./checks/link-check.js";
6
+ import { checkForms } from "./checks/form-check.js";
7
+ import { checkLoaders } from "./checks/loader-check.js";
8
+ import { checkParams } from "./checks/params-check.js";
9
+ import { checkInteractive } from "./checks/interactive-check.js";
10
+ import { checkA11y } from "./checks/a11y-check.js";
11
+ /**
12
+ * Main analyzer - orchestrates parsing and checking
13
+ */
14
+ export function analyze(options) {
15
+ const { root, files, checks } = options;
16
+ // Parse routes (always global)
17
+ let routes = [];
18
+ try {
19
+ routes = parseRoutes(root);
20
+ }
21
+ catch (error) {
22
+ // If no routes file, we can't do much
23
+ return {
24
+ issues: [
25
+ {
26
+ category: "links",
27
+ severity: "error",
28
+ message: error instanceof Error
29
+ ? error.message
30
+ : "Failed to parse routes file",
31
+ location: {
32
+ file: path.join(root, "app", "routes.ts"),
33
+ line: 1,
34
+ column: 1,
35
+ },
36
+ },
37
+ ],
38
+ routes: [],
39
+ components: [],
40
+ };
41
+ }
42
+ // Find component files to analyze
43
+ const componentFiles = findComponentFiles(root, files);
44
+ // Parse components
45
+ const components = [];
46
+ for (const file of componentFiles) {
47
+ try {
48
+ const analysis = parseComponent(file);
49
+ components.push(analysis);
50
+ }
51
+ catch (error) {
52
+ // Skip files that can't be parsed
53
+ console.error(`Warning: Could not parse ${file}:`, error);
54
+ }
55
+ }
56
+ // Run checks
57
+ const issues = [];
58
+ const enabledChecks = new Set(checks.length > 0 ? checks : ["links", "forms", "loader", "params", "interactive", "a11y"]);
59
+ if (enabledChecks.has("links")) {
60
+ issues.push(...checkLinks(components, routes));
61
+ }
62
+ if (enabledChecks.has("forms")) {
63
+ issues.push(...checkForms(components, routes, root));
64
+ }
65
+ if (enabledChecks.has("loader")) {
66
+ issues.push(...checkLoaders(components));
67
+ }
68
+ if (enabledChecks.has("params")) {
69
+ issues.push(...checkParams(components, routes, root));
70
+ }
71
+ if (enabledChecks.has("interactive")) {
72
+ issues.push(...checkInteractive(components));
73
+ }
74
+ if (enabledChecks.has("a11y")) {
75
+ issues.push(...checkA11y(components));
76
+ }
77
+ // If specific files were provided, filter issues to only those files
78
+ if (files.length > 0) {
79
+ const targetFiles = new Set(files.map((f) => path.resolve(f)));
80
+ const filteredIssues = issues.filter((issue) => targetFiles.has(path.resolve(issue.location.file)));
81
+ return { issues: filteredIssues, routes, components };
82
+ }
83
+ return { issues, routes, components };
84
+ }
85
+ /**
86
+ * Find all component files to analyze
87
+ */
88
+ function findComponentFiles(root, specificFiles) {
89
+ if (specificFiles.length > 0) {
90
+ // Analyze only specific files (paths are independent of root)
91
+ return specificFiles.map((f) => path.resolve(f));
92
+ }
93
+ // Find all TSX files in app/routes
94
+ const routesDir = path.join(root, "app", "routes");
95
+ if (!fs.existsSync(routesDir)) {
96
+ return [];
97
+ }
98
+ const files = [];
99
+ walkDir(routesDir, (filePath) => {
100
+ if (filePath.endsWith(".tsx")) {
101
+ files.push(filePath);
102
+ }
103
+ });
104
+ return files;
105
+ }
106
+ /**
107
+ * Recursively walk a directory
108
+ */
109
+ function walkDir(dir, callback) {
110
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
111
+ for (const entry of entries) {
112
+ const fullPath = path.join(dir, entry.name);
113
+ if (entry.isDirectory()) {
114
+ walkDir(fullPath, callback);
115
+ }
116
+ else if (entry.isFile()) {
117
+ callback(fullPath);
118
+ }
119
+ }
120
+ }
121
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis } from "../types.js";
2
+ /**
3
+ * Check accessibility issues
4
+ */
5
+ export declare function checkA11y(_components: ComponentAnalysis[]): AnalyzerIssue[];
6
+ //# sourceMappingURL=a11y-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y-check.d.ts","sourceRoot":"","sources":["../../src/checks/a11y-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAM3E"}
@@ -0,0 +1,13 @@
1
+ // Placeholder for accessibility checks
2
+ // These require cross-element analysis
3
+ /**
4
+ * Check accessibility issues
5
+ */
6
+ export function checkA11y(_components) {
7
+ // TODO: Implement accessibility checks
8
+ // - div with onClick but no keyboard handling
9
+ // - Form inputs without label association
10
+ // - Images without alt text
11
+ return [];
12
+ }
13
+ //# sourceMappingURL=a11y-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y-check.js","sourceRoot":"","sources":["../../src/checks/a11y-check.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAIvC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,WAAgC;IACxD,uCAAuC;IACvC,8CAA8C;IAC9C,0CAA0C;IAC1C,4BAA4B;IAC5B,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis, RouteDefinition } from "../types.js";
2
+ /**
3
+ * Check form-action wiring
4
+ */
5
+ export declare function checkForms(components: ComponentAnalysis[], routes: RouteDefinition[], rootDir: string): AnalyzerIssue[];
6
+ //# sourceMappingURL=form-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-check.d.ts","sourceRoot":"","sources":["../../src/checks/form-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAIrB;;GAEG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,iBAAiB,EAAE,EAC/B,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,MAAM,GACd,aAAa,EAAE,CAWjB"}
@@ -0,0 +1,74 @@
1
+ import * as path from "path";
2
+ import { matchRoute } from "../parsers/route-parser.js";
3
+ import { parseRouteExports } from "../parsers/action-parser.js";
4
+ /**
5
+ * Check form-action wiring
6
+ */
7
+ export function checkForms(components, routes, rootDir) {
8
+ const issues = [];
9
+ for (const component of components) {
10
+ for (const form of component.forms) {
11
+ const formIssues = validateForm(form, component, routes, rootDir);
12
+ issues.push(...formIssues);
13
+ }
14
+ }
15
+ return issues;
16
+ }
17
+ /**
18
+ * Validate a single form
19
+ */
20
+ function validateForm(form, component, routes, rootDir) {
21
+ const issues = [];
22
+ // If form has an explicit action, check that route has an action handler
23
+ if (form.action) {
24
+ const targetRoute = matchRoute(form.action, routes);
25
+ if (!targetRoute) {
26
+ issues.push({
27
+ category: "forms",
28
+ severity: "error",
29
+ message: `Form action targets non-existent route: ${form.action}`,
30
+ location: form.location,
31
+ code: `<Form action="${form.action}">`,
32
+ });
33
+ }
34
+ else {
35
+ // Check if the target route file has an action export
36
+ const routeFilePath = path.join(rootDir, "app", targetRoute.file);
37
+ try {
38
+ const exports = parseRouteExports(routeFilePath);
39
+ if (!exports.hasAction) {
40
+ issues.push({
41
+ category: "forms",
42
+ severity: "error",
43
+ message: `Form action targets route without action export`,
44
+ location: form.location,
45
+ code: `<Form action="${form.action}">`,
46
+ suggestion: `Add an action export to ${targetRoute.file}`,
47
+ });
48
+ }
49
+ }
50
+ catch {
51
+ // File doesn't exist or can't be parsed - route-parser should catch this
52
+ }
53
+ }
54
+ }
55
+ else {
56
+ // Form submits to current route - check if current file has action
57
+ if (!component.hasAction) {
58
+ issues.push({
59
+ category: "forms",
60
+ severity: "error",
61
+ message: "Form in route with no action export",
62
+ location: form.location,
63
+ code: "<Form>",
64
+ suggestion: "Add an action export to handle form submission",
65
+ });
66
+ }
67
+ }
68
+ // Check for inputs without name attribute
69
+ // Note: We track inputNames, but we should also warn about inputs WITHOUT names
70
+ // This would require more sophisticated tracking in the component parser
71
+ // For now, we'll skip this check
72
+ return issues;
73
+ }
74
+ //# sourceMappingURL=form-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-check.js","sourceRoot":"","sources":["../../src/checks/form-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAM7B,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,UAA+B,EAC/B,MAAyB,EACzB,OAAe;IAEf,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CACnB,IAAmC,EACnC,SAA4B,EAC5B,MAAyB,EACzB,OAAe;IAEf,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,yEAAyE;IACzE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEpD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,2CAA2C,IAAI,CAAC,MAAM,EAAE;gBACjE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,iBAAiB,IAAI,CAAC,MAAM,IAAI;aACvC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,sDAAsD;YACtD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;YAClE,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;gBACjD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;oBACvB,MAAM,CAAC,IAAI,CAAC;wBACV,QAAQ,EAAE,OAAO;wBACjB,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,iDAAiD;wBAC1D,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,IAAI,EAAE,iBAAiB,IAAI,CAAC,MAAM,IAAI;wBACtC,UAAU,EAAE,2BAA2B,WAAW,CAAC,IAAI,EAAE;qBAC1D,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,yEAAyE;YAC3E,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,mEAAmE;QACnE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,qCAAqC;gBAC9C,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,gDAAgD;aAC7D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,gFAAgF;IAChF,yEAAyE;IACzE,iCAAiC;IAEjC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis } from "../types.js";
2
+ /**
3
+ * Check interactive element completeness
4
+ */
5
+ export declare function checkInteractive(_components: ComponentAnalysis[]): AnalyzerIssue[];
6
+ //# sourceMappingURL=interactive-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-check.d.ts","sourceRoot":"","sources":["../../src/checks/interactive-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,iBAAiB,EAAE,GAC/B,aAAa,EAAE,CAKjB"}
@@ -0,0 +1,12 @@
1
+ // Placeholder for interactive element completeness checks
2
+ // This would check for buttons without handlers, etc.
3
+ /**
4
+ * Check interactive element completeness
5
+ */
6
+ export function checkInteractive(_components) {
7
+ // TODO: Implement interactive element checks
8
+ // - Buttons without onClick, type, or form context
9
+ // - onClick referencing undefined handlers
10
+ return [];
11
+ }
12
+ //# sourceMappingURL=interactive-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-check.js","sourceRoot":"","sources":["../../src/checks/interactive-check.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,sDAAsD;AAItD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,WAAgC;IAEhC,6CAA6C;IAC7C,mDAAmD;IACnD,2CAA2C;IAC3C,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis, RouteDefinition } from "../types.js";
2
+ /**
3
+ * Check all links in components against defined routes
4
+ */
5
+ export declare function checkLinks(components: ComponentAnalysis[], routes: RouteDefinition[]): AnalyzerIssue[];
6
+ //# sourceMappingURL=link-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-check.d.ts","sourceRoot":"","sources":["../../src/checks/link-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAQrB;;GAEG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,iBAAiB,EAAE,EAC/B,MAAM,EAAE,eAAe,EAAE,GACxB,aAAa,EAAE,CAcjB"}
@@ -0,0 +1,56 @@
1
+ import { matchRoute, matchDynamicPattern, getAllRoutePaths, } from "../parsers/route-parser.js";
2
+ import { findBestMatch, formatSuggestion } from "../utils/suggestion.js";
3
+ /**
4
+ * Check all links in components against defined routes
5
+ */
6
+ export function checkLinks(components, routes) {
7
+ const issues = [];
8
+ const allPaths = getAllRoutePaths(routes);
9
+ for (const component of components) {
10
+ for (const link of component.links) {
11
+ const issue = validateLink(link, routes, allPaths);
12
+ if (issue) {
13
+ issues.push(issue);
14
+ }
15
+ }
16
+ }
17
+ return issues;
18
+ }
19
+ /**
20
+ * Validate a single link
21
+ */
22
+ function validateLink(link, routes, allPaths) {
23
+ if (link.isDynamic) {
24
+ // For dynamic links, check the pattern
25
+ const pattern = link.pattern || link.href;
26
+ const match = matchDynamicPattern(pattern, routes);
27
+ if (!match) {
28
+ const suggestion = findBestMatch(pattern, allPaths);
29
+ return {
30
+ category: "links",
31
+ severity: "error",
32
+ message: "No matching route for dynamic link pattern",
33
+ location: link.location,
34
+ code: `${link.type === "link" ? "href" : link.type}="${link.href}"`,
35
+ suggestion: formatSuggestion(suggestion),
36
+ };
37
+ }
38
+ }
39
+ else {
40
+ // For static links, do exact matching
41
+ const match = matchRoute(link.href, routes);
42
+ if (!match) {
43
+ const suggestion = findBestMatch(link.href, allPaths);
44
+ return {
45
+ category: "links",
46
+ severity: "error",
47
+ message: "No matching route",
48
+ location: link.location,
49
+ code: `${link.type === "link" ? "href" : link.type}="${link.href}"`,
50
+ suggestion: formatSuggestion(suggestion),
51
+ };
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ //# sourceMappingURL=link-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-check.js","sourceRoot":"","sources":["../../src/checks/link-check.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEzE;;GAEG;AACH,MAAM,UAAU,UAAU,CACxB,UAA+B,EAC/B,MAAyB;IAEzB,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE1C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YACnD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CACnB,IAAmC,EACnC,MAAyB,EACzB,QAAkB;IAElB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,uCAAuC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC;QAC1C,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACpD,OAAO;gBACL,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,4CAA4C;gBACrD,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG;gBACnE,UAAU,EAAE,gBAAgB,CAAC,UAAU,CAAC;aACzC,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,sCAAsC;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAE5C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACtD,OAAO;gBACL,QAAQ,EAAE,OAAO;gBACjB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,mBAAmB;gBAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG;gBACnE,UAAU,EAAE,gBAAgB,CAAC,UAAU,CAAC;aACzC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis } from "../types.js";
2
+ /**
3
+ * Check loader-component binding
4
+ */
5
+ export declare function checkLoaders(components: ComponentAnalysis[]): AnalyzerIssue[];
6
+ //# sourceMappingURL=loader-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-check.d.ts","sourceRoot":"","sources":["../../src/checks/loader-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE;;GAEG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,iBAAiB,EAAE,GAC9B,aAAa,EAAE,CASjB"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Check loader-component binding
3
+ */
4
+ export function checkLoaders(components) {
5
+ const issues = [];
6
+ for (const component of components) {
7
+ const componentIssues = validateLoaderUsage(component);
8
+ issues.push(...componentIssues);
9
+ }
10
+ return issues;
11
+ }
12
+ /**
13
+ * Validate loader usage in a component
14
+ */
15
+ function validateLoaderUsage(component) {
16
+ const issues = [];
17
+ for (const hook of component.dataHooks) {
18
+ if (hook.hook === "useLoaderData" && !component.hasLoader) {
19
+ issues.push({
20
+ category: "loader",
21
+ severity: "error",
22
+ message: "useLoaderData() called but route has no loader",
23
+ location: hook.location,
24
+ code: "useLoaderData()",
25
+ suggestion: "Add a loader function or remove the hook",
26
+ });
27
+ }
28
+ if (hook.hook === "useActionData" && !component.hasAction) {
29
+ issues.push({
30
+ category: "loader",
31
+ severity: "warning",
32
+ message: "useActionData() called but route has no action",
33
+ location: hook.location,
34
+ code: "useActionData()",
35
+ suggestion: "Add an action function or remove the hook",
36
+ });
37
+ }
38
+ }
39
+ return issues;
40
+ }
41
+ //# sourceMappingURL=loader-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-check.js","sourceRoot":"","sources":["../../src/checks/loader-check.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,UAA+B;IAE/B,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,eAAe,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,SAA4B;IACvD,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,QAAQ;gBAClB,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,gDAAgD;gBACzD,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,iBAAiB;gBACvB,UAAU,EAAE,0CAA0C;aACvD,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,QAAQ;gBAClB,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,gDAAgD;gBACzD,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,IAAI,EAAE,iBAAiB;gBACvB,UAAU,EAAE,2CAA2C;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { AnalyzerIssue, ComponentAnalysis, RouteDefinition } from "../types.js";
2
+ /**
3
+ * Check route parameter consistency
4
+ */
5
+ export declare function checkParams(components: ComponentAnalysis[], routes: RouteDefinition[], rootDir: string): AnalyzerIssue[];
6
+ //# sourceMappingURL=params-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"params-check.d.ts","sourceRoot":"","sources":["../../src/checks/params-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,iBAAiB,EAAE,EAC/B,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,MAAM,GACd,aAAa,EAAE,CA4BjB"}
@@ -0,0 +1,56 @@
1
+ import * as path from "path";
2
+ /**
3
+ * Check route parameter consistency
4
+ */
5
+ export function checkParams(components, routes, rootDir) {
6
+ const issues = [];
7
+ // Build a map of file -> route definition
8
+ const fileToRoute = new Map();
9
+ function mapRoutes(routeList) {
10
+ for (const route of routeList) {
11
+ const fullPath = path.join(rootDir, "app", route.file);
12
+ fileToRoute.set(fullPath, route);
13
+ if (route.children) {
14
+ mapRoutes(route.children);
15
+ }
16
+ }
17
+ }
18
+ mapRoutes(routes);
19
+ for (const component of components) {
20
+ const route = fileToRoute.get(component.file);
21
+ if (!route) {
22
+ // Not a route file
23
+ continue;
24
+ }
25
+ const componentIssues = validateParamUsage(component, route);
26
+ issues.push(...componentIssues);
27
+ }
28
+ return issues;
29
+ }
30
+ /**
31
+ * Validate param usage in a component against its route definition
32
+ */
33
+ function validateParamUsage(component, route) {
34
+ const issues = [];
35
+ const routeParams = new Set(route.params);
36
+ for (const hook of component.dataHooks) {
37
+ if (hook.hook === "useParams" && hook.accessedParams) {
38
+ for (const param of hook.accessedParams) {
39
+ if (!routeParams.has(param)) {
40
+ issues.push({
41
+ category: "params",
42
+ severity: "error",
43
+ message: `useParams() accesses "${param}" but route has no :${param} parameter`,
44
+ location: hook.location,
45
+ code: `useParams().${param}`,
46
+ suggestion: route.params.length > 0
47
+ ? `Available params: ${route.params.map((p) => ":" + p).join(", ")}`
48
+ : `Route ${route.path} has no parameters`,
49
+ });
50
+ }
51
+ }
52
+ }
53
+ }
54
+ return issues;
55
+ }
56
+ //# sourceMappingURL=params-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"params-check.js","sourceRoot":"","sources":["../../src/checks/params-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAO7B;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,UAA+B,EAC/B,MAAyB,EACzB,OAAe;IAEf,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,0CAA0C;IAC1C,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;IACvD,SAAS,SAAS,CAAC,SAA4B;QAC7C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvD,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACjC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IACD,SAAS,CAAC,MAAM,CAAC,CAAC;IAElB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,mBAAmB;YACnB,SAAS;QACX,CAAC;QAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CACzB,SAA4B,EAC5B,KAAsB;IAEtB,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACrD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5B,MAAM,CAAC,IAAI,CAAC;wBACV,QAAQ,EAAE,QAAQ;wBAClB,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,yBAAyB,KAAK,uBAAuB,KAAK,YAAY;wBAC/E,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,IAAI,EAAE,eAAe,KAAK,EAAE;wBAC5B,UAAU,EACR,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;4BACrB,CAAC,CAAC,qBAAqB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;4BACpE,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,oBAAoB;qBAC9C,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}