next-route-graph 1.1.0 → 1.2.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/CHANGELOG.md +95 -0
- package/CONTRIBUTING.md +74 -0
- package/README.md +113 -189
- package/SECURITY.md +19 -0
- package/dist/cli.js +107 -80
- package/dist/core/analyzer.d.ts +5 -1
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +21 -14
- package/dist/core/inspect.d.ts +6 -0
- package/dist/core/inspect.d.ts.map +1 -0
- package/dist/core/inspect.js +21 -0
- package/dist/core/linter.d.ts.map +1 -1
- package/dist/core/linter.js +43 -23
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +31 -16
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +8 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/preview.d.ts +4 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +25 -0
- package/dist/render/dot.d.ts.map +1 -1
- package/dist/render/dot.js +25 -47
- package/dist/render/graph.d.ts +13 -0
- package/dist/render/graph.d.ts.map +1 -0
- package/dist/render/graph.js +53 -0
- package/dist/render/html.d.ts +8 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +718 -0
- package/dist/render/index.d.ts +4 -2
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +10 -3
- package/dist/render/mermaid.d.ts.map +1 -1
- package/dist/render/mermaid.js +19 -43
- package/dist/render/svg.d.ts +8 -0
- package/dist/render/svg.d.ts.map +1 -0
- package/dist/render/svg.js +76 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/index.d.ts.map +1 -1
- package/docs/ARCHITECTURE.md +71 -0
- package/docs/NEW_FEATURES.md +16 -0
- package/docs/adr/0001-offline-reports-and-shared-route-graph.md +29 -0
- package/docs/route-report.png +0 -0
- package/package.json +12 -4
package/dist/cli.js
CHANGED
|
@@ -1,113 +1,140 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { stripVTControlCharacters } from "node:util";
|
|
5
|
+
import { Command, Option } from "commander";
|
|
3
6
|
import pc from "picocolors";
|
|
4
|
-
import {
|
|
5
|
-
import { detectAppRouter } from "./core/detector.js";
|
|
6
|
-
import { scanAppDir } from "./core/scanner.js";
|
|
7
|
+
import { filterRoutes, inspectProject } from "./core/inspect.js";
|
|
7
8
|
import { NextRouteGraphError, RouteLintError } from "./errors/index.js";
|
|
9
|
+
import { startPreview } from "./preview.js";
|
|
8
10
|
import { getRenderer } from "./render/index.js";
|
|
9
|
-
/**
|
|
10
|
-
* Determines the target output format based on CLI flags.
|
|
11
|
-
*/
|
|
12
11
|
function resolveFormat(options) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (options.format)
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
const aliases = [
|
|
13
|
+
"json",
|
|
14
|
+
"flat",
|
|
15
|
+
"mermaid",
|
|
16
|
+
"dot",
|
|
17
|
+
"markdown",
|
|
18
|
+
"html",
|
|
19
|
+
"svg",
|
|
20
|
+
];
|
|
21
|
+
const selected = aliases.filter((format) => options[format]);
|
|
22
|
+
if (selected.length + Number(Boolean(options.format)) > 1) {
|
|
23
|
+
throw new Error("Choose one output format: --format <type> or one format flag.");
|
|
24
|
+
}
|
|
25
|
+
const format = selected[0] ??
|
|
26
|
+
options.format ??
|
|
27
|
+
(options.serve !== undefined ? "html" : "tree");
|
|
28
|
+
if (options.html && options.output)
|
|
29
|
+
throw new Error("Use --html [file] or --output <file>, not both.");
|
|
30
|
+
if (options.serve !== undefined &&
|
|
31
|
+
(format !== "html" || options.output || options.html)) {
|
|
32
|
+
throw new Error("Use --serve on its own or with --format html; file output is separate.");
|
|
33
|
+
}
|
|
34
|
+
return format;
|
|
26
35
|
}
|
|
27
36
|
async function runAnalysis(projectPath, options) {
|
|
28
37
|
try {
|
|
29
|
-
const { appDir, displayRoot } = detectAppRouter(projectPath);
|
|
30
|
-
const scannedFiles = await scanAppDir(appDir);
|
|
31
|
-
let analysisResult = await analyzeRoutes(scannedFiles, projectPath, displayRoot);
|
|
32
|
-
if (options.search) {
|
|
33
|
-
const search = options.search;
|
|
34
|
-
analysisResult.routes = analysisResult.routes.filter((route) => route.path.includes(search));
|
|
35
|
-
analysisResult.summary = {
|
|
36
|
-
...analysisResult.summary,
|
|
37
|
-
routes: analysisResult.routes.length,
|
|
38
|
-
dynamic: analysisResult.routes.filter((route) => route.segmentType !== "static").length,
|
|
39
|
-
client: analysisResult.routes.filter((route) => route.rendering === "client").length,
|
|
40
|
-
server: analysisResult.routes.filter((route) => route.rendering === "server").length,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
38
|
const format = resolveFormat(options);
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
const portText = options.serve === true ? "3000" : String(options.serve);
|
|
40
|
+
if (options.serve !== undefined &&
|
|
41
|
+
(!/^\d+$/.test(portText) || Number(portText) > 65535)) {
|
|
42
|
+
throw new Error("Preview port must be an integer between 0 and 65535 (0 chooses a free port).");
|
|
48
43
|
}
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
44
|
+
const fullResult = await inspectProject(projectPath);
|
|
45
|
+
const result = options.search
|
|
46
|
+
? filterRoutes(fullResult, options.search)
|
|
47
|
+
: fullResult;
|
|
48
|
+
let output = getRenderer(format).render(result);
|
|
49
|
+
const lint = fullResult.lint;
|
|
50
|
+
const failed = lint &&
|
|
51
|
+
((options.check && lint.hasErrors) ||
|
|
52
|
+
(options.strict && (lint.hasErrors || lint.warningCount > 0)));
|
|
53
|
+
if (options.serve !== undefined) {
|
|
54
|
+
// A failed CI check must terminate instead of leaving a preview process alive.
|
|
55
|
+
if (failed)
|
|
56
|
+
throw new RouteLintError(lint.errorCount, lint.warningCount);
|
|
57
|
+
const server = await startPreview(output, Number(portText));
|
|
58
|
+
const address = server.address();
|
|
59
|
+
if (address && typeof address !== "string") {
|
|
60
|
+
console.error(pc.green(`✓ Route Graph server running at http://127.0.0.1:${address.port}`));
|
|
61
|
+
console.error("Static snapshot · Press Ctrl+C to stop");
|
|
66
62
|
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const target = options.html
|
|
66
|
+
? typeof options.html === "string"
|
|
67
|
+
? options.html
|
|
68
|
+
: "route-graph.html"
|
|
69
|
+
: options.output;
|
|
70
|
+
if (target && target !== "-") {
|
|
71
|
+
const absolute = path.resolve(target);
|
|
72
|
+
await fs.mkdir(path.dirname(absolute), { recursive: true });
|
|
73
|
+
if (format === "tree")
|
|
74
|
+
output = stripVTControlCharacters(output);
|
|
75
|
+
await fs.writeFile(absolute, output + "\n", "utf-8");
|
|
76
|
+
console.error(pc.green(`✓ ${format === "html" ? "HTML report" : format.toUpperCase() + " export"} written to ${target}`));
|
|
67
77
|
}
|
|
78
|
+
else if (output) {
|
|
79
|
+
process.stdout.write(output + "\n");
|
|
80
|
+
}
|
|
81
|
+
// Write the report before applying CI exit policy so failing checks leave artifacts.
|
|
82
|
+
if (failed)
|
|
83
|
+
throw new RouteLintError(lint.errorCount, lint.warningCount);
|
|
68
84
|
}
|
|
69
85
|
catch (error) {
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
+
if (options.json || options.format === "json") {
|
|
88
|
+
console.error(JSON.stringify({
|
|
89
|
+
error: message,
|
|
90
|
+
code: error instanceof NextRouteGraphError ? error.code : "ERR_CLI",
|
|
91
|
+
}));
|
|
72
92
|
}
|
|
73
93
|
else {
|
|
74
|
-
console.error(pc.red(`✗ ${
|
|
75
|
-
if (error instanceof NextRouteGraphError && error.hint)
|
|
94
|
+
console.error(pc.red(`✗ ${message}`));
|
|
95
|
+
if (error instanceof NextRouteGraphError && error.hint)
|
|
76
96
|
console.error(pc.dim(` Hint: ${error.hint}`));
|
|
77
|
-
}
|
|
78
97
|
}
|
|
79
|
-
process.
|
|
98
|
+
process.exitCode = 1;
|
|
80
99
|
}
|
|
81
100
|
}
|
|
82
101
|
const program = new Command();
|
|
102
|
+
const { version } = JSON.parse(await fs.readFile(new URL("../package.json", import.meta.url), "utf-8"));
|
|
83
103
|
program
|
|
84
104
|
.name("next-route-graph")
|
|
85
105
|
.description("Inspect, lint, and visualize Next.js App Router project routes")
|
|
86
|
-
.version(
|
|
106
|
+
.version(version)
|
|
87
107
|
.argument("[projectPath]", "Path to the Next.js project root", ".")
|
|
88
|
-
.option("--flat", "Output
|
|
108
|
+
.option("--flat", "Output flat route paths")
|
|
89
109
|
.option("--json", "Output machine-readable JSON")
|
|
90
|
-
.option("--mermaid", "Output Mermaid
|
|
91
|
-
.option("--dot", "Output Graphviz DOT
|
|
92
|
-
.option("--markdown", "Output
|
|
93
|
-
.option("--
|
|
94
|
-
.option("--
|
|
95
|
-
.option("--
|
|
96
|
-
.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
.option("--mermaid", "Output Mermaid diagram source")
|
|
111
|
+
.option("--dot", "Output Graphviz DOT source")
|
|
112
|
+
.option("--markdown", "Output a Markdown table")
|
|
113
|
+
.option("--svg", "Output a rendered SVG route diagram")
|
|
114
|
+
.option("--html [file]", "Write an offline interactive HTML report (default: route-graph.html)")
|
|
115
|
+
.option("--serve [port]", "Preview an HTML snapshot on 127.0.0.1 (default: 3000)")
|
|
116
|
+
.addOption(new Option("--format <type>", "Output format (default: tree)").choices([
|
|
117
|
+
"tree",
|
|
118
|
+
"flat",
|
|
119
|
+
"json",
|
|
120
|
+
"mermaid",
|
|
121
|
+
"dot",
|
|
122
|
+
"markdown",
|
|
123
|
+
"html",
|
|
124
|
+
"svg",
|
|
125
|
+
]))
|
|
126
|
+
.option("-o, --output <file>", "Write any format to a file; '-' writes to stdout")
|
|
127
|
+
.option("--search <query>", "Filter path, source file, or HTTP method (case-insensitive)")
|
|
128
|
+
.option("--check", "Fail on route validation errors")
|
|
129
|
+
.option("--strict", "Fail on errors or warnings")
|
|
130
|
+
.action(runAnalysis);
|
|
100
131
|
program
|
|
101
132
|
.command("check")
|
|
102
|
-
.description("
|
|
133
|
+
.description("Check route collisions, root layouts, and slot fallbacks")
|
|
103
134
|
.argument("[projectPath]", "Path to the Next.js project root", ".")
|
|
104
135
|
.option("--strict", "Fail on warnings in addition to errors")
|
|
105
136
|
.option("--json", "Output check report as JSON")
|
|
106
137
|
.action(async (projectPath, options) => {
|
|
107
|
-
await runAnalysis(projectPath, {
|
|
108
|
-
check: true,
|
|
109
|
-
strict: options.strict ?? false,
|
|
110
|
-
json: options.json,
|
|
111
|
-
});
|
|
138
|
+
await runAnalysis(projectPath, { ...options, check: true });
|
|
112
139
|
});
|
|
113
|
-
program.
|
|
140
|
+
await program.parseAsync(process.argv);
|
package/dist/core/analyzer.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { AnalysisResult, DiscoveredFile } from "../types/index.js";
|
|
1
|
+
import { AnalysisResult, DiscoveredFile, RouteEntry, SummaryStats } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Aggregates summary statistics for the analyzed routes and convention files.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getRoutesSummary(routes: RouteEntry[], layouts: number, loading: number, errors: number): SummaryStats;
|
|
2
6
|
/**
|
|
3
7
|
* Analyzes discovered files in a Next.js App Router to construct route entries,
|
|
4
8
|
* evaluate rendering types, HTTP methods, layouts, and linter rules.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/core/analyzer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/core/analyzer.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,cAAc,EACd,cAAc,EACd,UAAU,EAEV,YAAY,EACb,MAAM,mBAAmB,CAAC;AAyK3B;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,YAAY,CA4Bd;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,cAAc,EAAE,EACvB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAqDzB"}
|
package/dist/core/analyzer.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { RouteFileReadError } from "../errors/index.js";
|
|
3
4
|
import { lintRoutes } from "./linter.js";
|
|
4
|
-
import { detectHttpMethods,
|
|
5
|
+
import { detectHttpMethods, getPrologueDirectives, detectRouteConfig, detectServerActions, extractRouteMetadata, getSegmentType, parseRoutePath, parseSpecialFileType, } from "./parser.js";
|
|
5
6
|
/**
|
|
6
7
|
* Groups discovered files by their directory relative to the App Router root.
|
|
7
8
|
*/
|
|
@@ -38,8 +39,12 @@ async function processDirectoryFiles(dirFiles) {
|
|
|
38
39
|
try {
|
|
39
40
|
content = await fs.readFile(file.fullPath, "utf-8");
|
|
40
41
|
}
|
|
41
|
-
catch {
|
|
42
|
-
|
|
42
|
+
catch (cause) {
|
|
43
|
+
throw new RouteFileReadError(file.relativePath, cause);
|
|
44
|
+
}
|
|
45
|
+
const rendering = getPrologueDirectives(content).has("use client")
|
|
46
|
+
? "client"
|
|
47
|
+
: "server";
|
|
43
48
|
const methods = specialType === "route" ? detectHttpMethods(content) : undefined;
|
|
44
49
|
const hasServerActions = detectServerActions(content);
|
|
45
50
|
const config = detectRouteConfig(content);
|
|
@@ -73,7 +78,7 @@ async function processDirectoryFiles(dirFiles) {
|
|
|
73
78
|
/**
|
|
74
79
|
* Finds all layout files in parent directories that wrap a specific directory.
|
|
75
80
|
*/
|
|
76
|
-
function findLayoutChain(targetDir,
|
|
81
|
+
function findLayoutChain(targetDir, layoutsByDirectory) {
|
|
77
82
|
const layoutChain = [];
|
|
78
83
|
const normalizedTarget = targetDir === "." ? "" : targetDir;
|
|
79
84
|
const segments = normalizedTarget ? normalizedTarget.split("/") : [];
|
|
@@ -81,13 +86,9 @@ function findLayoutChain(targetDir, allFiles) {
|
|
|
81
86
|
for (let i = 0; i <= segments.length; i++) {
|
|
82
87
|
const currentPath = segments.slice(0, i).join("/");
|
|
83
88
|
const checkDir = currentPath === "" ? "." : currentPath;
|
|
84
|
-
const layout =
|
|
85
|
-
const dir = path.dirname(f.relativePath).replace(/\\/g, "/");
|
|
86
|
-
const isDir = dir === checkDir || (checkDir === "." && dir === "");
|
|
87
|
-
return isDir && parseSpecialFileType(f.fileName) === "layout";
|
|
88
|
-
});
|
|
89
|
+
const layout = layoutsByDirectory.get(checkDir);
|
|
89
90
|
if (layout) {
|
|
90
|
-
layoutChain.push(layout
|
|
91
|
+
layoutChain.push(layout);
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
return layoutChain;
|
|
@@ -96,7 +97,7 @@ function findLayoutChain(targetDir, allFiles) {
|
|
|
96
97
|
* Creates a RouteEntry from the convention files in a directory.
|
|
97
98
|
* Uses cached metadata from the in-memory RouteFile to eliminate duplicate disk reads.
|
|
98
99
|
*/
|
|
99
|
-
function createRouteEntry(routeFiles,
|
|
100
|
+
function createRouteEntry(routeFiles, layoutsByDirectory) {
|
|
100
101
|
const pageFile = routeFiles.find((file) => file.type === "page");
|
|
101
102
|
const routeHandlerFile = routeFiles.find((file) => file.type === "route");
|
|
102
103
|
const primaryFile = pageFile ?? routeHandlerFile;
|
|
@@ -106,7 +107,7 @@ function createRouteEntry(routeFiles, allFiles) {
|
|
|
106
107
|
const computedPath = parseRoutePath(primaryFile.relativePath);
|
|
107
108
|
const metadata = extractRouteMetadata(primaryFile.relativePath);
|
|
108
109
|
const dir = path.dirname(primaryFile.relativePath).replace(/\\/g, "/");
|
|
109
|
-
const layoutChain = findLayoutChain(dir,
|
|
110
|
+
const layoutChain = findLayoutChain(dir, layoutsByDirectory);
|
|
110
111
|
return {
|
|
111
112
|
path: computedPath,
|
|
112
113
|
type: pageFile ? "page" : "route",
|
|
@@ -126,7 +127,7 @@ function createRouteEntry(routeFiles, allFiles) {
|
|
|
126
127
|
/**
|
|
127
128
|
* Aggregates summary statistics for the analyzed routes and convention files.
|
|
128
129
|
*/
|
|
129
|
-
function getRoutesSummary(routes, layouts, loading, errors) {
|
|
130
|
+
export function getRoutesSummary(routes, layouts, loading, errors) {
|
|
130
131
|
let dynamic = 0;
|
|
131
132
|
let client = 0;
|
|
132
133
|
let apiRoutes = 0;
|
|
@@ -165,6 +166,12 @@ function getRoutesSummary(routes, layouts, loading, errors) {
|
|
|
165
166
|
export async function analyzeRoutes(files, projectPath, displayRoot) {
|
|
166
167
|
const startTime = Date.now();
|
|
167
168
|
const dirMap = groupFilesByDirectory(files);
|
|
169
|
+
const layoutsByDirectory = new Map();
|
|
170
|
+
for (const [dir, dirFiles] of dirMap) {
|
|
171
|
+
const layout = dirFiles.find((file) => parseSpecialFileType(file.fileName) === "layout");
|
|
172
|
+
if (layout)
|
|
173
|
+
layoutsByDirectory.set(dir, layout.relativePath);
|
|
174
|
+
}
|
|
168
175
|
const discoveredRoutes = [];
|
|
169
176
|
let totalLayouts = 0;
|
|
170
177
|
let totalLoading = 0;
|
|
@@ -174,7 +181,7 @@ export async function analyzeRoutes(files, projectPath, displayRoot) {
|
|
|
174
181
|
totalLayouts += result.layouts;
|
|
175
182
|
totalLoading += result.loading;
|
|
176
183
|
totalErrors += result.errors;
|
|
177
|
-
const route = createRouteEntry(result.routeFiles,
|
|
184
|
+
const route = createRouteEntry(result.routeFiles, layoutsByDirectory);
|
|
178
185
|
if (route) {
|
|
179
186
|
discoveredRoutes.push(route);
|
|
180
187
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AnalysisResult } from "../types/index.js";
|
|
2
|
+
/** Scan a project without starting Next.js or executing project code. */
|
|
3
|
+
export declare function inspectProject(projectPath?: string): Promise<AnalysisResult>;
|
|
4
|
+
/** Filter endpoint counts; convention-file totals and diagnostics remain project-wide. */
|
|
5
|
+
export declare function filterRoutes(result: AnalysisResult, query: string): AnalysisResult;
|
|
6
|
+
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/core/inspect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,yEAAyE;AACzE,wBAAsB,cAAc,CAClC,WAAW,SAAM,GAChB,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,MAAM,GACZ,cAAc,CAiBhB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { analyzeRoutes, getRoutesSummary } from "./analyzer.js";
|
|
2
|
+
import { detectAppRouter } from "./detector.js";
|
|
3
|
+
import { scanAppDir } from "./scanner.js";
|
|
4
|
+
/** Scan a project without starting Next.js or executing project code. */
|
|
5
|
+
export async function inspectProject(projectPath = ".") {
|
|
6
|
+
const start = performance.now();
|
|
7
|
+
const { appDir, displayRoot } = detectAppRouter(projectPath);
|
|
8
|
+
const files = await scanAppDir(appDir);
|
|
9
|
+
const result = await analyzeRoutes(files, projectPath, displayRoot);
|
|
10
|
+
return { ...result, executionTimeMs: Math.round(performance.now() - start) };
|
|
11
|
+
}
|
|
12
|
+
/** Filter endpoint counts; convention-file totals and diagnostics remain project-wide. */
|
|
13
|
+
export function filterRoutes(result, query) {
|
|
14
|
+
const search = query.toLowerCase();
|
|
15
|
+
const routes = result.routes.filter((route) => [route.path, route.file, ...(route.methods ?? [])].some((value) => value.toLowerCase().includes(search)));
|
|
16
|
+
return {
|
|
17
|
+
...result,
|
|
18
|
+
routes,
|
|
19
|
+
summary: getRoutesSummary(routes, result.summary.layouts, result.summary.loading, result.summary.errors),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EAEd,UAAU,EACV,UAAU,EACX,MAAM,mBAAmB,CAAC;AAkB3B;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAAE,EACpB,KAAK,EAAE,cAAc,EAAE,GACtB,UAAU,
|
|
1
|
+
{"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../../src/core/linter.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EAEd,UAAU,EACV,UAAU,EACX,MAAM,mBAAmB,CAAC;AAkB3B;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAAE,EACpB,KAAK,EAAE,cAAc,EAAE,GACtB,UAAU,CA8LZ"}
|
package/dist/core/linter.js
CHANGED
|
@@ -13,7 +13,7 @@ function createPatternKey(routePath) {
|
|
|
13
13
|
return ":catchAll";
|
|
14
14
|
if (seg.startsWith("[") && seg.endsWith("]"))
|
|
15
15
|
return ":dynamic";
|
|
16
|
-
return seg
|
|
16
|
+
return seg;
|
|
17
17
|
})
|
|
18
18
|
.join("/");
|
|
19
19
|
}
|
|
@@ -47,7 +47,7 @@ export function lintRoutes(routes, files) {
|
|
|
47
47
|
});
|
|
48
48
|
if (!hasTopLevelRootLayout && routes.length > 0) {
|
|
49
49
|
// Check if every route has at least one layout in its layoutChain
|
|
50
|
-
const routesWithoutLayout = routes.filter((r) => !r.layoutChain || r.layoutChain.length === 0);
|
|
50
|
+
const routesWithoutLayout = routes.filter((r) => r.type === "page" && (!r.layoutChain || r.layoutChain.length === 0));
|
|
51
51
|
if (routesWithoutLayout.length > 0) {
|
|
52
52
|
issues.push({
|
|
53
53
|
rule: "require-root-layout",
|
|
@@ -77,13 +77,28 @@ export function lintRoutes(routes, files) {
|
|
|
77
77
|
// -------------------------------------------------------------
|
|
78
78
|
// Rule 3: Exact URL Collision across Route Groups (no-duplicate-paths)
|
|
79
79
|
// -------------------------------------------------------------
|
|
80
|
+
// Slots render alongside children, and intercepted pages intentionally share URLs.
|
|
81
|
+
// Collisions only apply within the same parallel-slot branch.
|
|
82
|
+
const branchKey = (route) => {
|
|
83
|
+
const parts = route.file.replace(/\\/g, "/").split("/");
|
|
84
|
+
let slot = -1;
|
|
85
|
+
parts.forEach((part, index) => {
|
|
86
|
+
if (part.startsWith("@"))
|
|
87
|
+
slot = index;
|
|
88
|
+
});
|
|
89
|
+
return slot < 0 ? "" : parts.slice(0, slot + 1).join("/");
|
|
90
|
+
};
|
|
91
|
+
const publicRoutes = routes.filter((route) => !route.intercepting);
|
|
80
92
|
const pathToFileMap = new Map();
|
|
81
|
-
for (const route of
|
|
82
|
-
const
|
|
83
|
-
existing.
|
|
84
|
-
|
|
93
|
+
for (const route of publicRoutes) {
|
|
94
|
+
const key = JSON.stringify([branchKey(route), route.path]);
|
|
95
|
+
const existing = pathToFileMap.get(key) || [];
|
|
96
|
+
existing.push(route);
|
|
97
|
+
pathToFileMap.set(key, existing);
|
|
85
98
|
}
|
|
86
|
-
for (const
|
|
99
|
+
for (const entries of pathToFileMap.values()) {
|
|
100
|
+
const routePath = entries[0].path;
|
|
101
|
+
const fileList = entries.map((route) => route.file);
|
|
87
102
|
if (fileList.length > 1) {
|
|
88
103
|
issues.push({
|
|
89
104
|
rule: "no-duplicate-paths",
|
|
@@ -98,23 +113,28 @@ export function lintRoutes(routes, files) {
|
|
|
98
113
|
// Rule 4: Dynamic Segment Collisions (no-route-collisions)
|
|
99
114
|
// -------------------------------------------------------------
|
|
100
115
|
const patternMap = new Map();
|
|
101
|
-
for (const route of
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
for (const route of publicRoutes) {
|
|
117
|
+
const segments = route.path.split("/").filter(Boolean);
|
|
118
|
+
for (let depth = 1; depth <= segments.length; depth++) {
|
|
119
|
+
if (!segments[depth - 1].startsWith("["))
|
|
120
|
+
continue;
|
|
121
|
+
const prefix = "/" + segments.slice(0, depth).join("/");
|
|
122
|
+
const key = JSON.stringify([branchKey(route), createPatternKey(prefix)]);
|
|
123
|
+
const existing = patternMap.get(key) ?? new Set();
|
|
124
|
+
existing.add(prefix);
|
|
125
|
+
patternMap.set(key, existing);
|
|
126
|
+
}
|
|
106
127
|
}
|
|
107
|
-
for (const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
128
|
+
for (const patternPaths of patternMap.values()) {
|
|
129
|
+
const uniquePaths = [...patternPaths];
|
|
130
|
+
const pattern = createPatternKey(uniquePaths[0]);
|
|
131
|
+
if (uniquePaths.length > 1) {
|
|
132
|
+
issues.push({
|
|
133
|
+
rule: "no-route-collisions",
|
|
134
|
+
severity: "error",
|
|
135
|
+
message: `Dynamic route collision detected matching pattern "/${pattern}": ${uniquePaths.join(", ")}`,
|
|
136
|
+
hint: "Next.js cannot disambiguate multiple dynamic segments at the same level. Unify the dynamic parameter names.",
|
|
137
|
+
});
|
|
118
138
|
}
|
|
119
139
|
}
|
|
120
140
|
// -------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,GAAG,CAAC,eAAe,CAU7C,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAQpC,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAQ7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,GAAG,CAAC,eAAe,CAU7C,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAQpC,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAQ7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAsElE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAuB/D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAW5D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,OAAO,GAAG,cAAc,CAAC;CACrE,CA2BA;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAmBA;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CA+C3D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,GAChB,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,oBAAoB,CAc3D"}
|
package/dist/core/parser.js
CHANGED
|
@@ -85,7 +85,9 @@ export function getPrologueDirectives(content) {
|
|
|
85
85
|
if (char === '"' || char === "'") {
|
|
86
86
|
const quote = char;
|
|
87
87
|
let endIndex = index + 1;
|
|
88
|
-
while (endIndex < len &&
|
|
88
|
+
while (endIndex < len &&
|
|
89
|
+
code[endIndex] !== quote &&
|
|
90
|
+
code[endIndex] !== "\n") {
|
|
89
91
|
endIndex++;
|
|
90
92
|
}
|
|
91
93
|
if (endIndex < len && code[endIndex] === quote) {
|
|
@@ -114,9 +116,7 @@ export function getPrologueDirectives(content) {
|
|
|
114
116
|
* when matching exported declarations.
|
|
115
117
|
*/
|
|
116
118
|
export function stripComments(content) {
|
|
117
|
-
return content
|
|
118
|
-
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
119
|
-
.replace(/\/\/[^\n]*/g, "");
|
|
119
|
+
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
122
|
* Analyzes the source content or file on disk to detect if a "use client" directive is present.
|
|
@@ -152,19 +152,25 @@ export async function detectRenderingType(fileContentOrPath) {
|
|
|
152
152
|
* @returns Array of discovered HTTP methods
|
|
153
153
|
*/
|
|
154
154
|
export function detectHttpMethods(content) {
|
|
155
|
-
const discovered = [];
|
|
156
155
|
const cleanCode = stripComments(content);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
const namedExports = new Set();
|
|
157
|
+
for (const match of cleanCode.matchAll(/\bexport\s*\{([^}]*)\}/g)) {
|
|
158
|
+
for (const entry of match[1].split(",")) {
|
|
159
|
+
const specifier = entry.trim();
|
|
160
|
+
if (!specifier || specifier.startsWith("type "))
|
|
161
|
+
continue;
|
|
162
|
+
const name = specifier
|
|
163
|
+
.split(/\s+as\s+/)
|
|
164
|
+
.pop()
|
|
165
|
+
.trim();
|
|
166
|
+
namedExports.add(name);
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
|
-
return
|
|
169
|
+
return HTTP_METHODS.filter((method) => {
|
|
170
|
+
// Direct declarations and named exports use the exported name, not the local alias.
|
|
171
|
+
const pattern = new RegExp(`export\\s+(?:async\\s+)?(?:function\\s+${method}\\b|(?:const|let|var)\\s+${method}(?:\\s*:[^=]+)?\\s*=)`, "m");
|
|
172
|
+
return namedExports.has(method) || pattern.test(cleanCode);
|
|
173
|
+
});
|
|
168
174
|
}
|
|
169
175
|
/**
|
|
170
176
|
* Detects if a file defines Server Actions via the "use server" directive.
|
|
@@ -256,8 +262,17 @@ export function parseRoutePath(relativePath) {
|
|
|
256
262
|
if (cleanedPart.startsWith("%5F") || cleanedPart.startsWith("%5f")) {
|
|
257
263
|
cleanedPart = "_" + cleanedPart.slice(3);
|
|
258
264
|
}
|
|
259
|
-
//
|
|
260
|
-
|
|
265
|
+
// Match URL segments, not filesystem levels: groups and slots never count.
|
|
266
|
+
const interception = cleanedPart.match(/^(\(\.\.\.\)|(?:\(\.\.\))+|\(\.\))/)?.[0];
|
|
267
|
+
if (interception) {
|
|
268
|
+
if (interception === "(...)")
|
|
269
|
+
urlSegments.length = 0;
|
|
270
|
+
else if (interception !== "(.)") {
|
|
271
|
+
const levels = interception.length / "(..)".length;
|
|
272
|
+
urlSegments.splice(Math.max(0, urlSegments.length - levels));
|
|
273
|
+
}
|
|
274
|
+
cleanedPart = cleanedPart.slice(interception.length);
|
|
275
|
+
}
|
|
261
276
|
urlSegments.push(cleanedPart);
|
|
262
277
|
}
|
|
263
278
|
const routePath = "/" + urlSegments.join("/");
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ export declare class RouteDirectoryReadError extends NextRouteGraphError {
|
|
|
22
22
|
readonly code = "ERR_DIRECTORY_READ";
|
|
23
23
|
constructor(dirPath?: string, cause?: unknown);
|
|
24
24
|
}
|
|
25
|
+
export declare class RouteFileReadError extends NextRouteGraphError {
|
|
26
|
+
readonly code = "ERR_FILE_READ";
|
|
27
|
+
constructor(filePath: string, cause: unknown);
|
|
28
|
+
}
|
|
25
29
|
export declare class RouteLintError extends NextRouteGraphError {
|
|
26
30
|
readonly code = "ERR_ROUTE_LINT";
|
|
27
31
|
readonly errorCount: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8BAAsB,mBAAoB,SAAQ,KAAK;IACrD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAM3C;AAED,qBAAa,oBAAqB,SAAQ,mBAAmB;IAC3D,QAAQ,CAAC,IAAI,2BAA2B;gBAE5B,WAAW,CAAC,EAAE,MAAM;CAQjC;AAED,qBAAa,oBAAqB,SAAQ,mBAAmB;IAC3D,QAAQ,CAAC,IAAI,0BAA0B;;CAQxC;AAED,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,QAAQ,CAAC,IAAI,uBAAuB;;CAQrC;AAED,qBAAa,uBAAwB,SAAQ,mBAAmB;IAC9D,QAAQ,CAAC,IAAI,wBAAwB;gBAEzB,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAW9C;AAED,qBAAa,cAAe,SAAQ,mBAAmB;IACrD,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,UAAU,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU;CAWzD"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,8BAAsB,mBAAoB,SAAQ,KAAK;IACrD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAM3C;AAED,qBAAa,oBAAqB,SAAQ,mBAAmB;IAC3D,QAAQ,CAAC,IAAI,2BAA2B;gBAE5B,WAAW,CAAC,EAAE,MAAM;CAQjC;AAED,qBAAa,oBAAqB,SAAQ,mBAAmB;IAC3D,QAAQ,CAAC,IAAI,0BAA0B;;CAQxC;AAED,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,QAAQ,CAAC,IAAI,uBAAuB;;CAQrC;AAED,qBAAa,uBAAwB,SAAQ,mBAAmB;IAC9D,QAAQ,CAAC,IAAI,wBAAwB;gBAEzB,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAW9C;AAED,qBAAa,kBAAmB,SAAQ,mBAAmB;IACzD,QAAQ,CAAC,IAAI,mBAAmB;gBAEpB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAO7C;AAED,qBAAa,cAAe,SAAQ,mBAAmB;IACrD,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,UAAU,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU;CAWzD"}
|
package/dist/errors/index.js
CHANGED
|
@@ -41,6 +41,13 @@ export class RouteDirectoryReadError extends NextRouteGraphError {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
export class RouteFileReadError extends NextRouteGraphError {
|
|
45
|
+
code = "ERR_FILE_READ";
|
|
46
|
+
constructor(filePath, cause) {
|
|
47
|
+
super(`Unable to read route file: "${filePath}"`, "Check that the file still exists and is readable, then scan again.");
|
|
48
|
+
this.cause = cause;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
44
51
|
export class RouteLintError extends NextRouteGraphError {
|
|
45
52
|
code = "ERR_ROUTE_LINT";
|
|
46
53
|
errorCount;
|
|
@@ -51,7 +58,7 @@ export class RouteLintError extends NextRouteGraphError {
|
|
|
51
58
|
details.push(`${errorCount} error(s)`);
|
|
52
59
|
if (warningCount > 0)
|
|
53
60
|
details.push(`${warningCount} warning(s)`);
|
|
54
|
-
super(`Route validation failed with ${details.join(" and ") || "issues"}.`, "Fix the reported route issues
|
|
61
|
+
super(`Route validation failed with ${details.join(" and ") || "issues"}.`, "Fix the reported route issues. Use a normal scan without --check or --strict to inspect without failing validation.");
|
|
55
62
|
this.errorCount = errorCount;
|
|
56
63
|
this.warningCount = warningCount;
|
|
57
64
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* Programmatic SDK entry point.
|
|
6
6
|
*/
|
|
7
7
|
export { analyzeRoutes } from "./core/analyzer.js";
|
|
8
|
+
export { inspectProject, filterRoutes } from "./core/inspect.js";
|
|
9
|
+
export { buildRouteGraph, type RouteGraphNode } from "./render/graph.js";
|
|
8
10
|
export { detectAppRouter, type DetectionResult } from "./core/detector.js";
|
|
9
11
|
export { lintRoutes } from "./core/linter.js";
|
|
10
12
|
export { detectHttpMethods, detectRenderingType, detectRouteConfig, detectServerActions, extractRouteMetadata, getPrologueDirectives, getSegmentType, HTTP_METHODS, parseRoutePath, parseSpecialFileType, SPECIAL_FILES, stripComments, } from "./core/parser.js";
|
|
11
13
|
export { scanAppDir } from "./core/scanner.js";
|
|
12
|
-
export { AmbiguousRouterError, NextRouteGraphError, NoAppRouterError, ProjectNotFoundError, RouteDirectoryReadError, RouteLintError, } from "./errors/index.js";
|
|
13
|
-
export { DotRenderer, FlatRenderer, getRenderer, JsonRenderer, MarkdownRenderer, MermaidRenderer, renderDot, renderFlat, renderJson, renderMarkdown, renderMermaid, renderTree, TreeRenderer, } from "./render/index.js";
|
|
14
|
+
export { AmbiguousRouterError, NextRouteGraphError, NoAppRouterError, ProjectNotFoundError, RouteDirectoryReadError, RouteFileReadError, RouteLintError, } from "./errors/index.js";
|
|
15
|
+
export { DotRenderer, FlatRenderer, getRenderer, HtmlRenderer, JsonRenderer, MarkdownRenderer, MermaidRenderer, renderDot, renderFlat, renderHtml, renderJson, renderMarkdown, renderMermaid, renderTree, TreeRenderer, SvgRenderer, renderSvg, } from "./render/index.js";
|
|
14
16
|
export type { OutputRenderer } from "./render/index.js";
|
|
15
17
|
export type { AnalysisResult, CLIOptions, DiscoveredFile, HttpMethod, LintIssue, LintResult, LintSeverity, OutputFormat, RenderingType, RouteEntry, RouteFile, SegmentType, SpecialFileType, SummaryStats, } from "./types/index.js";
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,YAAY,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,EACT,WAAW,EACX,eAAe,EACf,YAAY,GACb,MAAM,kBAAkB,CAAC"}
|