@kimesh/router-generator 0.2.8 → 0.2.9

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.mts CHANGED
@@ -417,6 +417,15 @@ interface LayerRouteNode extends RouteNode {
417
417
  */
418
418
  declare function collectLayerRoutes(sources: LayerRouteSource[], config: ResolvedRouterConfig): Promise<LayerRoutesResult>;
419
419
  //#endregion
420
+ //#region src/route-merger.d.ts
421
+ /**
422
+ * Merge app routes with layer routes
423
+ * App routes (priority 0) take precedence over layer routes
424
+ * Layer routes are nested under the host's root layout if one exists
425
+ * If app has a layout route for a path, layer routes become its children
426
+ */
427
+ declare function mergeRoutes(appRoutes: RouteNode[], layerRoutes: RouteNode[], _config?: ResolvedRouterConfig): RouteNode[];
428
+ //#endregion
420
429
  //#region src/layout-resolver.d.ts
421
430
  /**
422
431
  * Resolved layout information
@@ -501,4 +510,113 @@ declare function generateLayoutStructure(chain: LayoutChain): {
501
510
  children?: any[];
502
511
  } | null;
503
512
  //#endregion
504
- export { type ExtendedParsedRoute, type GeneratedOutput, type KimeshRouterConfig, type KimeshRouterPluginOptions, type LayerRouteConfig, type LayerRouteNode, type LayerRouteSource, type LayerRoutesResult, type LayoutChain, LayoutResolver, type ParsedFileName, type ParsedRoute, type ResolvedLayout, type ResolvedRouterConfig, type RouteNode, type RouteNodeType, type RouteParam, RouteScanner, RouteTreeBuilder, type TreeNode, buildGlobPattern, buildRoutePath, buildRouteTree, collectLayerRoutes, createCatchAllParam, createDynamicParam, createEmptyParsedRoute, createScanner, createTreeBuilder, extractDynamicParam, generateLayoutStructure, generateRouteTypes, generateRoutes, isDotNotationRoute, isRootDir, kimeshRouterGenerator, parseRouteFile, processDirectoryPath, processPathSegment, unescapeBrackets };
513
+ //#region src/middleware/types.d.ts
514
+ /**
515
+ * @kimesh/router-generator - Middleware Types (Build-time)
516
+ */
517
+ /**
518
+ * Middleware file metadata discovered during scanning
519
+ */
520
+ interface MiddlewareFile {
521
+ /** Middleware name (without extension and .global suffix) */
522
+ name: string;
523
+ /** Original filename with extension */
524
+ fileName: string;
525
+ /** Absolute path to the middleware file */
526
+ filePath: string;
527
+ /** Whether this is a global middleware (`.global.ts` suffix) */
528
+ isGlobal: boolean;
529
+ /** Optional priority extracted from filename (e.g., `01.auth.global.ts` -> 1) */
530
+ priority?: number;
531
+ /** Source layer name (for multi-layer support) */
532
+ layer?: string;
533
+ }
534
+ /**
535
+ * Middleware scanning options
536
+ */
537
+ interface MiddlewareScanOptions {
538
+ /** Root directory of the project */
539
+ root: string;
540
+ /** Middleware directory path (usually `src/middleware`) */
541
+ middlewareDir: string;
542
+ /** File extensions to scan */
543
+ extensions?: string[];
544
+ /** Ordering strategy for middleware */
545
+ orderStrategy?: "alphabetical" | "explicit" | "none";
546
+ }
547
+ /**
548
+ * Layer middleware configuration
549
+ */
550
+ interface LayerMiddlewareConfig {
551
+ /** Layer name */
552
+ layerName: string;
553
+ /** Layer path */
554
+ layerPath: string;
555
+ /** Middleware directory within the layer */
556
+ middlewareDir: string;
557
+ /** Layer priority (lower = higher priority) */
558
+ priority: number;
559
+ }
560
+ /**
561
+ * Result of middleware scanning
562
+ */
563
+ interface MiddlewareScanResult {
564
+ /** All discovered middleware files */
565
+ middleware: MiddlewareFile[];
566
+ /** Global middleware (sorted by priority/order) */
567
+ globalMiddleware: MiddlewareFile[];
568
+ /** Named middleware (non-global) */
569
+ namedMiddleware: MiddlewareFile[];
570
+ }
571
+ //#endregion
572
+ //#region src/middleware/scanner.d.ts
573
+ /**
574
+ * Scan a single middleware directory
575
+ */
576
+ declare function scanMiddlewareDir(middlewareDir: string, options?: {
577
+ extensions?: string[];
578
+ layer?: string;
579
+ }): Promise<MiddlewareFile[]>;
580
+ /**
581
+ * Scan middleware files from the application
582
+ */
583
+ declare function scanMiddlewareFiles(options: MiddlewareScanOptions): Promise<MiddlewareScanResult>;
584
+ /**
585
+ * Scan middleware from multiple layers and merge them
586
+ * Layer priority determines override behavior (lower = higher priority)
587
+ */
588
+ declare function scanLayerMiddleware(layers: LayerMiddlewareConfig[], options?: {
589
+ extensions?: string[];
590
+ orderStrategy?: "alphabetical" | "explicit" | "none";
591
+ }): Promise<MiddlewareScanResult>;
592
+ /**
593
+ * Create a middleware scanner with configuration
594
+ */
595
+ declare class MiddlewareScanner {
596
+ private options;
597
+ constructor(options: MiddlewareScanOptions);
598
+ /**
599
+ * Scan the configured middleware directory
600
+ */
601
+ scan(): Promise<MiddlewareScanResult>;
602
+ /**
603
+ * Check if middleware directory exists
604
+ */
605
+ exists(): boolean;
606
+ }
607
+ //#endregion
608
+ //#region src/middleware/codegen.d.ts
609
+ /**
610
+ * Generate middleware registry code
611
+ */
612
+ declare function generateMiddlewareRegistry(result: MiddlewareScanResult): string;
613
+ /**
614
+ * Generate middleware type declarations
615
+ */
616
+ declare function generateMiddlewareTypes(result: MiddlewareScanResult): string;
617
+ /**
618
+ * Generate middleware module content for a specific middleware file
619
+ */
620
+ declare function generateMiddlewareModule(file: MiddlewareFile): string;
621
+ //#endregion
622
+ export { type ExtendedParsedRoute, type GeneratedOutput, type KimeshRouterConfig, type KimeshRouterPluginOptions, type LayerMiddlewareConfig, type LayerRouteConfig, type LayerRouteNode, type LayerRouteSource, type LayerRoutesResult, type LayoutChain, LayoutResolver, type MiddlewareFile, type MiddlewareScanOptions, type MiddlewareScanResult, MiddlewareScanner, type ParsedFileName, type ParsedRoute, type ResolvedLayout, type ResolvedRouterConfig, type RouteNode, type RouteNodeType, type RouteParam, RouteScanner, RouteTreeBuilder, type TreeNode, buildGlobPattern, buildRoutePath, buildRouteTree, collectLayerRoutes, createCatchAllParam, createDynamicParam, createEmptyParsedRoute, createScanner, createTreeBuilder, extractDynamicParam, generateLayoutStructure, generateMiddlewareModule, generateMiddlewareRegistry, generateMiddlewareTypes, generateRouteTypes, generateRoutes, isDotNotationRoute, isRootDir, kimeshRouterGenerator, mergeRoutes, parseRouteFile, processDirectoryPath, processPathSegment, scanLayerMiddleware, scanMiddlewareDir, scanMiddlewareFiles, unescapeBrackets };
package/dist/index.mjs CHANGED
@@ -1,11 +1,50 @@
1
1
  import * as path from "pathe";
2
+ import { basename, extname, join } from "pathe";
2
3
  import * as fs from "node:fs";
4
+ import { existsSync } from "node:fs";
3
5
  import { watch } from "chokidar";
4
6
  import fg from "fast-glob";
5
7
  import { parse } from "@vue/compiler-sfc";
6
8
  import { parseSync } from "oxc-parser";
7
9
  import { consola } from "consola";
10
+ import { readdir } from "node:fs/promises";
8
11
 
12
+ //#region rolldown:runtime
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
+ var __getOwnPropNames = Object.getOwnPropertyNames;
16
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
17
+ var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
+ var __exportAll = (all, symbols) => {
19
+ let target = {};
20
+ for (var name in all) {
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true
24
+ });
25
+ }
26
+ if (symbols) {
27
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
28
+ }
29
+ return target;
30
+ };
31
+ var __copyProps = (to, from, except, desc) => {
32
+ if (from && typeof from === "object" || typeof from === "function") {
33
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
34
+ key = keys[i];
35
+ if (!__hasOwnProp.call(to, key) && key !== except) {
36
+ __defProp(to, key, {
37
+ get: ((k) => from[k]).bind(null, key),
38
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
39
+ });
40
+ }
41
+ }
42
+ }
43
+ return to;
44
+ };
45
+ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
+
47
+ //#endregion
9
48
  //#region src/parser.ts
