@lytjs/router-fs 6.5.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/README.md +80 -0
- package/dist/index.cjs +173 -0
- package/dist/index.d.cts +74 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.mjs +146 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @lytjs/router-fs
|
|
2
|
+
|
|
3
|
+
LytJS 文件系统路由引擎,自动扫描文件系统生成路由配置。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @lytjs/router-fs
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 快速开始
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createFileSystemRouter } from '@lytjs/router-fs';
|
|
15
|
+
|
|
16
|
+
const router = createFileSystemRouter({
|
|
17
|
+
pagesDir: './src/pages',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// 添加路由
|
|
21
|
+
router.addRoute({
|
|
22
|
+
path: '/about',
|
|
23
|
+
componentPath: './src/pages/about.ts',
|
|
24
|
+
isDynamic: false,
|
|
25
|
+
isNested: false,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 匹配路由
|
|
29
|
+
const match = router.match('/about');
|
|
30
|
+
console.log(match); // { path: '/about', ... }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 特性
|
|
34
|
+
|
|
35
|
+
- 基于文件系统的自动路由生成
|
|
36
|
+
- 支持动态路由参数
|
|
37
|
+
- 支持嵌套路由
|
|
38
|
+
- 零外部依赖
|
|
39
|
+
|
|
40
|
+
## API
|
|
41
|
+
|
|
42
|
+
### createFileSystemRouter(options)
|
|
43
|
+
|
|
44
|
+
创建文件系统路由引擎实例。
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { createFileSystemRouter } from '@lytjs/router-fs';
|
|
48
|
+
|
|
49
|
+
const router = createFileSystemRouter({
|
|
50
|
+
pagesDir: './src/pages',
|
|
51
|
+
basePath: '/',
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### router.addRoute(route)
|
|
56
|
+
|
|
57
|
+
添加路由。
|
|
58
|
+
|
|
59
|
+
### router.match(path)
|
|
60
|
+
|
|
61
|
+
匹配路由。
|
|
62
|
+
|
|
63
|
+
### router.getRoutes()
|
|
64
|
+
|
|
65
|
+
获取所有路由。
|
|
66
|
+
|
|
67
|
+
## 文件结构约定
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
src/
|
|
71
|
+
└── pages/
|
|
72
|
+
├── index.ts # /
|
|
73
|
+
├── about.ts # /about
|
|
74
|
+
└── user/
|
|
75
|
+
└── [id].ts # /user/:id
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 许可证
|
|
79
|
+
|
|
80
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createFileSystemRouter: () => createFileSystemRouter
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/utils.ts
|
|
28
|
+
var import_fs = require("fs");
|
|
29
|
+
var import_path = require("path");
|
|
30
|
+
function isDirectory(path) {
|
|
31
|
+
return (0, import_fs.existsSync)(path) && (0, import_fs.statSync)(path).isDirectory();
|
|
32
|
+
}
|
|
33
|
+
function isFile(path) {
|
|
34
|
+
return (0, import_fs.existsSync)(path) && (0, import_fs.statSync)(path).isFile();
|
|
35
|
+
}
|
|
36
|
+
function filePathToRoutePath(filePath, baseDir, extensions) {
|
|
37
|
+
let normalized = (0, import_path.normalize)((0, import_path.relative)(baseDir, filePath));
|
|
38
|
+
for (const ext of extensions) {
|
|
39
|
+
if (normalized.endsWith(ext)) {
|
|
40
|
+
normalized = normalized.slice(0, -ext.length);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
normalized = normalized.replace(/\\/g, "/");
|
|
45
|
+
if (normalized.endsWith("/index")) {
|
|
46
|
+
normalized = normalized.slice(0, -6);
|
|
47
|
+
} else if (normalized === "index") {
|
|
48
|
+
normalized = "";
|
|
49
|
+
}
|
|
50
|
+
normalized = normalized.replace(/\[(\w+)\]/g, ":$1");
|
|
51
|
+
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
52
|
+
}
|
|
53
|
+
function extractDynamicParams(routePath) {
|
|
54
|
+
const matches = routePath.match(/:(\w+)/g);
|
|
55
|
+
return matches ? matches.map((m) => m.slice(1)) : [];
|
|
56
|
+
}
|
|
57
|
+
function scanDirectory(dir, baseDir, extensions, ignorePatterns) {
|
|
58
|
+
const routes = [];
|
|
59
|
+
if (!isDirectory(dir)) return routes;
|
|
60
|
+
const files = (0, import_fs.readdirSync)(dir);
|
|
61
|
+
for (const file of files) {
|
|
62
|
+
const fullPath = (0, import_path.join)(dir, file);
|
|
63
|
+
const relativePath = (0, import_path.relative)(baseDir, fullPath);
|
|
64
|
+
if (ignorePatterns.some((pattern) => {
|
|
65
|
+
if (relativePath.includes(pattern)) return true;
|
|
66
|
+
return file.includes(pattern);
|
|
67
|
+
})) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (isDirectory(fullPath)) {
|
|
71
|
+
routes.push(...scanDirectory(fullPath, baseDir, extensions, ignorePatterns));
|
|
72
|
+
} else if (isFile(fullPath)) {
|
|
73
|
+
const ext = extensions.find((e) => file.endsWith(e));
|
|
74
|
+
if (ext) {
|
|
75
|
+
const routePath = filePathToRoutePath(fullPath, baseDir, extensions);
|
|
76
|
+
const params = extractDynamicParams(routePath);
|
|
77
|
+
routes.push({
|
|
78
|
+
path: routePath,
|
|
79
|
+
componentPath: fullPath,
|
|
80
|
+
isDynamic: params.length > 0,
|
|
81
|
+
params,
|
|
82
|
+
isNested: routePath.split("/").length > 2
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return routes;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/index.ts
|
|
91
|
+
var DEFAULT_OPTIONS = {
|
|
92
|
+
pagesDir: "src/pages",
|
|
93
|
+
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
94
|
+
layoutPattern: "_layout",
|
|
95
|
+
ignorePatterns: ["node_modules", ".git", "dist"],
|
|
96
|
+
strictMode: false
|
|
97
|
+
};
|
|
98
|
+
function createFileSystemRouter(options) {
|
|
99
|
+
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
100
|
+
let routes = [];
|
|
101
|
+
async function refresh() {
|
|
102
|
+
routes = scanDirectory(
|
|
103
|
+
config.pagesDir,
|
|
104
|
+
config.pagesDir,
|
|
105
|
+
config.extensions,
|
|
106
|
+
config.ignorePatterns
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
function match(path) {
|
|
110
|
+
for (const route of routes) {
|
|
111
|
+
if (route.path === path) {
|
|
112
|
+
return {
|
|
113
|
+
route,
|
|
114
|
+
params: {},
|
|
115
|
+
path
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const pathSegments = path.split("/").filter(Boolean);
|
|
120
|
+
for (const route of routes) {
|
|
121
|
+
const routeSegments = route.path.split("/").filter(Boolean);
|
|
122
|
+
if (routeSegments.length !== pathSegments.length) continue;
|
|
123
|
+
const params = {};
|
|
124
|
+
let match2 = true;
|
|
125
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
126
|
+
const routeSeg = routeSegments[i];
|
|
127
|
+
const pathSeg = pathSegments[i];
|
|
128
|
+
if (!routeSeg || !pathSeg) continue;
|
|
129
|
+
if (routeSeg.startsWith(":")) {
|
|
130
|
+
params[routeSeg.slice(1)] = pathSeg;
|
|
131
|
+
} else if (routeSeg !== pathSeg) {
|
|
132
|
+
match2 = false;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (match2) {
|
|
137
|
+
return {
|
|
138
|
+
route,
|
|
139
|
+
params,
|
|
140
|
+
path
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
function getRoutes() {
|
|
147
|
+
return [...routes];
|
|
148
|
+
}
|
|
149
|
+
function addRoute(route) {
|
|
150
|
+
routes.push(route);
|
|
151
|
+
}
|
|
152
|
+
function removeRoute(path) {
|
|
153
|
+
routes = routes.filter((r) => r.path !== path);
|
|
154
|
+
}
|
|
155
|
+
function clearRoutes() {
|
|
156
|
+
routes = [];
|
|
157
|
+
}
|
|
158
|
+
refresh().catch((err) => {
|
|
159
|
+
console.warn("Failed to scan routes:", err);
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
getRoutes,
|
|
163
|
+
match,
|
|
164
|
+
addRoute,
|
|
165
|
+
removeRoute,
|
|
166
|
+
clearRoutes,
|
|
167
|
+
refresh
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
171
|
+
0 && (module.exports = {
|
|
172
|
+
createFileSystemRouter
|
|
173
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lytjs/router-fs - 类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 路由配置接口 */
|
|
5
|
+
interface RouteConfig {
|
|
6
|
+
/** 路由路径 */
|
|
7
|
+
path: string;
|
|
8
|
+
/** 路由名称 */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** 组件路径 */
|
|
11
|
+
componentPath: string;
|
|
12
|
+
/** 是否为动态路由 */
|
|
13
|
+
isDynamic: boolean;
|
|
14
|
+
/** 动态路由参数名 */
|
|
15
|
+
params?: string[];
|
|
16
|
+
/** 是否为嵌套路由 */
|
|
17
|
+
isNested: boolean;
|
|
18
|
+
/** 子路由 */
|
|
19
|
+
children?: RouteConfig[];
|
|
20
|
+
/** 布局路径 */
|
|
21
|
+
layoutPath?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 文件系统路由配置选项 */
|
|
24
|
+
interface FileSystemRouterOptions {
|
|
25
|
+
/** 页面目录路径 */
|
|
26
|
+
pagesDir: string;
|
|
27
|
+
/** 页面文件扩展名 */
|
|
28
|
+
extensions?: string[];
|
|
29
|
+
/** 布局文件名称模式 */
|
|
30
|
+
layoutPattern?: string;
|
|
31
|
+
/** 忽略文件模式 */
|
|
32
|
+
ignorePatterns?: string[];
|
|
33
|
+
/** 是否启用严格模式 */
|
|
34
|
+
strictMode?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** 路由匹配结果 */
|
|
37
|
+
interface RouteMatch {
|
|
38
|
+
/** 匹配的路由配置 */
|
|
39
|
+
route: RouteConfig;
|
|
40
|
+
/** 路由参数 */
|
|
41
|
+
params: Record<string, string>;
|
|
42
|
+
/** 路由路径 */
|
|
43
|
+
path: string;
|
|
44
|
+
}
|
|
45
|
+
/** 路由管理器接口 */
|
|
46
|
+
interface FileSystemRouter {
|
|
47
|
+
/** 获取路由配置列表 */
|
|
48
|
+
getRoutes(): RouteConfig[];
|
|
49
|
+
/** 匹配路径 */
|
|
50
|
+
match(path: string): RouteMatch | null;
|
|
51
|
+
/** 添加路由 */
|
|
52
|
+
addRoute(route: RouteConfig): void;
|
|
53
|
+
/** 移除路由 */
|
|
54
|
+
removeRoute(path: string): void;
|
|
55
|
+
/** 清除所有路由 */
|
|
56
|
+
clearRoutes(): void;
|
|
57
|
+
/** 重新扫描文件系统 */
|
|
58
|
+
refresh(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @lytjs/router-fs
|
|
63
|
+
*
|
|
64
|
+
* LytJS File-System Router Engine
|
|
65
|
+
*
|
|
66
|
+
* @packageDocumentation
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 创建文件系统路由管理器
|
|
71
|
+
*/
|
|
72
|
+
declare function createFileSystemRouter(options?: FileSystemRouterOptions): FileSystemRouter;
|
|
73
|
+
|
|
74
|
+
export { type FileSystemRouter, type FileSystemRouterOptions, type RouteConfig, type RouteMatch, createFileSystemRouter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lytjs/router-fs - 类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 路由配置接口 */
|
|
5
|
+
interface RouteConfig {
|
|
6
|
+
/** 路由路径 */
|
|
7
|
+
path: string;
|
|
8
|
+
/** 路由名称 */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** 组件路径 */
|
|
11
|
+
componentPath: string;
|
|
12
|
+
/** 是否为动态路由 */
|
|
13
|
+
isDynamic: boolean;
|
|
14
|
+
/** 动态路由参数名 */
|
|
15
|
+
params?: string[];
|
|
16
|
+
/** 是否为嵌套路由 */
|
|
17
|
+
isNested: boolean;
|
|
18
|
+
/** 子路由 */
|
|
19
|
+
children?: RouteConfig[];
|
|
20
|
+
/** 布局路径 */
|
|
21
|
+
layoutPath?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 文件系统路由配置选项 */
|
|
24
|
+
interface FileSystemRouterOptions {
|
|
25
|
+
/** 页面目录路径 */
|
|
26
|
+
pagesDir: string;
|
|
27
|
+
/** 页面文件扩展名 */
|
|
28
|
+
extensions?: string[];
|
|
29
|
+
/** 布局文件名称模式 */
|
|
30
|
+
layoutPattern?: string;
|
|
31
|
+
/** 忽略文件模式 */
|
|
32
|
+
ignorePatterns?: string[];
|
|
33
|
+
/** 是否启用严格模式 */
|
|
34
|
+
strictMode?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** 路由匹配结果 */
|
|
37
|
+
interface RouteMatch {
|
|
38
|
+
/** 匹配的路由配置 */
|
|
39
|
+
route: RouteConfig;
|
|
40
|
+
/** 路由参数 */
|
|
41
|
+
params: Record<string, string>;
|
|
42
|
+
/** 路由路径 */
|
|
43
|
+
path: string;
|
|
44
|
+
}
|
|
45
|
+
/** 路由管理器接口 */
|
|
46
|
+
interface FileSystemRouter {
|
|
47
|
+
/** 获取路由配置列表 */
|
|
48
|
+
getRoutes(): RouteConfig[];
|
|
49
|
+
/** 匹配路径 */
|
|
50
|
+
match(path: string): RouteMatch | null;
|
|
51
|
+
/** 添加路由 */
|
|
52
|
+
addRoute(route: RouteConfig): void;
|
|
53
|
+
/** 移除路由 */
|
|
54
|
+
removeRoute(path: string): void;
|
|
55
|
+
/** 清除所有路由 */
|
|
56
|
+
clearRoutes(): void;
|
|
57
|
+
/** 重新扫描文件系统 */
|
|
58
|
+
refresh(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @lytjs/router-fs
|
|
63
|
+
*
|
|
64
|
+
* LytJS File-System Router Engine
|
|
65
|
+
*
|
|
66
|
+
* @packageDocumentation
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 创建文件系统路由管理器
|
|
71
|
+
*/
|
|
72
|
+
declare function createFileSystemRouter(options?: FileSystemRouterOptions): FileSystemRouter;
|
|
73
|
+
|
|
74
|
+
export { type FileSystemRouter, type FileSystemRouterOptions, type RouteConfig, type RouteMatch, createFileSystemRouter };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
3
|
+
import { join, normalize, relative } from "path";
|
|
4
|
+
function isDirectory(path) {
|
|
5
|
+
return existsSync(path) && statSync(path).isDirectory();
|
|
6
|
+
}
|
|
7
|
+
function isFile(path) {
|
|
8
|
+
return existsSync(path) && statSync(path).isFile();
|
|
9
|
+
}
|
|
10
|
+
function filePathToRoutePath(filePath, baseDir, extensions) {
|
|
11
|
+
let normalized = normalize(relative(baseDir, filePath));
|
|
12
|
+
for (const ext of extensions) {
|
|
13
|
+
if (normalized.endsWith(ext)) {
|
|
14
|
+
normalized = normalized.slice(0, -ext.length);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
normalized = normalized.replace(/\\/g, "/");
|
|
19
|
+
if (normalized.endsWith("/index")) {
|
|
20
|
+
normalized = normalized.slice(0, -6);
|
|
21
|
+
} else if (normalized === "index") {
|
|
22
|
+
normalized = "";
|
|
23
|
+
}
|
|
24
|
+
normalized = normalized.replace(/\[(\w+)\]/g, ":$1");
|
|
25
|
+
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
26
|
+
}
|
|
27
|
+
function extractDynamicParams(routePath) {
|
|
28
|
+
const matches = routePath.match(/:(\w+)/g);
|
|
29
|
+
return matches ? matches.map((m) => m.slice(1)) : [];
|
|
30
|
+
}
|
|
31
|
+
function scanDirectory(dir, baseDir, extensions, ignorePatterns) {
|
|
32
|
+
const routes = [];
|
|
33
|
+
if (!isDirectory(dir)) return routes;
|
|
34
|
+
const files = readdirSync(dir);
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const fullPath = join(dir, file);
|
|
37
|
+
const relativePath = relative(baseDir, fullPath);
|
|
38
|
+
if (ignorePatterns.some((pattern) => {
|
|
39
|
+
if (relativePath.includes(pattern)) return true;
|
|
40
|
+
return file.includes(pattern);
|
|
41
|
+
})) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (isDirectory(fullPath)) {
|
|
45
|
+
routes.push(...scanDirectory(fullPath, baseDir, extensions, ignorePatterns));
|
|
46
|
+
} else if (isFile(fullPath)) {
|
|
47
|
+
const ext = extensions.find((e) => file.endsWith(e));
|
|
48
|
+
if (ext) {
|
|
49
|
+
const routePath = filePathToRoutePath(fullPath, baseDir, extensions);
|
|
50
|
+
const params = extractDynamicParams(routePath);
|
|
51
|
+
routes.push({
|
|
52
|
+
path: routePath,
|
|
53
|
+
componentPath: fullPath,
|
|
54
|
+
isDynamic: params.length > 0,
|
|
55
|
+
params,
|
|
56
|
+
isNested: routePath.split("/").length > 2
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return routes;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/index.ts
|
|
65
|
+
var DEFAULT_OPTIONS = {
|
|
66
|
+
pagesDir: "src/pages",
|
|
67
|
+
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
|
68
|
+
layoutPattern: "_layout",
|
|
69
|
+
ignorePatterns: ["node_modules", ".git", "dist"],
|
|
70
|
+
strictMode: false
|
|
71
|
+
};
|
|
72
|
+
function createFileSystemRouter(options) {
|
|
73
|
+
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
74
|
+
let routes = [];
|
|
75
|
+
async function refresh() {
|
|
76
|
+
routes = scanDirectory(
|
|
77
|
+
config.pagesDir,
|
|
78
|
+
config.pagesDir,
|
|
79
|
+
config.extensions,
|
|
80
|
+
config.ignorePatterns
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function match(path) {
|
|
84
|
+
for (const route of routes) {
|
|
85
|
+
if (route.path === path) {
|
|
86
|
+
return {
|
|
87
|
+
route,
|
|
88
|
+
params: {},
|
|
89
|
+
path
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const pathSegments = path.split("/").filter(Boolean);
|
|
94
|
+
for (const route of routes) {
|
|
95
|
+
const routeSegments = route.path.split("/").filter(Boolean);
|
|
96
|
+
if (routeSegments.length !== pathSegments.length) continue;
|
|
97
|
+
const params = {};
|
|
98
|
+
let match2 = true;
|
|
99
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
100
|
+
const routeSeg = routeSegments[i];
|
|
101
|
+
const pathSeg = pathSegments[i];
|
|
102
|
+
if (!routeSeg || !pathSeg) continue;
|
|
103
|
+
if (routeSeg.startsWith(":")) {
|
|
104
|
+
params[routeSeg.slice(1)] = pathSeg;
|
|
105
|
+
} else if (routeSeg !== pathSeg) {
|
|
106
|
+
match2 = false;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (match2) {
|
|
111
|
+
return {
|
|
112
|
+
route,
|
|
113
|
+
params,
|
|
114
|
+
path
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function getRoutes() {
|
|
121
|
+
return [...routes];
|
|
122
|
+
}
|
|
123
|
+
function addRoute(route) {
|
|
124
|
+
routes.push(route);
|
|
125
|
+
}
|
|
126
|
+
function removeRoute(path) {
|
|
127
|
+
routes = routes.filter((r) => r.path !== path);
|
|
128
|
+
}
|
|
129
|
+
function clearRoutes() {
|
|
130
|
+
routes = [];
|
|
131
|
+
}
|
|
132
|
+
refresh().catch((err) => {
|
|
133
|
+
console.warn("Failed to scan routes:", err);
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
getRoutes,
|
|
137
|
+
match,
|
|
138
|
+
addRoute,
|
|
139
|
+
removeRoute,
|
|
140
|
+
clearRoutes,
|
|
141
|
+
refresh
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export {
|
|
145
|
+
createFileSystemRouter
|
|
146
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lytjs/router-fs",
|
|
3
|
+
"version": "6.5.0",
|
|
4
|
+
"description": "LytJS File-System based Router Engine",
|
|
5
|
+
"author": "lytjs",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:coverage": "vitest run --coverage",
|
|
30
|
+
"type-check": "tsc --noEmit",
|
|
31
|
+
"clean": "rm -rf dist node_modules .turbo"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"tsup": "^8.3.6",
|
|
36
|
+
"typescript": "^5.7.3",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"registry": "https://registry.npmjs.org/"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://gitee.com/lytjs/lytjs.git",
|
|
47
|
+
"directory": "packages/ecosystem/packages/router-fs"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"lytjs",
|
|
51
|
+
"router",
|
|
52
|
+
"file-system",
|
|
53
|
+
"fs"
|
|
54
|
+
],
|
|
55
|
+
"homepage": "https://gitee.com/lytjs/lytjs",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://gitee.com/lytjs/lytjs/issues"
|
|
58
|
+
}
|
|
59
|
+
}
|