@teardown/navigation-metro 2.0.68 → 2.0.70

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/index.d.ts CHANGED
@@ -26,6 +26,11 @@ export interface TeardownNavigationOptions {
26
26
  * @default false
27
27
  */
28
28
  verbose?: boolean;
29
+ /**
30
+ * Auto-populate new route files with template content
31
+ * @default true
32
+ */
33
+ autoTemplate?: boolean;
29
34
  }
30
35
  /**
31
36
  * Metro configuration type (simplified)
@@ -76,6 +81,7 @@ export type { GenerateOptions, RouteParamEntry } from "./generator/route-generat
76
81
  export { generateAllRouteFiles } from "./generator/route-generator";
77
82
  export type { ParamDefinition, RouteNode, ScanError, ScanResult } from "./scanner/file-scanner";
78
83
  export { buildUrlPath, extractParams, filePathToScreenName, flattenRoutes, scanRoutesDirectory, } from "./scanner/file-scanner";
84
+ export { extractParamsFromPath, fileNameToScreenName, generateLayoutTemplate, generateRouteTemplate, generateScreenTemplate, getTemplateType, isFileEmpty, screenNameToTitle, } from "./templates/route-templates";
79
85
  export type { ValidationError } from "./validator/route-validator";
80
86
  export { validateRoutes } from "./validator/route-validator";
81
87
  export type { WatcherOptions } from "./watcher/file-watcher";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmCH;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE;QACV,cAAc,CAAC,EAAE,CAChB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,KACnB;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAC/C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACvB,CAAC;IACF,WAAW,CAAC,EAAE;QACb,4BAA4B,CAAC,EAAE,OAAO,CAAC;QACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACvB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,yBAA8B,GAAG,WAAW,CAqEhH;AAED,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EACN,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,mBAAmB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmCH;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE;QACV,cAAc,CAAC,EAAE,CAChB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,KACnB;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAC/C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACvB,CAAC;IACF,WAAW,CAAC,EAAE;QACb,4BAA4B,CAAC,EAAE,OAAO,CAAC;QACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACvB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,yBAA8B,GAAG,WAAW,CAsEhH;AAED,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEpF,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EACN,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,mBAAmB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,iBAAiB,GACjB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Metro plugin for type-safe file-based navigation
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.stopRouteWatcher = exports.startRouteWatcher = exports.isWatcherRunning = exports.validateRoutes = exports.scanRoutesDirectory = exports.flattenRoutes = exports.filePathToScreenName = exports.extractParams = exports.buildUrlPath = exports.generateAllRouteFiles = void 0;
7
+ exports.stopRouteWatcher = exports.startRouteWatcher = exports.isWatcherRunning = exports.validateRoutes = exports.screenNameToTitle = exports.isFileEmpty = exports.getTemplateType = exports.generateScreenTemplate = exports.generateRouteTemplate = exports.generateLayoutTemplate = exports.fileNameToScreenName = exports.extractParamsFromPath = exports.scanRoutesDirectory = exports.flattenRoutes = exports.filePathToScreenName = exports.extractParams = exports.buildUrlPath = exports.generateAllRouteFiles = void 0;
8
8
  exports.withTeardownNavigation = withTeardownNavigation;
9
9
  const node_fs_1 = require("node:fs");
10
10
  const node_path_1 = require("node:path");
@@ -62,7 +62,7 @@ function readSlugFromConfig(projectRoot) {
62
62
  * ```
63
63
  */
