reroute-js 0.1.0 → 0.2.1

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.
Files changed (189) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/package.json +8 -6
  4. package/packages/cli/README.md +264 -0
  5. package/{cli/bin.d.ts → packages/cli/bin.ts} +1 -1
  6. package/packages/core/README.md +90 -0
  7. package/packages/elysia/README.md +250 -0
  8. package/packages/react/README.md +3 -0
  9. package/_/README.md +0 -59
  10. package/_/basic/package.json +0 -23
  11. package/_/basic/src/client/App.tsx +0 -10
  12. package/_/basic/src/client/components/Counter.tsx +0 -15
  13. package/_/basic/src/client/index.html +0 -12
  14. package/_/basic/src/client/index.tsx +0 -5
  15. package/_/basic/src/client/routes/[404].tsx +0 -18
  16. package/_/basic/src/client/routes/about.tsx +0 -25
  17. package/_/basic/src/client/routes/index.tsx +0 -57
  18. package/_/basic/src/index.ts +0 -20
  19. package/_/basic/tsconfig.json +0 -26
  20. package/_/blog/package.json +0 -23
  21. package/_/blog/src/client/App.tsx +0 -10
  22. package/_/blog/src/client/components/Counter.tsx +0 -14
  23. package/_/blog/src/client/components/RecentPosts.tsx +0 -90
  24. package/_/blog/src/client/index.html +0 -13
  25. package/_/blog/src/client/index.tsx +0 -5
  26. package/_/blog/src/client/routes/[404].tsx +0 -21
  27. package/_/blog/src/client/routes/about.tsx +0 -31
  28. package/_/blog/src/client/routes/blog/[404].tsx +0 -21
  29. package/_/blog/src/client/routes/blog/[layout].tsx +0 -84
  30. package/_/blog/src/client/routes/blog/[slug].tsx +0 -11
  31. package/_/blog/src/client/routes/blog/content/1-hello-world.tsx +0 -27
  32. package/_/blog/src/client/routes/blog/content/2-what-is-reroute.tsx +0 -31
  33. package/_/blog/src/client/routes/blog/index.tsx +0 -70
  34. package/_/blog/src/client/routes/index.tsx +0 -63
  35. package/_/blog/src/index.ts +0 -20
  36. package/_/blog/tsconfig.json +0 -26
  37. package/_/store/package.json +0 -25
  38. package/_/store/src/client/App.tsx +0 -17
  39. package/_/store/src/client/components/Header.tsx +0 -40
  40. package/_/store/src/client/components/ProductCard.tsx +0 -51
  41. package/_/store/src/client/index.html +0 -17
  42. package/_/store/src/client/index.tsx +0 -7
  43. package/_/store/src/client/lib/api.ts +0 -153
  44. package/_/store/src/client/routes/[404].tsx +0 -63
  45. package/_/store/src/client/routes/categories/[category].tsx +0 -223
  46. package/_/store/src/client/routes/categories/index.tsx +0 -187
  47. package/_/store/src/client/routes/index.tsx +0 -126
  48. package/_/store/src/client/routes/products/[id].tsx +0 -233
  49. package/_/store/src/client/routes/products/index.tsx +0 -261
  50. package/_/store/src/client/theme.css +0 -306
  51. package/_/store/src/index.ts +0 -19
  52. package/_/store/tsconfig.json +0 -26
  53. package/cli/bin.d.ts.map +0 -1
  54. package/cli/bin.js +0 -878
  55. package/cli/bin.js.map +0 -15
  56. package/cli/index.d.ts +0 -2
  57. package/cli/index.d.ts.map +0 -1
  58. package/cli/index.js +0 -147
  59. package/cli/index.js.map +0 -10
  60. package/cli/src/cli.d.ts +0 -8
  61. package/cli/src/cli.d.ts.map +0 -1
  62. package/cli/src/commands/build.d.ts +0 -8
  63. package/cli/src/commands/build.d.ts.map +0 -1
  64. package/cli/src/commands/dev.d.ts +0 -8
  65. package/cli/src/commands/dev.d.ts.map +0 -1
  66. package/cli/src/commands/gen.d.ts +0 -3
  67. package/cli/src/commands/gen.d.ts.map +0 -1
  68. package/cli/src/commands/init.d.ts +0 -8
  69. package/cli/src/commands/init.d.ts.map +0 -1
  70. package/cli/src/libs/index.d.ts +0 -2
  71. package/cli/src/libs/index.d.ts.map +0 -1
  72. package/cli/src/libs/tailwind.d.ts +0 -45
  73. package/cli/src/libs/tailwind.d.ts.map +0 -1
  74. package/core/index.d.ts +0 -2
  75. package/core/index.d.ts.map +0 -1
  76. package/core/index.js +0 -1117
  77. package/core/index.js.map +0 -25
  78. package/core/src/bundler/hash.d.ts +0 -2
  79. package/core/src/bundler/hash.d.ts.map +0 -1
  80. package/core/src/bundler/index.d.ts +0 -3
  81. package/core/src/bundler/index.d.ts.map +0 -1
  82. package/core/src/bundler/transpile.d.ts +0 -4
  83. package/core/src/bundler/transpile.d.ts.map +0 -1
  84. package/core/src/content/discovery.d.ts +0 -5
  85. package/core/src/content/discovery.d.ts.map +0 -1
  86. package/core/src/content/index.d.ts +0 -4
  87. package/core/src/content/index.d.ts.map +0 -1
  88. package/core/src/content/metadata.d.ts +0 -9
  89. package/core/src/content/metadata.d.ts.map +0 -1
  90. package/core/src/content/registry.d.ts +0 -2
  91. package/core/src/content/registry.d.ts.map +0 -1
  92. package/core/src/index.d.ts +0 -7
  93. package/core/src/index.d.ts.map +0 -1
  94. package/core/src/ssr/data.d.ts +0 -9
  95. package/core/src/ssr/data.d.ts.map +0 -1
  96. package/core/src/ssr/index.d.ts +0 -4
  97. package/core/src/ssr/index.d.ts.map +0 -1
  98. package/core/src/ssr/modules.d.ts +0 -8
  99. package/core/src/ssr/modules.d.ts.map +0 -1
  100. package/core/src/ssr/render.d.ts +0 -20
  101. package/core/src/ssr/render.d.ts.map +0 -1
  102. package/core/src/ssr/seed.d.ts +0 -2
  103. package/core/src/ssr/seed.d.ts.map +0 -1
  104. package/core/src/template/html.d.ts +0 -4
  105. package/core/src/template/html.d.ts.map +0 -1
  106. package/core/src/template/index.d.ts +0 -2
  107. package/core/src/template/index.d.ts.map +0 -1
  108. package/core/src/types.d.ts +0 -50
  109. package/core/src/types.d.ts.map +0 -1
  110. package/core/src/utils/cache.d.ts +0 -12
  111. package/core/src/utils/cache.d.ts.map +0 -1
  112. package/core/src/utils/compression.d.ts +0 -5
  113. package/core/src/utils/compression.d.ts.map +0 -1
  114. package/core/src/utils/index.d.ts +0 -5
  115. package/core/src/utils/index.d.ts.map +0 -1
  116. package/core/src/utils/mime.d.ts +0 -3
  117. package/core/src/utils/mime.d.ts.map +0 -1
  118. package/core/src/utils/path.d.ts +0 -6
  119. package/core/src/utils/path.d.ts.map +0 -1
  120. package/elysia/index.d.ts +0 -2
  121. package/elysia/index.d.ts.map +0 -1
  122. package/elysia/index.js +0 -1762
  123. package/elysia/index.js.map +0 -32
  124. package/elysia/src/index.d.ts +0 -3
  125. package/elysia/src/index.d.ts.map +0 -1
  126. package/elysia/src/plugin.d.ts +0 -32
  127. package/elysia/src/plugin.d.ts.map +0 -1
  128. package/elysia/src/routes/artifacts.d.ts +0 -3
  129. package/elysia/src/routes/artifacts.d.ts.map +0 -1
  130. package/elysia/src/routes/content.d.ts +0 -3
  131. package/elysia/src/routes/content.d.ts.map +0 -1
  132. package/elysia/src/routes/dev.d.ts +0 -7
  133. package/elysia/src/routes/dev.d.ts.map +0 -1
  134. package/elysia/src/routes/ssr.d.ts +0 -19
  135. package/elysia/src/routes/ssr.d.ts.map +0 -1
  136. package/elysia/src/routes/static.d.ts +0 -19
  137. package/elysia/src/routes/static.d.ts.map +0 -1
  138. package/elysia/src/types.d.ts +0 -31
  139. package/elysia/src/types.d.ts.map +0 -1
  140. package/elysia/src/utils/http.d.ts +0 -5
  141. package/elysia/src/utils/http.d.ts.map +0 -1
  142. package/react/index.d.ts +0 -2
  143. package/react/index.d.ts.map +0 -1
  144. package/react/index.js +0 -1152
  145. package/react/index.js.map +0 -23
  146. package/react/src/components/ContentRoute.d.ts +0 -13
  147. package/react/src/components/ContentRoute.d.ts.map +0 -1
  148. package/react/src/components/Link.d.ts +0 -8
  149. package/react/src/components/Link.d.ts.map +0 -1
  150. package/react/src/components/Outlet.d.ts +0 -7
  151. package/react/src/components/Outlet.d.ts.map +0 -1
  152. package/react/src/components/index.d.ts +0 -4
  153. package/react/src/components/index.d.ts.map +0 -1
  154. package/react/src/hooks/index.d.ts +0 -7
  155. package/react/src/hooks/index.d.ts.map +0 -1
  156. package/react/src/hooks/useContent.d.ts +0 -26
  157. package/react/src/hooks/useContent.d.ts.map +0 -1
  158. package/react/src/hooks/useData.d.ts +0 -10
  159. package/react/src/hooks/useData.d.ts.map +0 -1
  160. package/react/src/hooks/useNavigate.d.ts +0 -6
  161. package/react/src/hooks/useNavigate.d.ts.map +0 -1
  162. package/react/src/hooks/useParams.d.ts +0 -6
  163. package/react/src/hooks/useParams.d.ts.map +0 -1
  164. package/react/src/hooks/useRouter.d.ts +0 -7
  165. package/react/src/hooks/useRouter.d.ts.map +0 -1
  166. package/react/src/hooks/useSearchParams.d.ts +0 -6
  167. package/react/src/hooks/useSearchParams.d.ts.map +0 -1
  168. package/react/src/index.d.ts +0 -6
  169. package/react/src/index.d.ts.map +0 -1
  170. package/react/src/providers/ContentProvider.d.ts +0 -35
  171. package/react/src/providers/ContentProvider.d.ts.map +0 -1
  172. package/react/src/providers/RerouteProvider.d.ts +0 -25
  173. package/react/src/providers/RerouteProvider.d.ts.map +0 -1
  174. package/react/src/providers/RouterProvider.d.ts +0 -23
  175. package/react/src/providers/RouterProvider.d.ts.map +0 -1
  176. package/react/src/providers/index.d.ts +0 -4
  177. package/react/src/providers/index.d.ts.map +0 -1
  178. package/react/src/types/any.d.ts +0 -3
  179. package/react/src/types/any.d.ts.map +0 -1
  180. package/react/src/types/index.d.ts +0 -3
  181. package/react/src/types/index.d.ts.map +0 -1
  182. package/react/src/types/router.d.ts +0 -32
  183. package/react/src/types/router.d.ts.map +0 -1
  184. package/react/src/utils/content.d.ts +0 -8
  185. package/react/src/utils/content.d.ts.map +0 -1
  186. package/react/src/utils/head.d.ts +0 -6
  187. package/react/src/utils/head.d.ts.map +0 -1
  188. package/react/src/utils/index.d.ts +0 -3
  189. package/react/src/utils/index.d.ts.map +0 -1