10
49
  /**
11
50
  * @kimesh/router-generator - OXC-Powered Route Parser
@@ -1637,6 +1676,83 @@ function shouldBeLazy(filePath, config) {
1637
1676
  return importMode === "async";
1638
1677
  }
1639
1678
 
1679
+ //#endregion
1680
+ //#region src/route-merger.ts
1681
+ var route_merger_exports = /* @__PURE__ */ __exportAll({ mergeRoutes: () => mergeRoutes });
1682
+ /**
1683
+ * Merge app routes with layer routes
1684
+ * App routes (priority 0) take precedence over layer routes
1685
+ * Layer routes are nested under the host's root layout if one exists
1686
+ * If app has a layout route for a path, layer routes become its children
1687
+ */
1688
+ function mergeRoutes(appRoutes, layerRoutes, _config) {
1689
+ const rootLayout = findRootLayout(appRoutes);
1690
+ if (rootLayout && rootLayout.children) return mergeWithRootLayout(appRoutes, layerRoutes, rootLayout);
1691
+ return mergeWithoutRootLayout(appRoutes, layerRoutes);
1692
+ }
1693
+ function findRootLayout(routes) {
1694
+ return routes.find((r) => r.routePath === "/" && r.type === "layout") || null;
1695
+ }
1696
+ function mergeWithRootLayout(appRoutes, layerRoutes, rootLayout) {
1697
+ const layoutRoutesByPath = buildLayoutRoutesMap(rootLayout.children);
1698
+ for (const layerRoute of layerRoutes) {
1699
+ const relativePath = normalizeRoutePath(layerRoute.routePath);
1700
+ const hostLayoutRoute = layoutRoutesByPath.get(relativePath);
1701
+ if (hostLayoutRoute) nestLayerUnderHost(layerRoute, hostLayoutRoute);
1702
+ else addLayerAsSibling(layerRoute, relativePath, rootLayout, layoutRoutesByPath);
1703
+ }
1704
+ sortRouteChildren(rootLayout.children);
1705
+ return appRoutes;
1706
+ }
1707
+ function buildLayoutRoutesMap(children) {
1708
+ const map = /* @__PURE__ */ new Map();
1709
+ for (const child of children) if (child.routePath && !child.routePath.includes(":")) {
1710
+ const normalizedPath = normalizeRoutePath(child.routePath);
1711
+ map.set(normalizedPath, child);
1712
+ }
1713
+ return map;
1714
+ }
1715
+ function normalizeRoutePath(routePath) {
1716
+ return routePath.startsWith("/") ? routePath.slice(1) : routePath;
1717
+ }
1718
+ function nestLayerUnderHost(layerRoute, hostLayoutRoute) {
1719
+ hostLayoutRoute.children = hostLayoutRoute.children || [];
1720
+ hostLayoutRoute.type = "layout";
1721
+ const layerWrapper = {
1722
+ ...layerRoute,
1723
+ routePath: "",
1724
+ parent: hostLayoutRoute
1725
+ };
1726
+ hostLayoutRoute.children.push(layerWrapper);
1727
+ }
1728
+ function addLayerAsSibling(layerRoute, relativePath, rootLayout, layoutRoutesByPath) {
1729
+ const nestedRoute = {
1730
+ ...layerRoute,
1731
+ routePath: relativePath,
1732
+ parent: rootLayout
1733
+ };
1734
+ rootLayout.children.push(nestedRoute);
1735
+ layoutRoutesByPath.set(relativePath, nestedRoute);
1736
+ }
1737
+ function sortRouteChildren(children) {
1738
+ children.sort((a, b) => {
1739
+ if (a.routePath === "") return -1;
1740
+ if (b.routePath === "") return 1;
1741
+ return a.routePath.localeCompare(b.routePath);
1742
+ });
1743
+ }
1744
+ function mergeWithoutRootLayout(appRoutes, layerRoutes) {
1745
+ const merged = [...appRoutes];
1746
+ const usedPaths = new Set(appRoutes.map((r) => r.routePath));
1747
+ for (const layerRoute of layerRoutes) if (!usedPaths.has(layerRoute.routePath)) {
1748
+ merged.push(layerRoute);
1749
+ usedPaths.add(layerRoute.routePath);
1750
+ }
1751
+ merged.sort((a, b) => a.routePath.localeCompare(b.routePath));
1752
+ return merged;
1753
+ }
1754
+ var init_route_merger = __esmMin((() => {}));
1755
+
1640
1756
  //#endregion
