sdnext 0.0.2 → 0.0.3

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 CHANGED
@@ -12,19 +12,19 @@
12
12
 
13
13
  ### 对比表(Next.js 16 App Router vs sdrr)
14
14
 
15
- | Next.js 16(App Router)约定 | sdrr 行为(react-router 映射) | 备注 |
16
- | --- | --- | --- |
17
- | `app/` 作为路由根 | 扫描当前工作目录下的 `app/` 并生成 `components/Router.tsx` | 在 monorepo 里通常先 `cd` 到应用包根目录再执行 |
18
- | `page.(ts/tsx/js/jsx)` | 生成 `index: true` 的子路由组件(目录级页面) | 同名文件选择:`.lazy` 优先,其次 `tsx > jsx > ts > js` |
19
- | `layout.(ts/tsx/js/jsx)` | 生成父 route 的 `Component`(布局组件) | 典型 layout 需要渲染 `<Outlet />` |
20
- | 路由分组 `(group)` | 生成 `path` 为空的“pathless route” | 不会出现在 URL 中 |
21
- | 动态段 `[id]` | 映射为 `:id` | 与 Next 的动态段语义对齐 |
22
- | catch-all `[...slug]` | 映射为 `:slug/*`(内部用两层 route 生成) | `slug` 是第一个段;剩余段在 `params["*"]` |
23
- | optional catch-all `[[...slug]]` | 同时生成 `/`(index)与 `:slug/*` 两种匹配 | 与 Next 的“可选”语义对齐 |
24
- | `error.(ts/tsx/js/jsx)` | 映射为 route 的 `ErrorBoundary` | Next 的 `error.js` 是错误边界概念,近似映射 |
25
- | `not-found.(ts/tsx/js/jsx)` | 生成 `path: "*"` 的兜底子路由 | 用于该布局/段下的 404 兜底 |
26
- | `@slot`(并行路由) | 不支持,直接抛错 | `react-router` 缺少命名 slot/outlet 的等价能力 |
27
- | `(.)/(..)/(...)`(拦截路由) | 不支持,直接抛错 | `react-router` 无等价语义 |
15
+ | Next.js 16(App Router)约定 | sdrr 行为(react-router 映射) | 备注 |
16
+ | -------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------ |
17
+ | `app/` 作为路由根 | 扫描当前工作目录下的 `app/` 并生成 `components/Router.tsx` | 在 monorepo 里通常先 `cd` 到应用包根目录再执行 |
18
+ | `page.(ts/tsx/js/jsx)` | 生成 `index: true` 的子路由组件(目录级页面) | 同名文件选择:`.lazy` 优先,其次 `tsx > jsx > ts > js` |
19
+ | `layout.(ts/tsx/js/jsx)` | 生成父 route 的 `Component`(布局组件) | 典型 layout 需要渲染 `<Outlet />` |
20
+ | 路由分组 `(group)` | 生成 `path` 为空的“pathless route” | 不会出现在 URL 中 |
21
+ | 动态段 `[id]` | 映射为 `:id` | 与 Next 的动态段语义对齐 |
22
+ | catch-all `[...slug]` | 映射为 `:slug/*`(内部用两层 route 生成) | `slug` 是第一个段;剩余段在 `params["*"]` |
23
+ | optional catch-all `[[...slug]]` | 同时生成 `/`(index)与 `:slug/*` 两种匹配 | 与 Next 的“可选”语义对齐 |
24
+ | `error.(ts/tsx/js/jsx)` | 映射为 route 的 `ErrorBoundary` | Next 的 `error.js` 是错误边界概念,近似映射 |
25
+ | `not-found.(ts/tsx/js/jsx)` | 生成 `path: "*"` 的兜底子路由 | 用于该布局/段下的 404 兜底 |
26
+ | `@slot`(并行路由) | 不支持,直接抛错 | `react-router` 缺少命名 slot/outlet 的等价能力 |
27
+ | `(.)/(..)/(...)`(拦截路由) | 不支持,直接抛错 | `react-router` 无等价语义 |
28
28
 
29
29
  ## 前置要求
30
30
 
@@ -182,14 +182,14 @@ sdrr build pnpm dev --watch
182
182
  同一目录下:
183
183
 
184
184
  - 同时存在 `layout.*` 和 `page.*`
185
- - 该目录会生成一个带 `path` 的布局 route
186
- - `page.*` 会作为该布局的 `index: true` 子路由
187
- - 子目录路由会作为该布局的 children
185
+ - 该目录会生成一个带 `path` 的布局 route
186
+ - `page.*` 会作为该布局的 `index: true` 子路由
187
+ - 子目录路由会作为该布局的 children
188
188
  - 只有 `page.*`
