@teardown/navigation-metro 2.0.53 → 2.0.56
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/dist/generator/index.d.ts +5 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +12 -0
- package/dist/generator/route-generator.d.ts +37 -0
- package/dist/generator/route-generator.d.ts.map +1 -0
- package/dist/generator/route-generator.js +179 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/scanner/file-scanner.d.ts +62 -0
- package/dist/scanner/file-scanner.d.ts.map +1 -0
- package/dist/scanner/file-scanner.js +250 -0
- package/dist/scanner/index.d.ts +5 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +12 -0
- package/{src/validator/index.ts → dist/validator/index.d.ts} +1 -1
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +8 -0
- package/dist/validator/route-validator.d.ts +15 -0
- package/dist/validator/route-validator.d.ts.map +1 -0
- package/dist/validator/route-validator.js +153 -0
- package/dist/watcher/file-watcher.d.ts +27 -0
- package/dist/watcher/file-watcher.d.ts.map +1 -0
- package/dist/watcher/file-watcher.js +110 -0
- package/{src/watcher/index.ts → dist/watcher/index.d.ts} +1 -1
- package/dist/watcher/index.d.ts.map +1 -0
- package/dist/watcher/index.js +10 -0
- package/package.json +12 -9
- package/src/generator/index.ts +0 -13
- package/src/generator/route-generator.test.ts +0 -287
- package/src/generator/route-generator.ts +0 -231
- package/src/index.ts +0 -158
- package/src/scanner/file-scanner.test.ts +0 -271
- package/src/scanner/file-scanner.ts +0 -329
- package/src/scanner/index.ts +0 -15
- package/src/validator/route-validator.test.ts +0 -192
- package/src/validator/route-validator.ts +0 -178
- package/src/watcher/file-watcher.ts +0 -132
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { validateRoutes } from "./route-validator";
|
|
5
|
-
|
|
6
|
-
const TEST_DIR = join(import.meta.dir, "__test_routes__");
|
|
7
|
-
|
|
8
|
-
function createTestFile(relativePath: string, content: string) {
|
|
9
|
-
const fullPath = join(TEST_DIR, relativePath);
|
|
10
|
-
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
11
|
-
mkdirSync(dir, { recursive: true });
|
|
12
|
-
writeFileSync(fullPath, content);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe("Route Validator", () => {
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
mkdirSync(TEST_DIR, { recursive: true });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("validateRoutes", () => {
|
|
25
|
-
it("should return error for non-existent directory", () => {
|
|
26
|
-
const errors = validateRoutes("/non/existent/path");
|
|
27
|
-
expect(errors.length).toBeGreaterThan(0);
|
|
28
|
-
expect(errors[0].severity).toBe("error");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("should return no errors for valid simple route", () => {
|
|
32
|
-
createTestFile(
|
|
33
|
-
"about.tsx",
|
|
34
|
-
`
|
|
35
|
-
export default function About() {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
`
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const errors = validateRoutes(TEST_DIR);
|
|
42
|
-
const actualErrors = errors.filter((e) => e.severity === "error");
|
|
43
|
-
expect(actualErrors).toEqual([]);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("should detect missing default export", () => {
|
|
47
|
-
createTestFile(
|
|
48
|
-
"about.tsx",
|
|
49
|
-
`
|
|
50
|
-
export function About() {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
`
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const errors = validateRoutes(TEST_DIR);
|
|
57
|
-
const missingExport = errors.find((e) => e.message.includes("default export"));
|
|
58
|
-
expect(missingExport).toBeDefined();
|
|
59
|
-
expect(missingExport?.severity).toBe("error");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("should detect duplicate route paths", () => {
|
|
63
|
-
// Create two routes that resolve to the same path
|
|
64
|
-
createTestFile("users/index.tsx", "export default function UsersIndex() {}");
|
|
65
|
-
// We can't easily create duplicate paths with file-based routing
|
|
66
|
-
// but we can simulate by checking the validator handles it
|
|
67
|
-
// For now, just check that the validator runs without error
|
|
68
|
-
const errors = validateRoutes(TEST_DIR);
|
|
69
|
-
expect(errors).toBeDefined();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("should warn when screen doesn't use defineScreen", () => {
|
|
73
|
-
createTestFile(
|
|
74
|
-
"about.tsx",
|
|
75
|
-
`
|
|
76
|
-
export default function About() {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
`
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const errors = validateRoutes(TEST_DIR);
|
|
83
|
-
const warning = errors.find((e) => e.message.includes("defineScreen") && e.severity === "warning");
|
|
84
|
-
expect(warning).toBeDefined();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("should not warn when screen uses defineScreen", () => {
|
|
88
|
-
createTestFile(
|
|
89
|
-
"about.tsx",
|
|
90
|
-
`
|
|
91
|
-
import { defineScreen } from '@teardown/navigation';
|
|
92
|
-
|
|
93
|
-
function AboutScreen() {
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export default defineScreen({
|
|
98
|
-
component: AboutScreen,
|
|
99
|
-
});
|
|
100
|
-
`
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
const errors = validateRoutes(TEST_DIR);
|
|
104
|
-
const defineScreenWarning = errors.find((e) => e.message.includes("defineScreen") && e.file.includes("about"));
|
|
105
|
-
expect(defineScreenWarning).toBeUndefined();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("should warn when layout doesn't use defineLayout", () => {
|
|
109
|
-
createTestFile(
|
|
110
|
-
"_layout.tsx",
|
|
111
|
-
`
|
|
112
|
-
export default {
|
|
113
|
-
type: 'stack'
|
|
114
|
-
};
|
|
115
|
-
`
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const errors = validateRoutes(TEST_DIR);
|
|
119
|
-
const warning = errors.find((e) => e.message.includes("defineLayout"));
|
|
120
|
-
expect(warning).toBeDefined();
|
|
121
|
-
expect(warning?.severity).toBe("warning");
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("should not warn when layout uses defineLayout", () => {
|
|
125
|
-
createTestFile(
|
|
126
|
-
"_layout.tsx",
|
|
127
|
-
`
|
|
128
|
-
import { defineLayout } from '@teardown/navigation';
|
|
129
|
-
|
|
130
|
-
export default defineLayout({
|
|
131
|
-
type: 'stack'
|
|
132
|
-
});
|
|
133
|
-
`
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const errors = validateRoutes(TEST_DIR);
|
|
137
|
-
const defineLayoutWarning = errors.find((e) => e.message.includes("defineLayout") && e.file.includes("_layout"));
|
|
138
|
-
expect(defineLayoutWarning).toBeUndefined();
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("should warn when dynamic route lacks param schema", () => {
|
|
142
|
-
createTestFile(
|
|
143
|
-
"users/[userId].tsx",
|
|
144
|
-
`
|
|
145
|
-
export default function UserProfile() {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
`
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
const errors = validateRoutes(TEST_DIR);
|
|
152
|
-
const warning = errors.find((e) => e.message.includes("param") && e.message.includes("schema"));
|
|
153
|
-
expect(warning).toBeDefined();
|
|
154
|
-
expect(warning?.severity).toBe("warning");
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("should not warn when dynamic route has param schema", () => {
|
|
158
|
-
createTestFile(
|
|
159
|
-
"users/[userId].tsx",
|
|
160
|
-
`
|
|
161
|
-
import { createParamSchema, paramValidators } from '@teardown/navigation';
|
|
162
|
-
|
|
163
|
-
export const paramsSchema = createParamSchema({
|
|
164
|
-
userId: paramValidators.uuid(),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
export default function UserProfile() {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
`
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const errors = validateRoutes(TEST_DIR);
|
|
174
|
-
const schemaWarning = errors.find(
|
|
175
|
-
(e) => e.message.includes("param") && e.message.includes("schema") && e.file.includes("[userId]")
|
|
176
|
-
);
|
|
177
|
-
expect(schemaWarning).toBeUndefined();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("should validate nested routes", () => {
|
|
181
|
-
createTestFile("_layout.tsx", "export default { type: 'stack' }");
|
|
182
|
-
createTestFile("users/_layout.tsx", "export default { type: 'stack' }");
|
|
183
|
-
createTestFile("users/index.tsx", "export default function Users() {}");
|
|
184
|
-
createTestFile("users/[userId].tsx", "export default function User() {}");
|
|
185
|
-
|
|
186
|
-
const errors = validateRoutes(TEST_DIR);
|
|
187
|
-
// Should have some warnings but no errors
|
|
188
|
-
const actualErrors = errors.filter((e) => e.severity === "error");
|
|
189
|
-
expect(actualErrors).toEqual([]);
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
});
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route validator for @teardown/navigation-metro
|
|
3
|
-
* Validates route files for common issues and best practices
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { readFileSync } from "node:fs";
|
|
7
|
-
import { flattenRoutes, type RouteNode, scanRoutesDirectory } from "../scanner/file-scanner";
|
|
8
|
-
|
|
9
|
-
export interface ValidationError {
|
|
10
|
-
file: string;
|
|
11
|
-
message: string;
|
|
12
|
-
severity: "error" | "warning";
|
|
13
|
-
line?: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Validates all routes in a directory
|
|
18
|
-
*/
|
|
19
|
-
export function validateRoutes(routesDir: string): ValidationError[] {
|
|
20
|
-
const errors: ValidationError[] = [];
|
|
21
|
-
const { routes, errors: scanErrors } = scanRoutesDirectory(routesDir);
|
|
22
|
-
|
|
23
|
-
// Add scan errors
|
|
24
|
-
errors.push(
|
|
25
|
-
...scanErrors.map((e) => ({
|
|
26
|
-
file: e.file,
|
|
27
|
-
message: e.message,
|
|
28
|
-
severity: "error" as const,
|
|
29
|
-
}))
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// If the directory doesn't exist, we already have an error
|
|
33
|
-
if (scanErrors.length > 0 && routes.length === 0) {
|
|
34
|
-
return errors;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Flatten routes for validation
|
|
38
|
-
const flatRoutes = flattenRoutes(routes);
|
|
39
|
-
const seenPaths = new Map<string, string>();
|
|
40
|
-
|
|
41
|
-
for (const route of flatRoutes) {
|
|
42
|
-
// Skip layout files for path uniqueness check
|
|
43
|
-
if (route.isLayout) {
|
|
44
|
-
validateLayoutFile(route, errors);
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Check for duplicate paths
|
|
49
|
-
if (seenPaths.has(route.path)) {
|
|
50
|
-
errors.push({
|
|
51
|
-
file: route.filePath,
|
|
52
|
-
message: `Duplicate route path "${route.path}" (also defined in ${seenPaths.get(route.path)})`,
|
|
53
|
-
severity: "error",
|
|
54
|
-
});
|
|
55
|
-
} else {
|
|
56
|
-
seenPaths.set(route.path, route.filePath);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Validate screen file
|
|
60
|
-
validateScreenFile(route, errors);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return errors;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Validates a screen file
|
|
68
|
-
*/
|
|
69
|
-
function validateScreenFile(route: RouteNode, errors: ValidationError[]): void {
|
|
70
|
-
const content = safeReadFile(route.filePath);
|
|
71
|
-
if (content === null) {
|
|
72
|
-
errors.push({
|
|
73
|
-
file: route.filePath,
|
|
74
|
-
message: "Could not read route file",
|
|
75
|
-
severity: "error",
|
|
76
|
-
});
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Check for default export
|
|
81
|
-
if (!hasDefaultExport(content)) {
|
|
82
|
-
errors.push({
|
|
83
|
-
file: route.filePath,
|
|
84
|
-
message: "Route file must have a default export",
|
|
85
|
-
severity: "error",
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Check for defineScreen usage
|
|
90
|
-
if (!usesDefineScreen(content)) {
|
|
91
|
-
errors.push({
|
|
92
|
-
file: route.filePath,
|
|
93
|
-
message: "Screen should use defineScreen() for proper typing",
|
|
94
|
-
severity: "warning",
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Check dynamic routes have param schema
|
|
99
|
-
if (route.params.length > 0 && !hasParamSchema(content)) {
|
|
100
|
-
errors.push({
|
|
101
|
-
file: route.filePath,
|
|
102
|
-
message: "Dynamic route should export a params schema for runtime validation",
|
|
103
|
-
severity: "warning",
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Validates a layout file
|
|
110
|
-
*/
|
|
111
|
-
function validateLayoutFile(route: RouteNode, errors: ValidationError[]): void {
|
|
112
|
-
const content = safeReadFile(route.filePath);
|
|
113
|
-
if (content === null) {
|
|
114
|
-
errors.push({
|
|
115
|
-
file: route.filePath,
|
|
116
|
-
message: "Could not read layout file",
|
|
117
|
-
severity: "error",
|
|
118
|
-
});
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Check for default export
|
|
123
|
-
if (!hasDefaultExport(content)) {
|
|
124
|
-
errors.push({
|
|
125
|
-
file: route.filePath,
|
|
126
|
-
message: "Layout file must have a default export",
|
|
127
|
-
severity: "error",
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Check for defineLayout usage
|
|
132
|
-
if (!usesDefineLayout(content)) {
|
|
133
|
-
errors.push({
|
|
134
|
-
file: route.filePath,
|
|
135
|
-
message: "Layout file should use defineLayout() for proper configuration",
|
|
136
|
-
severity: "warning",
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Safely reads a file, returning null on error
|
|
143
|
-
*/
|
|
144
|
-
function safeReadFile(filePath: string): string | null {
|
|
145
|
-
try {
|
|
146
|
-
return readFileSync(filePath, "utf-8");
|
|
147
|
-
} catch {
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Checks if file has a default export
|
|
154
|
-
*/
|
|
155
|
-
function hasDefaultExport(content: string): boolean {
|
|
156
|
-
return content.includes("export default");
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Checks if file uses defineScreen
|
|
161
|
-
*/
|
|
162
|
-
function usesDefineScreen(content: string): boolean {
|
|
163
|
-
return content.includes("defineScreen");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Checks if file uses defineLayout
|
|
168
|
-
*/
|
|
169
|
-
function usesDefineLayout(content: string): boolean {
|
|
170
|
-
return content.includes("defineLayout");
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Checks if file has a param schema
|
|
175
|
-
*/
|
|
176
|
-
function hasParamSchema(content: string): boolean {
|
|
177
|
-
return content.includes("paramsSchema") || content.includes("createParamSchema");
|
|
178
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File watcher for @teardown/navigation-metro
|
|
3
|
-
* Watches route files and triggers regeneration on changes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { join, relative } from "node:path";
|
|
7
|
-
import { type FSWatcher, watch } from "chokidar";
|
|
8
|
-
import { generateAllRouteFiles } from "../generator/route-generator";
|
|
9
|
-
import { type ValidationError, validateRoutes } from "../validator/route-validator";
|
|
10
|
-
|
|
11
|
-
export interface WatcherOptions {
|
|
12
|
-
routesDir: string;
|
|
13
|
-
generatedDir: string;
|
|
14
|
-
prefixes: string[];
|
|
15
|
-
verbose: boolean;
|
|
16
|
-
onRegenerate?: () => void;
|
|
17
|
-
onError?: (errors: ValidationError[]) => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let watcherInstance: FSWatcher | null = null;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Starts watching the routes directory for changes
|
|
24
|
-
* Returns a cleanup function to stop watching
|
|
25
|
-
*/
|
|
26
|
-
export function startRouteWatcher(options: WatcherOptions): () => void {
|
|
27
|
-
const { routesDir, generatedDir, prefixes, verbose, onRegenerate, onError } = options;
|
|
28
|
-
|
|
29
|
-
// Close existing watcher if any
|
|
30
|
-
if (watcherInstance) {
|
|
31
|
-
watcherInstance.close();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const watcher = watch(join(routesDir, "**/*.{ts,tsx}"), {
|
|
35
|
-
ignoreInitial: true,
|
|
36
|
-
ignored: [
|
|
37
|
-
/(^|[/\\])\../, // Dotfiles
|
|
38
|
-
/node_modules/,
|
|
39
|
-
/\.test\./,
|
|
40
|
-
/\.spec\./,
|
|
41
|
-
],
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
45
|
-
|
|
46
|
-
const regenerate = () => {
|
|
47
|
-
if (debounceTimer) {
|
|
48
|
-
clearTimeout(debounceTimer);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: debounced validate + generate
|
|
52
|
-
debounceTimer = setTimeout(() => {
|
|
53
|
-
try {
|
|
54
|
-
// Validate first
|
|
55
|
-
const errors = validateRoutes(routesDir);
|
|
56
|
-
const hasErrors = errors.some((e) => e.severity === "error");
|
|
57
|
-
|
|
58
|
-
if (hasErrors) {
|
|
59
|
-
if (verbose) {
|
|
60
|
-
console.error("[teardown/navigation] Validation errors:");
|
|
61
|
-
for (const e of errors.filter((err) => err.severity === "error")) {
|
|
62
|
-
console.error(` ${e.file}: ${e.message}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
onError?.(errors);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Generate if validation passes
|
|
70
|
-
generateAllRouteFiles({ routesDir, generatedDir, prefixes, verbose });
|
|
71
|
-
|
|
72
|
-
if (verbose) {
|
|
73
|
-
console.log("[teardown/navigation] Routes regenerated");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
onRegenerate?.();
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (verbose) {
|
|
79
|
-
console.error("[teardown/navigation] Generation failed:", error);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}, 100);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
watcher.on("add", (filePath) => {
|
|
86
|
-
if (verbose) {
|
|
87
|
-
console.log(`[teardown/navigation] File added: ${relative(routesDir, filePath)}`);
|
|
88
|
-
}
|
|
89
|
-
regenerate();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
watcher.on("unlink", (filePath) => {
|
|
93
|
-
if (verbose) {
|
|
94
|
-
console.log(`[teardown/navigation] File removed: ${relative(routesDir, filePath)}`);
|
|
95
|
-
}
|
|
96
|
-
regenerate();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
watcher.on("change", (filePath) => {
|
|
100
|
-
if (verbose) {
|
|
101
|
-
console.log(`[teardown/navigation] File changed: ${relative(routesDir, filePath)}`);
|
|
102
|
-
}
|
|
103
|
-
regenerate();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
watcherInstance = watcher;
|
|
107
|
-
|
|
108
|
-
return () => {
|
|
109
|
-
if (debounceTimer) {
|
|
110
|
-
clearTimeout(debounceTimer);
|
|
111
|
-
}
|
|
112
|
-
watcher.close();
|
|
113
|
-
watcherInstance = null;
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Stops the route watcher if it's running
|
|
119
|
-
*/
|
|
120
|
-
export function stopRouteWatcher(): void {
|
|
121
|
-
if (watcherInstance) {
|
|
122
|
-
watcherInstance.close();
|
|
123
|
-
watcherInstance = null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Checks if the watcher is currently running
|
|
129
|
-
*/
|
|
130
|
-
export function isWatcherRunning(): boolean {
|
|
131
|
-
return watcherInstance !== null;
|
|
132
|
-
}
|