1641
1757
  //#region src/plugin.ts
1642
1758
  const VIRTUAL_ROUTES_ID = "\0virtual:kimesh-routes";
@@ -1743,7 +1859,7 @@ function kimeshRouterGenerator(options = {}) {
1743
1859
  priority: l.priority
1744
1860
  })), config);
1745
1861
  log("Collected layer routes:", layerResult.routes.length);
1746
- routes = mergeRoutes(appRoutes, layerResult.routes, config);
1862
+ routes = mergeRoutes$1(appRoutes, layerResult.routes, config);
1747
1863
  } else routes = appRoutes;
1748
1864
  log("Final merged routes:", routes.length, routes.map((r) => r.routePath));
1749
1865
  await writeGeneratedFiles();
@@ -1799,75 +1915,14 @@ function kimeshRouterGenerator(options = {}) {
1799
1915
  * Layer routes are nested under the host's root layout if one exists
1800
1916
  * If app has a layout route for a path, layer routes become its children
1801
1917
  */
1802
- function mergeRoutes(appRoutes, layerRoutes, _config) {
1803
- const rootLayout = findRootLayout(appRoutes);
1804
- if (rootLayout && rootLayout.children) return mergeWithRootLayout(appRoutes, layerRoutes, rootLayout);
1805
- return mergeWithoutRootLayout(appRoutes, layerRoutes);
1806
- }
1807
- function findRootLayout(routes) {
1808
- return routes.find((r) => r.routePath === "/" && r.type === "layout") || null;
1809
- }
1810
- function mergeWithRootLayout(appRoutes, layerRoutes, rootLayout) {
1811
- const layoutRoutesByPath = buildLayoutRoutesMap(rootLayout.children);
1812
- for (const layerRoute of layerRoutes) {
1813
- const relativePath = normalizeRoutePath(layerRoute.routePath);
1814
- const hostLayoutRoute = layoutRoutesByPath.get(relativePath);
1815
- if (hostLayoutRoute) nestLayerUnderHost(layerRoute, hostLayoutRoute);
1816
- else addLayerAsSibling(layerRoute, relativePath, rootLayout, layoutRoutesByPath);
1817
- }
1818
- sortRouteChildren(rootLayout.children);
1819
- return appRoutes;
1820
- }
1821
- function buildLayoutRoutesMap(children) {
1822
- const map = /* @__PURE__ */ new Map();
1823
- for (const child of children) if (child.routePath && !child.routePath.includes(":")) {
1824
- const normalizedPath = normalizeRoutePath(child.routePath);
1825
- map.set(normalizedPath, child);
1826
- }
1827
- return map;
1828
- }
1829
- function normalizeRoutePath(routePath) {
1830
- return routePath.startsWith("/") ? routePath.slice(1) : routePath;
1831
- }
1832
- function nestLayerUnderHost(layerRoute, hostLayoutRoute) {
1833
- hostLayoutRoute.children = hostLayoutRoute.children || [];
1834
- hostLayoutRoute.type = "layout";
1835
- const layerWrapper = {
1836
- ...layerRoute,
1837
- routePath: "",
1838
- parent: hostLayoutRoute
1839
- };
1840
- hostLayoutRoute.children.push(layerWrapper);
1841
- }
1842
- function addLayerAsSibling(layerRoute, relativePath, rootLayout, layoutRoutesByPath) {
1843
- const nestedRoute = {
1844
- ...layerRoute,
1845
- routePath: relativePath,
1846
- parent: rootLayout
1847
- };
1848
- rootLayout.children.push(nestedRoute);
1849
- layoutRoutesByPath.set(relativePath, nestedRoute);
1850
- }
1851
- function sortRouteChildren(children) {
1852
- children.sort((a, b) => {
1853
- if (a.routePath === "") return -1;
1854
- if (b.routePath === "") return 1;
1855
- return a.routePath.localeCompare(b.routePath);
1856
- });
1857
- }
1858
- function mergeWithoutRootLayout(appRoutes, layerRoutes) {
1859
- const merged = [...appRoutes];
1860
- const usedPaths = new Set(appRoutes.map((r) => r.routePath));
1861
- for (const layerRoute of layerRoutes) if (!usedPaths.has(layerRoute.routePath)) {
1862
- merged.push(layerRoute);
1863
- usedPaths.add(layerRoute.routePath);
1864
- }
1865
- merged.sort((a, b) => a.routePath.localeCompare(b.routePath));
1866
- return merged;
1918
+ function mergeRoutes$1(appRoutes, layerRoutes, _config) {
1919
+ const { mergeRoutes: mergeRoutesImpl } = (init_route_merger(), __toCommonJS(route_merger_exports));
1920
+ return mergeRoutesImpl(appRoutes, layerRoutes, _config);
1867
1921
  }
1868
1922
 
1869
1923
  //#endregion
1870
1924
  //#region src/layout-resolver.ts
1925
+ init_route_merger();
1871
1926
  /**
1872
1927
  * @kimesh/router-generator - Layout Resolver
1873
1928
  *
@@ -2025,4 +2080,283 @@ function generateLayoutStructure(chain) {
2025
2080
  }
2026
2081
 
2027
2082
  //#endregion
2028
- export { LayoutResolver, RouteScanner, RouteTreeBuilder, buildGlobPattern, buildRoutePath, buildRouteTree, collectLayerRoutes, createCatchAllParam, createDynamicParam, createEmptyParsedRoute, createScanner, createTreeBuilder, extractDynamicParam, generateLayoutStructure, generateRouteTypes, generateRoutes, isDotNotationRoute, isRootDir, kimeshRouterGenerator, parseRouteFile, processDirectoryPath, processPathSegment, unescapeBrackets };
2083
+ //#region src/middleware/scanner.ts
2084
+ /**
2085
+ * @kimesh/router-generator - Middleware Scanner
2086
+ *
2087
+ * Scans middleware directories for middleware files following conventions:
2088
+ * - `*.ts` or `*.js` files in `src/middleware/`
2089
+ * - `.global.ts` suffix for global middleware
2090
+ * - Numeric prefix for priority (e.g., `01.auth.global.ts`)
2091
+ */
2092
+ const DEFAULT_EXTENSIONS = [
2093
+ ".ts",
2094
+ ".js",
2095
+ ".mjs",
2096
+ ".cjs"
2097
+ ];
2098
+ /**
2099
+ * Extract priority from filename
2100
+ * Supports format: "01.auth.global.ts" -> priority 1
2101
+ */
2102
+ function extractPriority(name) {
2103
+ const match = name.match(/^(\d+)\./);
2104
+ return match ? parseInt(match[1], 10) : void 0;
2105
+ }
2106
+ /**
2107
+ * Parse middleware filename into metadata
2108
+ */
2109
+ function parseMiddlewareFile(filePath, fileName, layer) {
2110
+ const nameWithoutExt = basename(fileName, extname(fileName));
2111
+ const isGlobal = nameWithoutExt.endsWith(".global");
2112
+ const nameWithoutGlobal = isGlobal ? nameWithoutExt.slice(0, -7) : nameWithoutExt;
2113
+ const priority = extractPriority(nameWithoutGlobal);
2114
+ return {
2115
+ name: priority !== void 0 ? nameWithoutGlobal.replace(/^\d+\./, "") : nameWithoutGlobal,
2116
+ fileName,
2117
+ filePath,
2118
+ isGlobal,
2119
+ priority,
2120
+ layer
2121
+ };
2122
+ }
2123
+ /**
2124
+ * Scan a single middleware directory
2125
+ */
2126
+ async function scanMiddlewareDir(middlewareDir, options = {}) {
2127
+ const extensions = options.extensions || DEFAULT_EXTENSIONS;
2128
+ const middlewareFiles = [];
2129
+ if (!existsSync(middlewareDir)) return [];
2130
+ try {
2131
+ const files = await readdir(middlewareDir, { withFileTypes: true });
2132
+ for (const file of files) {
2133
+ if (!file.isFile()) continue;
2134
+ const ext = extname(file.name);
2135
+ if (!extensions.includes(ext)) continue;
2136
+ const parsed = parseMiddlewareFile(join(middlewareDir, file.name), file.name, options.layer);
2137
+ middlewareFiles.push(parsed);
2138
+ }
2139
+ } catch (error) {
2140
+ console.warn(`[Kimesh] Could not scan middleware directory: ${middlewareDir}`, error);
2141
+ }
2142
+ return middlewareFiles;
2143
+ }
2144
+ /**
2145
+ * Sort middleware files according to the specified strategy
2146
+ */
2147
+ function sortMiddleware(files, strategy) {
2148
+ if (strategy === "none") return files;
2149
+ return [...files].sort((a, b) => {
2150
+ if (a.isGlobal !== b.isGlobal) return a.isGlobal ? -1 : 1;
2151
+ if (strategy === "explicit") {
2152
+ const aPriority = a.priority ?? Infinity;
2153
+ const bPriority = b.priority ?? Infinity;
2154
+ if (aPriority !== bPriority) return aPriority - bPriority;
2155
+ }
2156
+ return a.name.localeCompare(b.name);
2157
+ });
2158
+ }
2159
+ /**
2160
+ * Scan middleware files from the application
2161
+ */
2162
+ async function scanMiddlewareFiles(options) {
2163
+ const strategy = options.orderStrategy || "alphabetical";
2164
+ const extensions = options.extensions || DEFAULT_EXTENSIONS;
2165
+ const sorted = sortMiddleware(await scanMiddlewareDir(options.middlewareDir, { extensions }), strategy);
2166
+ return {
2167
+ middleware: sorted,
2168
+ globalMiddleware: sorted.filter((m) => m.isGlobal),
2169
+ namedMiddleware: sorted.filter((m) => !m.isGlobal)
2170
+ };
2171
+ }
2172
+ /**
2173
+ * Scan middleware from multiple layers and merge them
2174
+ * Layer priority determines override behavior (lower = higher priority)
2175
+ */
2176
+ async function scanLayerMiddleware(layers, options = {}) {
2177
+ const strategy = options.orderStrategy || "alphabetical";
2178
+ const extensions = options.extensions || DEFAULT_EXTENSIONS;
2179
+ const allMiddleware = [];
2180
+ const seenNames = /* @__PURE__ */ new Map();
2181
+ const sortedLayers = [...layers].sort((a, b) => b.priority - a.priority);
2182
+ for (const layer of sortedLayers) {
2183
+ const files = await scanMiddlewareDir(layer.middlewareDir, {
2184
+ extensions,
2185
+ layer: layer.layerName
2186
+ });
2187
+ for (const file of files) {
2188
+ const key = `${file.name}:${file.isGlobal}`;
2189
+ seenNames.set(key, file);
2190
+ }
2191
+ }
2192
+ allMiddleware.push(...seenNames.values());
2193
+ const sorted = sortMiddleware(allMiddleware, strategy);
2194
+ return {
2195
+ middleware: sorted,
2196
+ globalMiddleware: sorted.filter((m) => m.isGlobal),
2197
+ namedMiddleware: sorted.filter((m) => !m.isGlobal)
2198
+ };
2199
+ }
2200
+ /**
2201
+ * Create a middleware scanner with configuration
2202
+ */
2203
+ var MiddlewareScanner = class {
2204
+ options;
2205
+ constructor(options) {
2206
+ this.options = {
2207
+ extensions: DEFAULT_EXTENSIONS,
2208
+ orderStrategy: "alphabetical",
2209
+ ...options
2210
+ };
2211
+ }
2212
+ /**
2213
+ * Scan the configured middleware directory
2214
+ */
2215
+ async scan() {
2216
+ return scanMiddlewareFiles(this.options);
2217
+ }
2218
+ /**
2219
+ * Check if middleware directory exists
2220
+ */
2221
+ exists() {
2222
+ return existsSync(this.options.middlewareDir);
2223
+ }
2224
+ };
2225
+
2226
+ //#endregion
2227
+ //#region src/middleware/codegen.ts
2228
+ /**
2229
+ * Generate a safe variable name from middleware name
2230
+ */
2231
+ function toSafeVariableName(name) {
2232
+ return name.replace(/[^a-zA-Z0-9_$]/g, "_");
2233
+ }
2234
+ /**
2235
+ * Normalize file path for import (forward slashes, no backslashes, no .ts extension)
2236
+ */
2237
+ function normalizeImportPath(filePath) {
2238
+ return filePath.replace(/\\/g, "/").replace(/\.ts$/, "");
2239
+ }
2240
+ /**
2241
+ * Generate middleware registry code
2242
+ */
2243
+ function generateMiddlewareRegistry(result) {
2244
+ const { globalMiddleware, namedMiddleware, middleware } = result;
2245
+ if (middleware.length === 0) return generateEmptyRegistry();
2246
+ const lines = [
2247
+ "// Auto-generated by @kimesh/router-generator",
2248
+ "// DO NOT EDIT - This file is regenerated when middleware files change",
2249
+ ""
2250
+ ];
2251
+ if (globalMiddleware.length > 0) {
2252
+ lines.push("// Global middleware imports (eager loading)");
2253
+ for (const mw of globalMiddleware) {
2254
+ const varName = `global_${toSafeVariableName(mw.name)}`;
2255
+ lines.push(`import ${varName} from '${normalizeImportPath(mw.filePath)}';`);
2256
+ }
2257
+ lines.push("");
2258
+ }
2259
+ lines.push("// Global middleware (executed on every navigation)");
2260
+ if (globalMiddleware.length > 0) {
2261
+ const globalNames = globalMiddleware.map((mw) => `global_${toSafeVariableName(mw.name)}`);
2262
+ lines.push(`export const globalMiddleware = [${globalNames.join(", ")}];`);
2263
+ } else lines.push("export const globalMiddleware = [];");
2264
+ lines.push("");
2265
+ lines.push("// Named middleware (lazy loaded when needed)");
2266
+ if (namedMiddleware.length > 0) {
2267
+ const namedEntries = namedMiddleware.map((mw) => {
2268
+ const importPath = normalizeImportPath(mw.filePath);
2269
+ return ` '${mw.name}': () => import('${importPath}').then(m => m.default || m)`;
2270
+ });
2271
+ lines.push(`export const namedMiddleware = {`);
2272
+ lines.push(namedEntries.join(",\n"));
2273
+ lines.push("};");
2274
+ } else lines.push("export const namedMiddleware = {};");
2275
+ lines.push("");
2276
+ const allNames = middleware.map((m) => `'${m.name}'`);
2277
+ lines.push("// Middleware names (for type safety)");
2278
+ lines.push(`export const middlewareNames = [${allNames.join(", ")}] as const;`);
2279
+ lines.push("export type MiddlewareName = typeof middlewareNames[number];");
2280
+ lines.push("");
2281
+ lines.push("// Helper functions");
2282
+ lines.push(`export function getGlobalMiddleware() {`);
2283
+ lines.push(` return globalMiddleware;`);
2284
+ lines.push(`}`);
2285
+ lines.push("");
2286
+ lines.push(`export function getNamedMiddleware(name: string) {`);
2287
+ lines.push(` return namedMiddleware[name as keyof typeof namedMiddleware];`);
2288
+ lines.push(`}`);
2289
+ lines.push("");
2290
+ lines.push(`export function hasMiddleware(name: string): boolean {`);
2291
+ lines.push(` return middlewareNames.includes(name as MiddlewareName);`);
2292
+ lines.push(`}`);
2293
+ return lines.join("\n");
2294
+ }
2295
+ /**
2296
+ * Generate empty middleware registry
2297
+ */
2298
+ function generateEmptyRegistry() {
2299
+ return `// Auto-generated by @kimesh/router-generator
2300
+ // No middleware files found
2301
+
2302
+ export const globalMiddleware = [];
2303
+ export const namedMiddleware = {};
2304
+ export const middlewareNames = [] as const;
2305
+ export type MiddlewareName = never;
2306
+
2307
+ export function getGlobalMiddleware() {
2308
+ return [];
2309
+ }
2310
+
2311
+ export function getNamedMiddleware(_name: string) {
2312
+ return undefined;
2313
+ }
2314
+
2315
+ export function hasMiddleware(_name: string): boolean {
2316
+ return false;
2317
+ }
2318
+ `;
2319
+ }
2320
+ /**
2321
+ * Generate middleware type declarations
2322
+ */
2323
+ function generateMiddlewareTypes(result) {
2324
+ const { middleware } = result;
2325
+ const lines = [
2326
+ "// Auto-generated middleware type declarations",
2327
+ "// DO NOT EDIT - This file is regenerated when middleware files change",
2328
+ "",
2329
+ "import type { RouteMiddleware } from \"@kimesh/router-runtime\";",
2330
+ ""
2331
+ ];
2332
+ if (middleware.length > 0) {
2333
+ const names = middleware.map((m) => `'${m.name}'`).join(" | ");
2334
+ lines.push(`export type KnownMiddleware = ${names};`);
2335
+ } else lines.push("export type KnownMiddleware = never;");
2336
+ lines.push("");
2337
+ lines.push("declare module \"vue-router\" {");
2338
+ lines.push(" interface RouteMeta {");
2339
+ lines.push(" middleware?: KnownMiddleware | KnownMiddleware[] | RouteMiddleware | RouteMiddleware[];");
2340
+ lines.push(" }");
2341
+ lines.push("}");
2342
+ lines.push("");
2343
+ lines.push("declare module \"@kimesh/router-runtime\" {");
2344
+ lines.push(" interface KimeshMiddlewareNames {");
2345
+ for (const mw of middleware) lines.push(` '${mw.name}': true;`);
2346
+ lines.push(" }");
2347
+ lines.push("}");
2348
+ return lines.join("\n");
2349
+ }
2350
+ /**
2351
+ * Generate middleware module content for a specific middleware file
2352
+ */
2353
+ function generateMiddlewareModule(file) {
2354
+ return `// Middleware: ${file.name}
2355
+ // Auto-generated export wrapper
2356
+
2357
+ export { default } from '${normalizeImportPath(file.filePath)}';
2358
+ `;
2359
+ }
2360
+
2361
+ //#endregion
2362
+ export { LayoutResolver, MiddlewareScanner, RouteScanner, RouteTreeBuilder, buildGlobPattern, buildRoutePath, buildRouteTree, collectLayerRoutes, createCatchAllParam, createDynamicParam, createEmptyParsedRoute, createScanner, createTreeBuilder, extractDynamicParam, generateLayoutStructure, generateMiddlewareModule, generateMiddlewareRegistry, generateMiddlewareTypes, generateRouteTypes, generateRoutes, isDotNotationRoute, isRootDir, kimeshRouterGenerator, mergeRoutes, parseRouteFile, processDirectoryPath, processPathSegment, scanLayerMiddleware, scanMiddlewareDir, scanMiddlewareFiles, unescapeBrackets };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kimesh/router-generator",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "File-based route generator for Kimesh",
5
5
  "type": "module",
6
6
  "repository": {