64
64
  function withTeardownNavigation(config, options = {}) {
65
- const { routesDir = "./src/routes", generatedDir = "./.teardown", verbose = false } = options;
65
+ const { routesDir = "./src/routes", generatedDir = "./.teardown", verbose = false, autoTemplate = true } = options;
66
66
  const projectRoot = config.projectRoot ?? process.cwd();
67
67
  const absoluteRoutesDir = (0, node_path_1.resolve)(projectRoot, routesDir);
68
68
  const absoluteGeneratedDir = (0, node_path_1.resolve)(projectRoot, generatedDir);
@@ -99,6 +99,7 @@ function withTeardownNavigation(config, options = {}) {
99
99
  generatedDir: absoluteGeneratedDir,
100
100
  prefixes,
101
101
  verbose,
102
+ autoTemplate,
102
103
  onRegenerate: () => {
103
104
  if (verbose) {
104
105
  console.log("[teardown/navigation] Routes regenerated");
@@ -134,6 +135,15 @@ Object.defineProperty(exports, "extractParams", { enumerable: true, get: functio
134
135
  Object.defineProperty(exports, "filePathToScreenName", { enumerable: true, get: function () { return file_scanner_1.filePathToScreenName; } });
135
136
  Object.defineProperty(exports, "flattenRoutes", { enumerable: true, get: function () { return file_scanner_1.flattenRoutes; } });
136
137
  Object.defineProperty(exports, "scanRoutesDirectory", { enumerable: true, get: function () { return file_scanner_1.scanRoutesDirectory; } });
138
+ var route_templates_1 = require("./templates/route-templates");
139
+ Object.defineProperty(exports, "extractParamsFromPath", { enumerable: true, get: function () { return route_templates_1.extractParamsFromPath; } });
140
+ Object.defineProperty(exports, "fileNameToScreenName", { enumerable: true, get: function () { return route_templates_1.fileNameToScreenName; } });
141
+ Object.defineProperty(exports, "generateLayoutTemplate", { enumerable: true, get: function () { return route_templates_1.generateLayoutTemplate; } });
142
+ Object.defineProperty(exports, "generateRouteTemplate", { enumerable: true, get: function () { return route_templates_1.generateRouteTemplate; } });
143
+ Object.defineProperty(exports, "generateScreenTemplate", { enumerable: true, get: function () { return route_templates_1.generateScreenTemplate; } });
144
+ Object.defineProperty(exports, "getTemplateType", { enumerable: true, get: function () { return route_templates_1.getTemplateType; } });
145
+ Object.defineProperty(exports, "isFileEmpty", { enumerable: true, get: function () { return route_templates_1.isFileEmpty; } });
146
+ Object.defineProperty(exports, "screenNameToTitle", { enumerable: true, get: function () { return route_templates_1.screenNameToTitle; } });
137
147
  var route_validator_1 = require("./validator/route-validator");
138
148
  Object.defineProperty(exports, "validateRoutes", { enumerable: true, get: function () { return route_validator_1.validateRoutes; } });
139
149
  var file_watcher_2 = require("./watcher/file-watcher");
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Template module exports for @teardown/navigation-metro
3
+ */
4
+ export { extractParamsFromPath, fileNameToScreenName, generateLayoutTemplate, generateRouteTemplate, generateScreenTemplate, getTemplateType, isFileEmpty, screenNameToTitle, } from "./route-templates";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,iBAAiB,GACjB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Template module exports for @teardown/navigation-metro
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.screenNameToTitle = exports.isFileEmpty = exports.getTemplateType = exports.generateScreenTemplate = exports.generateRouteTemplate = exports.generateLayoutTemplate = exports.fileNameToScreenName = exports.extractParamsFromPath = void 0;
7
+ var route_templates_1 = require("./route-templates");
8
+ Object.defineProperty(exports, "extractParamsFromPath", { enumerable: true, get: function () { return route_templates_1.extractParamsFromPath; } });
9
+ Object.defineProperty(exports, "fileNameToScreenName", { enumerable: true, get: function () { return route_templates_1.fileNameToScreenName; } });
10
+ Object.defineProperty(exports, "generateLayoutTemplate", { enumerable: true, get: function () { return route_templates_1.generateLayoutTemplate; } });
11
+ Object.defineProperty(exports, "generateRouteTemplate", { enumerable: true, get: function () { return route_templates_1.generateRouteTemplate; } });
12
+ Object.defineProperty(exports, "generateScreenTemplate", { enumerable: true, get: function () { return route_templates_1.generateScreenTemplate; } });
13
+ Object.defineProperty(exports, "getTemplateType", { enumerable: true, get: function () { return route_templates_1.getTemplateType; } });
14
+ Object.defineProperty(exports, "isFileEmpty", { enumerable: true, get: function () { return route_templates_1.isFileEmpty; } });
15
+ Object.defineProperty(exports, "screenNameToTitle", { enumerable: true, get: function () { return route_templates_1.screenNameToTitle; } });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Route templates for @teardown/navigation-metro
3
+ * Generates template content for new route files
4
+ */
5
+ import type { ParamDefinition } from "../scanner/file-scanner";
6
+ /**
7
+ * Checks if a file is empty or has minimal content (less than 10 bytes)
8
+ */
9
+ export declare function isFileEmpty(filePath: string): boolean;
10
+ /**
11
+ * Converts a filename to a PascalCase screen name
12
+ * e.g., "user-profile" -> "UserProfile", "[userId]" -> "UserId"
13
+ */
14
+ export declare function fileNameToScreenName(fileName: string): string;
15
+ /**
16
+ * Converts a PascalCase name to a human-readable title
17
+ * e.g., "UserProfile" -> "User Profile"
18
+ */
19
+ export declare function screenNameToTitle(screenName: string): string;
20
+ /**
21
+ * Generates the template content for a screen file
22
+ */
23
+ export declare function generateScreenTemplate(routeName: string, params?: ParamDefinition[]): string;
24
+ /**
25
+ * Generates the template content for a layout file
26
+ */
27
+ export declare function generateLayoutTemplate(layoutType?: "stack" | "tabs" | "drawer"): string;
28
+ /**
29
+ * Determines the appropriate template type from a file path
30
+ */
31
+ export declare function getTemplateType(relativePath: string): "screen" | "layout";
32
+ /**
33
+ * Extracts dynamic parameters from a filename
34
+ * Mirrors the logic from file-scanner.ts
35
+ */
36
+ export declare function extractParamsFromPath(fileName: string): ParamDefinition[];
37
+ /**
38
+ * Generates the appropriate template for a route file
39
+ */
40
+ export declare function generateRouteTemplate(relativePath: string): string;
41
+ //# sourceMappingURL=route-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-templates.d.ts","sourceRoot":"","sources":["../../src/templates/route-templates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAarD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgB7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,GAAE,eAAe,EAAO,GAAG,MAAM,CA2ChG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,GAAE,OAAO,GAAG,MAAM,GAAG,QAAkB,GAAG,MAAM,CA0BhG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAIzE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE,CAoBzE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CASlE"}
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * Route templates for @teardown/navigation-metro
4
+ * Generates template content for new route files
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isFileEmpty = isFileEmpty;
8
+ exports.fileNameToScreenName = fileNameToScreenName;
9
+ exports.screenNameToTitle = screenNameToTitle;
10
+ exports.generateScreenTemplate = generateScreenTemplate;
11
+ exports.generateLayoutTemplate = generateLayoutTemplate;
12
+ exports.getTemplateType = getTemplateType;
13
+ exports.extractParamsFromPath = extractParamsFromPath;
14
+ exports.generateRouteTemplate = generateRouteTemplate;
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = require("node:path");
17
+ /**
18
+ * Checks if a file is empty or has minimal content (less than 10 bytes)
19
+ */
20
+ function isFileEmpty(filePath) {
21
+ try {
22
+ const stats = (0, node_fs_1.statSync)(filePath);
23
+ if (stats.size < 10) {
24
+ return true;
25
+ }
26
+ // Also check if file only contains whitespace
27
+ const content = (0, node_fs_1.readFileSync)(filePath, "utf-8").trim();
28
+ return content.length === 0;
29
+ }
30
+ catch {
31
+ // If we can't read the file, assume it's not empty
32
+ return false;
33
+ }
34
+ }
35
+ /**
36
+ * Converts a filename to a PascalCase screen name
37
+ * e.g., "user-profile" -> "UserProfile", "[userId]" -> "UserId"
38
+ */
39
+ function fileNameToScreenName(fileName) {
40
+ const ext = (0, node_path_1.extname)(fileName);
41
+ const baseName = (0, node_path_1.basename)(fileName, ext);
42
+ // Remove param brackets and special characters
43
+ const cleanName = baseName
44
+ .replace(/\[\.\.\.([^\]]+)\]/g, "$1") // [...slug] -> slug
45
+ .replace(/\[\[([^\]]+)\]\]/g, "$1") // [[id]] -> id
46
+ .replace(/\[([^\]]+)\]/g, "$1") // [userId] -> userId
47
+ .replace(/\?/g, ""); // Remove optional markers
48
+ // Convert to PascalCase
49
+ return cleanName
50
+ .split(/[-_]/)
51
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
52
+ .join("");
53
+ }
54
+ /**
55
+ * Converts a PascalCase name to a human-readable title
56
+ * e.g., "UserProfile" -> "User Profile"
57
+ */
58
+ function screenNameToTitle(screenName) {
59
+ return screenName.replace(/([A-Z])/g, " $1").trim();
60
+ }
61
+ /**
62
+ * Generates the template content for a screen file
63
+ */
64
+ function generateScreenTemplate(routeName, params = []) {
65
+ const screenName = fileNameToScreenName(routeName);
66
+ const title = screenNameToTitle(screenName);
67
+ // Build params type annotation if there are params
68
+ let paramsImport = "";
69
+ let paramsType = "";
70
+ let paramsUsage = "";
71
+ if (params.length > 0) {
72
+ const paramEntries = params.map((p) => {
73
+ const type = p.isCatchAll ? "string[]" : "string";
74
+ return `${p.name}${p.isOptional ? "?" : ""}: ${type}`;
75
+ });
76
+ paramsType = `{ ${paramEntries.join("; ")} }`;
77
+ paramsImport = '\nimport { useTypedParams } from "@teardown/navigation";';
78
+ paramsUsage = `
79
+ const params = useTypedParams<${paramsType}>();`;
80
+ }
81
+ return `/**
82
+ * ${title} Screen
83
+ */
84
+
85
+ import { defineScreen } from "@teardown/navigation/primitives";${paramsImport}
86
+ import type React from "react";
87
+ import { View, Text } from "react-native";
88
+
89
+ function ${screenName}Screen(): React.JSX.Element {${paramsUsage}
90
+ return (
91
+ <View className="flex-1 bg-background p-6">
92
+ <Text className="text-foreground">${title}</Text>
93
+ </View>
94
+ );
95
+ }
96
+
97
+ export default defineScreen({
98
+ component: ${screenName}Screen,
99
+ options: {
100
+ title: "${title}",
101
+ },
102
+ });
103
+ `;
104
+ }
105
+ /**
106
+ * Generates the template content for a layout file
107
+ */
108
+ function generateLayoutTemplate(layoutType = "stack") {
109
+ const screenOptionsMap = {
110
+ stack: `{
111
+ headerShown: true,
112
+ }`,
113
+ tabs: `{
114
+ headerShown: false,
115
+ tabBarActiveTintColor: "#007AFF",
116
+ }`,
117
+ drawer: `{
118
+ headerShown: true,
119
+ drawerType: "front",
120
+ }`,
121
+ };
122
+ return `/**
123
+ * Layout Configuration
124
+ */
125
+
126
+ import { defineLayout } from "@teardown/navigation/primitives";
127
+
128
+ export default defineLayout({
129
+ type: "${layoutType}",
130
+ screenOptions: ${screenOptionsMap[layoutType]},
131
+ });
132
+ `;
133
+ }
134
+ /**
135
+ * Determines the appropriate template type from a file path
136
+ */
137
+ function getTemplateType(relativePath) {
138
+ const ext = (0, node_path_1.extname)(relativePath);
139
+ const fileName = (0, node_path_1.basename)(relativePath, ext);
140
+ return fileName === "_layout" ? "layout" : "screen";
141
+ }
142
+ /**
143
+ * Extracts dynamic parameters from a filename
144
+ * Mirrors the logic from file-scanner.ts
145
+ */
146
+ function extractParamsFromPath(fileName) {
147
+ const params = [];
148
+ // Match patterns: [param], [param]?, [...param], [[param]]
149
+ const regex = /\[\[([^\]]+)\]\]|\[(?:\.\.\.)?([^\]]+)\]\??/g;
150
+ let match;
151
+ // biome-ignore lint/suspicious/noAssignInExpressions: standard regex iteration pattern
152
+ while ((match = regex.exec(fileName)) !== null) {
153
+ const fullMatch = match[0];
154
+ // match[1] is for [[param]] syntax, match[2] is for [param] syntax
155
+ const paramName = (match[1] || match[2]).replace("?", "");
156
+ params.push({
157
+ name: paramName,
158
+ isOptional: fullMatch.endsWith("?") || fullMatch.startsWith("[["),
159
+ isCatchAll: fullMatch.startsWith("[..."),
160
+ });
161
+ }
162
+ return params;
163
+ }
164
+ /**
165
+ * Generates the appropriate template for a route file
166
+ */
167
+ function generateRouteTemplate(relativePath) {
168
+ const templateType = getTemplateType(relativePath);
169
+ if (templateType === "layout") {
170
+ return generateLayoutTemplate("stack");
171
+ }
172
+ const params = extractParamsFromPath(relativePath);
173
+ return generateScreenTemplate(relativePath, params);
174
+ }
@@ -8,6 +8,11 @@ export interface WatcherOptions {
8
8
  generatedDir: string;
9
9
  prefixes: string[];
10
10
  verbose: boolean;
11
+ /**
12
+ * Auto-populate new route files with template content
13
+ * @default true
14
+ */
15
+ autoTemplate?: boolean;
11
16
  onRegenerate?: () => void;
12
17
  onError?: (errors: ValidationError[]) => void;
13
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-watcher.d.ts","sourceRoot":"","sources":["../../src/watcher/file-watcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,8BAA8B,CAAC;AAEpF,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CAC9C;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI,CAyFrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
1
+ {"version":3,"file":"file-watcher.d.ts","sourceRoot":"","sources":["../../src/watcher/file-watcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,8BAA8B,CAAC;AAEpF,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CAC9C;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI,CA0GrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
@@ -7,9 +7,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.startRouteWatcher = startRouteWatcher;
8
8
  exports.stopRouteWatcher = stopRouteWatcher;
9
9
  exports.isWatcherRunning = isWatcherRunning;
10
+ const node_fs_1 = require("node:fs");
10
11
  const node_path_1 = require("node:path");
11
12
  const chokidar_1 = require("chokidar");
12
13
  const route_generator_1 = require("../generator/route-generator");
14
+ const route_templates_1 = require("../templates/route-templates");
13
15
  const route_validator_1 = require("../validator/route-validator");
14
16
  let watcherInstance = null;
15
17
  /**
@@ -17,7 +19,7 @@ let watcherInstance = null;
17
19
  * Returns a cleanup function to stop watching
18
20
  */
19
21
  function startRouteWatcher(options) {
20
- const { routesDir, generatedDir, prefixes, verbose, onRegenerate, onError } = options;
22
+ const { routesDir, generatedDir, prefixes, verbose, autoTemplate = true, onRegenerate, onError } = options;
21
23
  // Close existing watcher if any
22
24
  if (watcherInstance) {
23
25
  watcherInstance.close();
@@ -67,8 +69,24 @@ function startRouteWatcher(options) {
67
69
  }, 100);
68
70
  };
69
71
  watcher.on("add", (filePath) => {
72
+ const relativePath = (0, node_path_1.relative)(routesDir, filePath);
70
73
  if (verbose) {
71
- console.log(`[teardown/navigation] File added: ${(0, node_path_1.relative)(routesDir, filePath)}`);
74
+ console.log(`[teardown/navigation] File added: ${relativePath}`);
75
+ }
76
+ // Auto-populate empty files with template content
77
+ if (autoTemplate && (0, route_templates_1.isFileEmpty)(filePath)) {
78
+ try {
79
+ const templateContent = (0, route_templates_1.generateRouteTemplate)(relativePath);
80
+ (0, node_fs_1.writeFileSync)(filePath, templateContent);
81
+ if (verbose) {
82
+ console.log(`[teardown/navigation] Generated template for: ${relativePath}`);
83
+ }
84
+ }
85
+ catch (error) {
86
+ if (verbose) {
87
+ console.error(`[teardown/navigation] Failed to generate template for ${relativePath}:`, error);
88
+ }
89
+ }
72
90
  }
73
91
  regenerate();
74
92
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teardown/navigation-metro",
3
- "version": "2.0.68",
3
+ "version": "2.0.70",
4
4
  "description": "Metro plugin for @teardown/navigation type generation",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@biomejs/biome": "2.3.11",
45
- "@teardown/tsconfig": "2.0.68",
45
+ "@teardown/tsconfig": "2.0.70",
46
46
  "@types/node": "24.10.1",
47
47
  "typescript": "5.9.3"
48
48
  }