189
- - 如果该目录下没有子目录路由:会生成一个普通 route
190
- - 如果该目录下还有子目录路由:会生成一个父 route(`path` 为目录名),并将 `page.*` 作为其 `index: true` 子路由,同时把子目录路由挂到该父 route 的 `children` 下(从而支持如 `/user/a` 这类嵌套路由)
189
+ - 如果该目录下没有子目录路由:会生成一个普通 route
190
+ - 如果该目录下还有子目录路由:会生成一个父 route(`path` 为目录名),并将 `page.*` 作为其 `index: true` 子路由,同时把子目录路由挂到该父 route 的 `children` 下(从而支持如 `/user/a` 这类嵌套路由)
191
191
  - 只有 `layout.*`
192
- - 会生成一个“无 path 的布局包装层”(pathless route),更适合放在分组目录 `(xxx)` 下用于包裹子路由
192
+ - 会生成一个“无 path 的布局包装层”(pathless route),更适合放在分组目录 `(xxx)` 下用于包裹子路由
193
193
 
194
194
  ### 一个更完整的目录示例
195
195
 
@@ -293,8 +293,8 @@ export default function App() {
293
293
  "scripts": {
294
294
  "router:gen": "sdrr build",
295
295
  "dev": "sdrr build vite dev -w",
296
- "build": "sdrr build vite build"
297
- }
296
+ "build": "sdrr build vite build",
297
+ },
298
298
  }
299
299
  ```
300
300
 
@@ -16,7 +16,7 @@ async function build(options, { args }) {
16
16
  await excludeActions();
17
17
  await buildFolder("shared");
18
18
  if (0 === args.length) return;
19
- spawn(args.at(0), args.slice(1), {
19
+ spawn(args.join(" "), {
20
20
  stdio: "inherit",
21
21
  shell: true
22
22
  });
package/dist/utils/dev.js CHANGED
@@ -9,7 +9,7 @@ async function dev(options, { args }) {
9
9
  const child = spawn(process.execPath, [
10
10
  watchPath
11
11
  ]);
12
- const child2 = spawn(args.at(0), args.slice(1), {
12
+ const child2 = spawn(args.join(" "), {
13
13
  stdio: "inherit",
14
14
  shell: true
15
15
  });
@@ -151,10 +151,12 @@ async function hook(options, { args }) {
151
151
  choices: [
152
152
  "mutation",
153
153
  "query",
154
- "get"
154
+ "get",
155
+ "skip"
155
156
  ],
156
157
  default: type
157
158
  });
159
+ if ("skip" === answer) continue;
158
160
  const { dir, base } = parse(path);
159
161
  await mkdir(join("hooks", dir), {
160
162
  recursive: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdnext",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "exports": {
@@ -26,7 +26,7 @@ export async function build(options: Record<string, string>, { args }: Command)
26
26
 
27
27
  if (args.length === 0) return
28
28
 
29
- spawn(args.at(0)!, args.slice(1), {
29
+ spawn(args.join(" "), {
30
30
  stdio: "inherit",
31
31
  shell: true,
32
32
  })
package/src/utils/dev.ts CHANGED
@@ -16,7 +16,7 @@ export async function dev(options: Record<string, string>, { args }: Command) {
16
16
 
17
17
  const child = spawn(process.execPath, [watchPath])
18
18
 
19
- const child2 = spawn(args.at(0)!, args.slice(1), {
19
+ const child2 = spawn(args.join(" "), {
20
20
  stdio: "inherit",
21
21
  shell: true,
22
22
  })
package/src/utils/hook.ts CHANGED
@@ -212,12 +212,16 @@ export async function hook(options: Record<string, string>, { args }: Command) {
212
212
  const oldEntires = entires.filter(([path, { overwrite }]) => !overwrite)
213
213
 
214
214
  for await (const [path, { overwrite, type, ...map }] of newEntires) {
215
- const answer = await select<HookType>({
215
+ type OperationType = HookType | "skip"
216
+
217
+ const answer = await select<OperationType>({
216
218
  message: path,
217
- choices: ["mutation", "query", "get"],
219
+ choices: ["mutation", "query", "get", "skip"],
218
220
  default: type,
219
221
  })
220
222
 
223
+ if (answer === "skip") continue
224
+
221
225
  const { dir, base } = parse(path)
222
226
  await mkdir(join("hooks", dir), { recursive: true })
223
227
  await writeFile(