package/cli/bin.js DELETED
@@ -1,878 +0,0 @@
1
- #!/usr/bin/env bun
2
- // @bun
3
- var __defProp = Object.defineProperty;
4
- var __export = (target, all) => {
5
- for (var name in all)
6
- __defProp(target, name, {
7
- get: all[name],
8
- enumerable: true,
9
- configurable: true,
10
- set: (newValue) => all[name] = () => newValue
11
- });
12
- };
13
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
14
-
15
- // packages/cli/src/commands/init.ts
16
- var exports_init = {};
17
- __export(exports_init, {
18
- default: () => init
19
- });
20
- import { existsSync } from "node:fs";
21
- import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
22
- import { join } from "node:path";
23
- async function init(args) {
24
- const options = parseArgs(args);
25
- if (!options) {
26
- printHelp();
27
- process.exit(1);
28
- }
29
- try {
30
- await scaffoldProject(options);
31
- } catch (error) {
32
- console.error("Error scaffolding project:", error);
33
- process.exit(1);
34
- }
35
- }
36
- function parseArgs(args) {
37
- if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
38
- return null;
39
- }
40
- const projectName = args[0];
41
- if (!projectName || projectName.startsWith("-")) {
42
- console.error("Error: Project name is required");
43
- return null;
44
- }
45
- if (!/^[a-z0-9-_]+$/i.test(projectName)) {
46
- console.error("Error: Project name can only contain letters, numbers, hyphens, and underscores");
47
- return null;
48
- }
49
- let template = "basic";
50
- const templateIndex = args.indexOf("--template");
51
- if (templateIndex !== -1 && args[templateIndex + 1]) {
52
- const templateArg = args[templateIndex + 1];
53
- if (["basic", "blog", "store"].includes(templateArg)) {
54
- template = templateArg;
55
- } else {
56
- console.error(`Error: Unknown template "${templateArg}". Available templates: basic, blog, store`);
57
- return null;
58
- }
59
- }
60
- return { projectName, template };
61
- }
62
- async function scaffoldProject(options) {
63
- const { projectName, template } = options;
64
- const projectPath = join(process.cwd(), projectName);
65
- if (existsSync(projectPath)) {
66
- console.error(`Error: Directory "${projectName}" already exists`);
67
- process.exit(1);
68
- }
69
- console.log(`
70
- \uD83C\uDFD7️ Creating project: ${projectName}`);
71
- console.log(`
72
- \uD83D\uDCE6 Template: ${template}
73
- `);
74
- const templatePath = join(import.meta.dir, "..", "_", template);
75
- if (!existsSync(templatePath)) {
76
- console.error(`Error: Template directory not found at ${templatePath}`);
77
- process.exit(1);
78
- }
79
- await mkdir(projectPath, { recursive: true });
80
- await copyTemplateFiles(templatePath, projectPath, {
81
- PROJECT_NAME: projectName
82
- });
83
- console.log(`\uD83D\uDCE5 Installing dependencies...
84
- `);
85
- const proc = Bun.spawn(["bun", "install"], {
86
- cwd: projectPath,
87
- stdout: "inherit",
88
- stderr: "inherit"
89
- });
90
- await proc.exited;
91
- printSuccess(projectName, template);
92
- }
93
- async function copyTemplateFiles(templatePath, targetPath, variables) {
94
- const entries = await readdir(templatePath, { withFileTypes: true });
95
- for (const entry of entries) {
96
- const sourcePath = join(templatePath, entry.name);
97
- const destPath = join(targetPath, entry.name);
98
- if (entry.isDirectory()) {
99
- await mkdir(destPath, { recursive: true });
100
- await copyTemplateFiles(sourcePath, destPath, variables);
101
- } else if (entry.isFile()) {
102
- const content = await readFile(sourcePath, "utf-8");
103
- let processedContent = content;
104
- for (const [key, value] of Object.entries(variables)) {
105
- const placeholder = `{{${key}}}`;
106
- processedContent = processedContent.split(placeholder).join(value);
107
- }
108
- await writeFile(destPath, processedContent);
109
- }
110
- }
111
- }
112
- function printSuccess(projectName, template) {
113
- console.log(`
114
- \uD83C\uDFCE️ Project created successfully!
115
- `);
116
- console.log(`Next steps:
117
- `);
118
- console.log(` cd ${projectName}`);
119
- console.log(" bunx reroute-js gen # Required on first run");
120
- console.log(` bun dev
121
- `);
122
- console.log(`Your app will be running at http://localhost:3000
123
- `);
124
- console.log("Project structure:");
125
- console.log(" src/");
126
- console.log(" |-- index.ts # Server entry point");
127
- console.log(" +-- client/");
128
- console.log(" |-- App.tsx # Root React component");
129
- console.log(" |-- index.tsx # Client entry point");
130
- console.log(" |-- index.html # HTML template");
131
- console.log(" |-- routes/ # File-based routes");
132
- if (template === "blog") {
133
- console.log(" | |-- blog/");
134
- console.log(" | | |-- content/ # Blog posts");
135
- console.log(" | | |-- [slug].tsx");
136
- console.log(" | | +-- index.tsx");
137
- }
138
- if (template === "store") {
139
- console.log(" | |-- products/");
140
- console.log(" | |-- categories/");
141
- console.log(" |-- lib/ # API client & utilities");
142
- console.log(" +-- theme.css # Tailwind CSS v4");
143
- }
144
- console.log(" | |-- index.tsx");
145
- console.log(" | +-- about.tsx");
146
- console.log(` +-- components/ # React components
147
- `);
148
- console.log("Learn more at https://github.com/stewones/reroute");
149
- }
150
- function printHelp() {
151
- console.log("reroute init - Scaffold a new Reroute project");
152
- console.log("");
153
- console.log("Usage:");
154
- console.log(" reroute init <project-name> [options]");
155
- console.log("");
156
- console.log("Options:");
157
- console.log(" --template <name> Template to use (basic, blog, store)");
158
- console.log(" -h, --help Show help");
159
- console.log("");
160
- console.log("Examples:");
161
- console.log(" reroute init my-app");
162
- console.log(" reroute init my-blog --template blog");
163
- console.log(" reroute init my-store --template store");
164
- }
165
- var init_init = () => {};
166
-
167
- // packages/cli/src/commands/build.ts
168
- var exports_build = {};
169
- __export(exports_build, {
170
- default: () => build
171
- });
172
- async function build(_args) {
173
- console.log("reroute build - Coming Soon");
174
- console.log("");
175
- console.log("This command will build your Reroute application for production.");
176
- console.log("");
177
- console.log("Planned usage:");
178
- console.log(" reroute build");
179
- console.log(" reroute build --minify");
180
- console.log(" reroute build --analyze");
181
- console.log("");
182
- console.log("For now, please use your own build setup or check the examples.");
183
- }
184
-
185
- // packages/cli/src/commands/dev.ts
186
- var exports_dev = {};
187
- __export(exports_dev, {
188
- default: () => dev
189
- });
190
- async function dev(_args) {
191
- console.log("reroute dev - Coming Soon");
192
- console.log("");
193
- console.log("This command will start a development server with live reload.");
194
- console.log("");
195
- console.log("Planned usage:");
196
- console.log(" reroute dev");
197
- console.log(" reroute dev --port 3000");
198
- console.log(" reroute dev --host 0.0.0.0");
199
- console.log("");
200
- console.log("Note: dev already generates content registry and static assets");
201
- console.log("");
202
- console.log("For now, please use your own dev server setup or check the examples.");
203
- }
204
-
205
- // packages/cli/src/libs/tailwind.ts
206
- import { spawn } from "node:child_process";
207
- import { existsSync as existsSync2, readFileSync } from "node:fs";
208
- import { join as join2 } from "node:path";
209
- function isTailwindAvailable(cwd) {
210
- const packageJsonPath = join2(cwd, "package.json");
211
- if (!existsSync2(packageJsonPath)) {
212
- return false;
213
- }
214
- try {
215
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
216
- const deps = {
217
- ...packageJson.dependencies,
218
- ...packageJson.devDependencies
219
- };
220
- return "@tailwindcss/cli" in deps;
221
- } catch {
222
- return false;
223
- }
224
- }
225
- function getTailwindPaths(cwd) {
226
- const input = join2(cwd, "src/client/theme.css");
227
- const output = join2(cwd, ".reroute/theme.css");
228
- return { input, output };
229
- }
230
- function hasTailwindInput(cwd) {
231
- const { input } = getTailwindPaths(cwd);
232
- if (!existsSync2(input)) {
233
- return false;
234
- }
235
- try {
236
- const content = readFileSync(input, "utf-8");
237
- return content.includes('@import "tailwindcss"');
238
- } catch {
239
- return false;
240
- }
241
- }
242
- function resolveTailwindBin(cwd) {
243
- const pathsToTry = [
244
- join2(cwd, "node_modules/.bin/tailwindcss"),
245
- join2(cwd, "../node_modules/.bin/tailwindcss"),
246
- join2(cwd, "../../node_modules/.bin/tailwindcss"),
247
- join2(cwd, "../../../node_modules/.bin/tailwindcss")
248
- ];
249
- for (const binPath of pathsToTry) {
250
- if (existsSync2(binPath)) {
251
- return binPath;
252
- }
253
- }
254
- return join2(cwd, "node_modules/.bin/tailwindcss");
255
- }
256
- async function buildTailwind(cwd) {
257
- const { input, output } = getTailwindPaths(cwd);
258
- return new Promise((resolve, reject) => {
259
- const tailwindBin = resolveTailwindBin(cwd);
260
- const args = ["-i", input, "-o", output];
261
- console.log(`[reroute/tailwind] build start: -i ${input} -o ${output}`);
262
- const tailwind = spawn(tailwindBin, args, {
263
- cwd,
264
- stdio: "pipe"
265
- });
266
- tailwind.stdout?.on("data", (data) => {
267
- const line = data.toString().trim();
268
- if (line) {
269
- console.log(`[reroute/tailwind] ${line}`);
270
- }
271
- });
272
- tailwind.stderr?.on("data", (data) => {
273
- const line = data.toString().trim();
274
- if (line) {
275
- console.log(`[reroute/tailwind] ${line}`);
276
- }
277
- });
278
- tailwind.on("close", (code) => {
279
- if (code === 0) {
280
- console.log("[reroute/tailwind] build done");
281
- resolve();
282
- } else {
283
- reject(new Error(`Tailwind CSS build failed with code ${code}`));
284
- }
285
- });
286
- tailwind.on("error", (error) => {
287
- reject(error);
288
- });
289
- });
290
- }
291
- function initTailwind(cwd) {
292
- if (!isTailwindAvailable(cwd)) {
293
- return null;
294
- }
295
- if (!hasTailwindInput(cwd)) {
296
- console.log('[reroute/tailwind] theme.css not found or missing @import "tailwindcss", skipping...');
297
- return null;
298
- }
299
- console.log("[reroute/tailwind] Detected Tailwind CSS v4");
300
- buildTailwind(cwd).then(() => {
301
- console.log("[reroute/tailwind] Built successfully");
302
- }).catch((error) => {
303
- console.error("[reroute/tailwind] Build failed:", error);
304
- });
305
- return null;
306
- }
307
- var init_tailwind = () => {};
308
-
309
- // packages/cli/src/commands/gen.ts
310
- var exports_gen = {};
311
- __export(exports_gen, {
312
- default: () => gen
313
- });
314
- import { watch } from "node:fs";
315
- import { mkdir as mkdir2, readdir as readdir2, rm, writeFile as writeFile2 } from "node:fs/promises";
316
- import { join as join3 } from "node:path";
317
- import { pathToFileURL } from "node:url";
318
- async function cleanupOutputDir(cwd) {
319
- try {
320
- await rm(join3(cwd, OUTPUT_DIR), { force: true });
321
- await mkdir2(join3(cwd, OUTPUT_DIR), { recursive: true });
322
- console.log("[reroute/gen] Cleaned up generated artifacts in .reroute");
323
- } catch {}
324
- }
325
- async function scanDirectory(dir, base = "") {
326
- const files = [];
327
- const entries = await readdir2(dir, { withFileTypes: true });
328
- for (const entry of entries) {
329
- const fullPath = join3(dir, entry.name);
330
- const relativePath = join3(base, entry.name);
331
- if (entry.isDirectory()) {
332
- if (entry.name === "content")
333
- continue;
334
- const nested = await scanDirectory(fullPath, relativePath);
335
- files.push(...nested);
336
- } else if (entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts"))) {
337
- if (relativePath.includes("/content/") || relativePath.startsWith("content/")) {
338
- continue;
339
- }
340
- if (!entry.name.startsWith("_") || entry.name === "[layout].tsx") {
341
- files.push(relativePath);
342
- }
343
- }
344
- }
345
- return files;
346
- }
347
- async function scan404Files(dir, base = "") {
348
- const files = [];
349
- const entries = await readdir2(dir, { withFileTypes: true });
350
- for (const entry of entries) {
351
- const fullPath = join3(dir, entry.name);
352
- const relativePath = join3(base, entry.name);
353
- if (entry.isDirectory()) {
354
- const nested = await scan404Files(fullPath, relativePath);
355
- files.push(...nested);
356
- } else if (entry.isFile()) {
357
- if (/^\[404]\.(tsx|ts)$/.test(entry.name))
358
- files.push(relativePath);
359
- }
360
- }
361
- return files;
362
- }
363
- function fileToRoute(filePath) {
364
- const isLayout = filePath.endsWith("[layout].tsx") || filePath.endsWith("[layout].ts");
365
- let routePath = filePath.replace(/\.(tsx|ts)$/, "");
366
- if (isLayout) {
367
- routePath = routePath.replace(/[layout]$/, "").replace(/\/$/, "");
368
- }
369
- routePath = routePath.replace(/\/index$/, "").replace(/^index$/, "");
370
- const params = [];
371
- const pattern = routePath.replace(/\[([^\]]+)\]/g, (_, param) => {
372
- params.push(param);
373
- return `:${param}`;
374
- });
375
- const normalizedPattern = pattern === "" ? "/" : `/${pattern}`;
376
- const isNotFound = /(^|\/)\[404\]$/.test(routePath);
377
- let notFoundBasePattern;
378
- if (isNotFound) {
379
- const base = routePath.replace(/(^|\/)\[404\]$/, "").replace(/\/$/, "");
380
- notFoundBasePattern = base ? `/${base}` : "/";
381
- }
382
- return {
383
- path: routePath,
384
- pattern: normalizedPattern,
385
- filePath,
386
- isLayout,
387
- isDynamic: params.length > 0,
388
- params,
389
- isNotFound,
390
- notFoundBasePattern
391
- };
392
- }
393
- function sortRoutes(routes) {
394
- return routes.sort((a, b) => {
395
- const aDepth = a.pattern.split("/").length;
396
- const bDepth = b.pattern.split("/").length;
397
- if (aDepth !== bDepth)
398
- return bDepth - aDepth;
399
- if (!a.isDynamic && b.isDynamic)
400
- return -1;
401
- if (a.isDynamic && !b.isDynamic)
402
- return 1;
403
- return a.pattern.localeCompare(b.pattern);
404
- });
405
- }
406
- function generateRouteTree(files) {
407
- const routes = [];
408
- const layouts = [];
409
- const notFoundRoutes = [];
410
- for (const file of files) {
411
- const route = fileToRoute(file);
412
- if (route.isLayout) {
413
- layouts.push(route);
414
- } else if (route.isNotFound) {
415
- notFoundRoutes.push(route);
416
- } else {
417
- routes.push(route);
418
- }
419
- }
420
- return {
421
- routes: sortRoutes(routes),
422
- layouts,
423
- notFoundRoutes
424
- };
425
- }
426
- function generateTypeScript(tree) {
427
- const imports = [
428
- ...tree.routes.map((r, i) => `import Route${i} from '../src/client/routes/${r.filePath.replace(/\.(tsx|ts)$/, "")}';`),
429
- ...tree.layouts.map((l, i) => `import Layout${i} from '../src/client/routes/${l.filePath.replace(/\.(tsx|ts)$/, "")}';`),
430
- ...tree.notFoundRoutes.map((nf, i) => `import NotFound${i} from '../src/client/routes/${nf.filePath.replace(/\.(tsx|ts)$/, "")}';`)
431
- ].join(`
432
- `);
433
- const routesArray = tree.routes.map((r, i) => {
434
- return ` {
435
- pattern: "${r.pattern}",
436
- path: "${r.path}",
437
- component: Route${i},
438
- params: ${JSON.stringify(r.params)},
439
- isDynamic: ${r.isDynamic},
440
- } as const`;
441
- }).join(`,
442
- `);
443
- const routePatterns = tree.routes.map((r) => ` | "${r.pattern}"`).join(`
444
- `);
445
- const routeParamsUnion = tree.routes.filter((r) => r.isDynamic).map((r) => {
446
- const params = r.params.map((p) => `${p}: string`).join("; ");
447
- return ` T extends "${r.pattern}" ? { ${params} } :`;
448
- }).join(`
449
- `);
450
- const layoutsArray = tree.layouts.map((l, i) => {
451
- return ` {
452
- pattern: "${l.pattern}",
453
- path: "${l.path}",
454
- component: Layout${i},
455
- } as const`;
456
- }).join(`,
457
- `);
458
- const notFoundRoutesArray = tree.notFoundRoutes.map((nf, i) => {
459
- return ` {
460
- pattern: "${nf.notFoundBasePattern || "/"}",
461
- path: "${nf.path}",
462
- component: NotFound${i},
463
- } as const`;
464
- }).join(`,
465
- `);
466
- return `// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8
467
- /* eslint-disable */
468
- // @ts-nocheck
469
-
470
- ${imports}
471
-
472
- export const routes: RouteInfo = [
473
- ${routesArray}
474
- ] as const;
475
-
476
- export const layouts = [
477
- ${layoutsArray || ""}
478
- ] as const;
479
-
480
- export const notFoundRoutes = [
481
- ${notFoundRoutesArray || ""}
482
- ] as const;
483
-
484
- export type RoutePath =
485
- ${routePatterns || ' | "/"'};
486
-
487
- export type RouteParams<T extends RoutePath> = ${routeParamsUnion ? `
488
- ${routeParamsUnion}
489
- Record<string, never>;` : "Record<string, never>;"}
490
-
491
- export interface Route {
492
- pattern: string;
493
- path: string;
494
- component: any;
495
- params: string[];
496
- isDynamic: boolean;
497
- }
498
-
499
- export function matchRoute(pathname: string): { route: Route; params: Record<string, string> } | null {
500
- for (const route of routes) {
501
- const match = matchPattern(route.pattern, pathname);
502
- if (match) {
503
- return { route, params: match };
504
- }
505
- }
506
- return null;
507
- }
508
-
509
- function matchPattern(pattern: string, pathname: string): Record<string, string> | null {
510
- const patternParts = pattern.split('/').filter(Boolean);
511
- const pathnameParts = pathname.split('/').filter(Boolean);
512
-
513
- if (patternParts.length !== pathnameParts.length) {
514
- return null;
515
- }
516
-
517
- const params: Record<string, string> = {};
518
-
519
- for (let i = 0; i < patternParts.length; i++) {
520
- const patternPart = patternParts[i];
521
- const pathnamePart = pathnameParts[i];
522
-
523
- if (patternPart.startsWith(':')) {
524
- params[patternPart.slice(1)] = pathnamePart;
525
- } else if (patternPart !== pathnamePart) {
526
- return null;
527
- }
528
- }
529
-
530
- return params;
531
- }
532
- `;
533
- }
534
- async function listContentFiles(collectionDir) {
535
- try {
536
- const entries = await readdir2(collectionDir, { withFileTypes: true });
537
- return entries.filter((e) => e.isFile() && /\.(tsx|ts)$/.test(e.name) && !e.name.startsWith("_")).map((e) => e.name);
538
- } catch {
539
- return [];
540
- }
541
- }
542
- async function sha8(text) {
543
- const data = new TextEncoder().encode(text);
544
- const buf = await crypto.subtle.digest("SHA-256", data);
545
- let hex = "";
546
- for (const b of new Uint8Array(buf))
547
- hex += b.toString(16).padStart(2, "0");
548
- return hex.slice(0, 8);
549
- }
550
- async function buildContentChunks(cwd) {
551
- const routesRoot = join3(cwd, ROUTES_DIR);
552
- console.log(`[reroute/content] scan ${routesRoot}`);
553
- const collections = await readdir2(routesRoot, { withFileTypes: true });
554
- const results = [];
555
- for (const c of collections) {
556
- if (!c.isDirectory())
557
- continue;
558
- const collection = c.name;
559
- const contentDir = join3(routesRoot, collection, "content");
560
- console.log(`[reroute/content] collection ${collection} dir ${contentDir}`);
561
- const files = await listContentFiles(contentDir);
562
- console.log(`[reroute/content] files ${files.join(",")}`);
563
- if (!files.length)
564
- continue;
565
- for (const file of files) {
566
- const name = file.replace(/\.(tsx|ts)$/, "");
567
- const absSrc = join3(contentDir, file);
568
- let code = "";
569
- try {
570
- console.log(`[reroute/content] build ${absSrc}`);
571
- const result = await Bun.build({
572
- entrypoints: [absSrc],
573
- target: "browser",
574
- format: "esm",
575
- splitting: false,
576
- sourcemap: Bun.env.NODE_ENV === "production" ? "linked" : "none",
577
- minify: Bun.env.NODE_ENV === "production",
578
- define: {
579
- "process.env.NODE_ENV": Bun.env.NODE_ENV === "production" ? '"production"' : '"development"'
580
- }
581
- });
582
- if (!result.success)
583
- throw new Error("build failed");
584
- code = await result.outputs[0].text();
585
- } catch (e) {
586
- console.error("[reroute/gen] Failed to build content chunk:", absSrc, e);
587
- continue;
588
- }
589
- const hash = await sha8(code);
590
- const chunkRelDir = join3(".reroute", "chunks", collection);
591
- const chunkAbsDir = join3(cwd, chunkRelDir);
592
- const outFile = `${name}.${hash}.js`;
593
- const absOut = join3(chunkAbsDir, outFile);
594
- await mkdir2(chunkAbsDir, { recursive: true });
595
- try {
596
- const exists = await Bun.file(absOut).exists();
597
- if (!exists)
598
- await writeFile2(absOut, code, "utf-8");
599
- } catch {}
600
- let meta = {};
601
- try {
602
- console.log(`[reroute/content] meta ${absSrc}`);
603
- const url = `${pathToFileURL(absSrc).href}?t=${Date.now()}`;
604
- const m = await import(url);
605
- meta = m.meta || {};
606
- } catch {}
607
- results.push({
608
- collection,
609
- name,
610
- slug: name,
611
- href: `/${collection}/${name}`,
612
- moduleUrl: ("/" + chunkRelDir.replace(/\\/g, "/") + "/" + outFile).replace(/\\+/g, "/"),
613
- meta
614
- });
615
- }
616
- }
617
- const lines = [];
618
- lines.push("// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8");
619
- lines.push("/* eslint-disable */");
620
- lines.push("// @ts-nocheck");
621
- lines.push("");
622
- lines.push("export const contents = [");
623
- for (const e of results) {
624
- lines.push(" { collection: '" + e.collection + "', slug: '" + e.slug + "', name: '" + e.name + "', href: '" + e.href + "', module: '" + e.moduleUrl + "', meta: " + JSON.stringify(e.meta || {}) + " },");
625
- }
626
- lines.push("] as const;");
627
- lines.push("");
628
- lines.push("export const byCollection: Record<string, any[]> = {};");
629
- lines.push("for (const c of contents) { (byCollection[c.collection] ||= []).push(c as any); }");
630
- lines.push("");
631
- lines.push("export const byCollectionAndName: Record<string, Record<string, any>> = {};");
632
- lines.push("for (const c of contents) { ((byCollectionAndName[c.collection] ||= {})[c.name] = c as any); }");
633
- lines.push("");
634
- lines.push("export type Collections = keyof typeof byCollection;");
635
- lines.push("export type Names<C extends Collections> = keyof (typeof byCollectionAndName)[C];");
636
- lines.push("export type ContentEntry = (typeof contents)[number];");
637
- lines.push("");
638
- lines.push("export function getContentEntry<C extends string, N extends string>(collection: C, name: N) {");
639
- lines.push(" const m = (byCollectionAndName as any)[collection];");
640
- lines.push(" return m ? (m as Record<string, any>)[name] : undefined;");
641
- lines.push("}");
642
- lines.push("");
643
- await mkdir2(join3(cwd, ".reroute"), { recursive: true });
644
- await writeFile2(join3(cwd, OUTPUT_CONTENT_TS), lines.join(`
645
- `), "utf-8");
646
- console.log(`[reroute/content] wrote ${join3(cwd, OUTPUT_CONTENT_TS)}`);
647
- const collectionsSet = new Set(results.map((r) => r.collection));
648
- await mkdir2(join3(cwd, OUTPUT_COLLECTIONS_DIR), { recursive: true });
649
- for (const collection of collectionsSet) {
650
- const items = results.filter((r) => r.collection === collection);
651
- const js = [];
652
- js.push("// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8");
653
- js.push("");
654
- js.push("export const items = [");
655
- for (const e of items) {
656
- js.push(` { collection: '${e.collection}', slug: '${e.slug}', name: '${e.name}', href: '${e.href}', module: '${e.moduleUrl}', meta: ${JSON.stringify(e.meta || {})} },`);
657
- }
658
- js.push("];");
659
- js.push("");
660
- js.push("export const byName = {};");
661
- js.push("for (const it of items) { byName[it.name] = it; }");
662
- js.push("");
663
- js.push("export function get(collectionName, name) {");
664
- js.push(` if (collectionName !== '${collection}') return undefined;`);
665
- js.push(" return byName[name];");
666
- js.push("}");
667
- js.push("");
668
- await writeFile2(join3(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`), js.join(`
669
- `), "utf-8");
670
- console.log(`[reroute/content] wrote ${join3(cwd, OUTPUT_COLLECTIONS_DIR, `${collection}.js`)}`);
671
- }
672
- }
673
- async function generate(cwd) {
674
- console.log("[reroute/gen] Starting generation...");
675
- await cleanupOutputDir(cwd);
676
- const routesPath = join3(cwd, ROUTES_DIR);
677
- try {
678
- const files = await scanDirectory(routesPath);
679
- const nfFiles = await scan404Files(routesPath);
680
- const all = Array.from(new Set([...files, ...nfFiles]));
681
- const tree = generateRouteTree(all.map((f) => f.replace(/\\/g, "/")));
682
- const ts = generateTypeScript(tree);
683
- await mkdir2(join3(cwd, ".reroute"), { recursive: true });
684
- await writeFile2(join3(cwd, OUTPUT_ROUTES), ts, "utf-8");
685
- console.log(`[reroute/gen] Generated routes: ${join3(cwd, OUTPUT_ROUTES)}`);
686
- } catch (error) {
687
- console.error("[reroute/gen] Failed to generate routes:", error);
688
- throw error;
689
- }
690
- try {
691
- await buildContentChunks(cwd);
692
- console.log(`[reroute/gen] Generated content: ${join3(cwd, OUTPUT_CONTENT_TS)} + collections/*.js`);
693
- } catch (error) {
694
- console.error("[reroute/gen] Failed to generate content:", error);
695
- throw error;
696
- }
697
- const indexLines = [];
698
- indexLines.push("// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8");
699
- indexLines.push("/* eslint-disable */");
700
- indexLines.push("// @ts-nocheck");
701
- indexLines.push("");
702
- indexLines.push("import { layouts, matchRoute, notFoundRoutes } from './routes';");
703
- indexLines.push("");
704
- indexLines.push("export const artifacts = {");
705
- indexLines.push(" layouts,");
706
- indexLines.push(" matchRoute,");
707
- indexLines.push(" notFoundRoutes,");
708
- indexLines.push(" contentBaseUrl: '/.reroute/collections'");
709
- indexLines.push("} as const;");
710
- indexLines.push("");
711
- indexLines.push("export type RerouteArtifacts = typeof artifacts;");
712
- await writeFile2(join3(cwd, OUTPUT_INDEX), indexLines.join(`
713
- `), "utf-8");
714
- console.log(`[reroute/gen] Generated index: ${join3(cwd, OUTPUT_INDEX)}`);
715
- console.log("[reroute/gen] ✅ Generation complete!");
716
- }
717
- async function gen(args) {
718
- const cwd = process.cwd();
719
- const watchMode = args.includes("--watch") || args.includes("-w");
720
- if (!watchMode) {
721
- await generate(cwd);
722
- initTailwind(cwd);
723
- return;
724
- }
725
- console.log("[reroute/gen] Watch mode enabled");
726
- console.log("[reroute/gen] Initial generation...");
727
- await generate(cwd);
728
- try {
729
- await buildTailwind(cwd);
730
- } catch {}
731
- const notifyReload = async (reason) => {
732
- const ports = [
733
- Number(process.env.PORT || "0") || 0,
734
- Number(process.env.REROUTE_PORT || "0") || 0,
735
- 3001,
736
- 3000
737
- ].filter(Boolean);
738
- for (const p of ports) {
739
- try {
740
- await fetch(`http://localhost:${p}/__reroute_reload`, {
741
- method: "POST"
742
- });
743
- console.log(`[reroute/gen] reload notified (port ${p})${reason ? `: ${reason}` : ""}`);
744
- break;
745
- } catch {}
746
- }
747
- };
748
- const routesPath = join3(cwd, ROUTES_DIR);
749
- console.log(`[reroute/gen] Watching ${routesPath} for changes...`);
750
- let debounce = null;
751
- const routesWatcher = watch(routesPath, { recursive: true }, (_ev, filename) => {
752
- if (!filename)
753
- return;
754
- if (debounce)
755
- clearTimeout(debounce);
756
- debounce = setTimeout(async () => {
757
- console.log("[reroute/gen] Change detected, regenerating...");
758
- try {
759
- await generate(cwd);
760
- await buildTailwind(cwd);
761
- await notifyReload("routes change");
762
- } catch (e) {
763
- console.error("[reroute/gen] Error during regeneration:", e);
764
- }
765
- }, 120);
766
- });
767
- const clientPath = join3(cwd, "src", "client");
768
- console.log(`[reroute/gen] Watching ${clientPath} for Tailwind class changes...`);
769
- let twDebounce = null;
770
- const twWatcher = watch(clientPath, { recursive: true }, (_ev, filename) => {
771
- if (!filename)
772
- return;
773
- const name = String(filename);
774
- if (name.includes(".reroute") || name.includes("node_modules"))
775
- return;
776
- if (name.includes("routes/") || name.includes("routes\\"))
777
- return;
778
- if (!/\.(tsx|ts|jsx|js|html|md|mdx|css)$/.test(name))
779
- return;
780
- if (twDebounce)
781
- clearTimeout(twDebounce);
782
- twDebounce = setTimeout(async () => {
783
- try {
784
- await buildTailwind(cwd);
785
- await notifyReload("client change");
786
- } catch {}
787
- }, 150);
788
- });
789
- process.on("SIGINT", () => {
790
- console.log(`
791
- [reroute/gen] Stopping watch mode...`);
792
- try {
793
- routesWatcher.close();
794
- } catch {}
795
- try {
796
- twWatcher.close();
797
- } catch {}
798
- process.exit(0);
799
- });
800
- }
801
- var ROUTES_DIR = "src/client/routes", OUTPUT_DIR = ".reroute", OUTPUT_ROUTES = ".reroute/routes.ts", OUTPUT_CONTENT_TS = ".reroute/content.ts", OUTPUT_COLLECTIONS_DIR = ".reroute/collections", OUTPUT_INDEX = ".reroute/index.ts";
802
- var init_gen = __esm(() => {
803
- init_tailwind();
804
- });
805
-
806
- // packages/cli/src/cli.ts
807
- import path from "node:path";
808
- var commands = {
809
- init: () => Promise.resolve().then(() => (init_init(), exports_init)),
810
- build: () => Promise.resolve().then(() => exports_build),
811
- dev: () => Promise.resolve().then(() => exports_dev),
812
- gen: () => Promise.resolve().then(() => (init_gen(), exports_gen))
813
- };
814
- async function main() {
815
- const args = process.argv.slice(2);
816
- if (args[0] === "--version" || args[0] === "-v") {
817
- const version = await getVersion();
818
- console.log(version);
819
- process.exit(0);
820
- }
821
- if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
822
- printHelp2();
823
- process.exit(0);
824
- }
825
- const command = args[0];
826
- if (!commands[command]) {
827
- console.error(`Unknown command: ${command}`);
828
- console.error("");
829
- printHelp2();
830
- process.exit(1);
831
- }
832
- try {
833
- const module = await commands[command]();
834
- await module.default(args.slice(1));
835
- } catch (error) {
836
- console.error("Error executing command:", error);
837
- process.exit(1);
838
- }
839
- }
840
- function printHelp2() {
841
- console.log("Reroute CLI - File-based routing framework");
842
- console.log("");
843
- console.log("Usage:");
844
- console.log(" reroute <command> [options]");
845
- console.log("");
846
- console.log("Commands:");
847
- console.log(" gen Generate content registry and static assets");
848
- console.log(" init Scaffold a new Reroute project");
849
- console.log(" build Build for production");
850
- console.log(" dev Start development server");
851
- console.log("");
852
- console.log("Options:");
853
- console.log(" -h, --help Show help");
854
- console.log(" -v, --version Show version");
855
- console.log("");
856
- console.log("Examples:");
857
- console.log(" reroute gen");
858
- console.log(" reroute gen --watch");
859
- console.log(" reroute init my-app");
860
- console.log(" reroute build --minify");
861
- console.log(" reroute dev --port 3000");
862
- }
863
- async function getVersion() {
864
- const possiblePaths = [
865
- path.join(import.meta.dir, "../../../package.json"),
866
- path.join(import.meta.dir, "../package.json")
867
- ];
868
- for (const pkgPath of possiblePaths) {
869
- try {
870
- const pkg = await Bun.file(pkgPath).json();
871
- return pkg.version;
872
- } catch {}
873
- }
874
- return "unknown";
875
- }
876
- main();
877
-
878
- //# debugId=6AFDAF7BCD23E07864756E2164756E21