bosia 0.2.2 → 0.3.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 +39 -39
- package/package.json +56 -53
- package/src/ambient.d.ts +31 -0
- package/src/cli/add.ts +120 -114
- package/src/cli/build.ts +10 -10
- package/src/cli/create.ts +142 -137
- package/src/cli/dev.ts +8 -8
- package/src/cli/feat.ts +291 -132
- package/src/cli/index.ts +51 -42
- package/src/cli/registry.ts +136 -115
- package/src/cli/start.ts +17 -17
- package/src/cli/test.ts +25 -0
- package/src/core/build.ts +72 -56
- package/src/core/client/App.svelte +177 -153
- package/src/core/client/appState.svelte.ts +57 -0
- package/src/core/client/enhance.ts +112 -0
- package/src/core/client/hydrate.ts +97 -65
- package/src/core/client/prefetch.ts +101 -94
- package/src/core/client/router.svelte.ts +64 -51
- package/src/core/cookies.ts +70 -66
- package/src/core/cors.ts +44 -35
- package/src/core/csrf.ts +38 -38
- package/src/core/dedup.ts +17 -17
- package/src/core/dev.ts +165 -168
- package/src/core/env.ts +155 -128
- package/src/core/envCodegen.ts +73 -73
- package/src/core/errors.ts +48 -49
- package/src/core/hooks.ts +50 -50
- package/src/core/html.ts +192 -139
- package/src/core/matcher.ts +130 -121
- package/src/core/paths.ts +8 -10
- package/src/core/plugin.ts +113 -107
- package/src/core/prerender.ts +191 -118
- package/src/core/renderer.ts +359 -265
- package/src/core/routeFile.ts +140 -127
- package/src/core/routeTypes.ts +144 -83
- package/src/core/scanner.ts +125 -95
- package/src/core/server.ts +543 -370
- package/src/core/types.ts +25 -20
- package/src/lib/client.ts +12 -0
- package/src/lib/index.ts +8 -8
- package/src/lib/utils.ts +44 -30
- package/templates/default/.prettierignore +5 -0
- package/templates/default/.prettierrc.json +9 -0
- package/templates/default/README.md +5 -5
- package/templates/default/package.json +22 -18
- package/templates/default/src/app.css +80 -80
- package/templates/default/src/app.d.ts +3 -3
- package/templates/default/src/routes/+error.svelte +7 -10
- package/templates/default/src/routes/+layout.svelte +2 -2
- package/templates/default/src/routes/+page.svelte +31 -29
- package/templates/default/src/routes/about/+page.svelte +3 -3
- package/templates/default/tsconfig.json +20 -20
- package/templates/demo/.prettierignore +5 -0
- package/templates/demo/.prettierrc.json +9 -0
- package/templates/demo/README.md +9 -9
- package/templates/demo/package.json +22 -17
- package/templates/demo/src/app.css +80 -80
- package/templates/demo/src/app.d.ts +3 -3
- package/templates/demo/src/hooks.server.ts +9 -9
- package/templates/demo/src/routes/(public)/+layout.svelte +45 -23
- package/templates/demo/src/routes/(public)/+page.svelte +96 -67
- package/templates/demo/src/routes/(public)/about/+page.svelte +13 -25
- package/templates/demo/src/routes/(public)/all/[...catchall]/+page.svelte +24 -28
- package/templates/demo/src/routes/(public)/blog/+page.svelte +55 -46
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.server.ts +36 -38
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.svelte +60 -42
- package/templates/demo/src/routes/+error.svelte +10 -7
- package/templates/demo/src/routes/+layout.server.ts +4 -4
- package/templates/demo/src/routes/+layout.svelte +2 -2
- package/templates/demo/src/routes/actions-test/+page.server.ts +16 -16
- package/templates/demo/src/routes/actions-test/+page.svelte +49 -49
- package/templates/demo/src/routes/api/hello/+server.ts +25 -25
- package/templates/demo/tsconfig.json +20 -20
- package/templates/todo/.prettierignore +5 -0
- package/templates/todo/.prettierrc.json +9 -0
- package/templates/todo/README.md +9 -9
- package/templates/todo/package.json +22 -17
- package/templates/todo/src/app.css +80 -80
- package/templates/todo/src/app.d.ts +7 -7
- package/templates/todo/src/hooks.server.ts +9 -9
- package/templates/todo/src/routes/+error.svelte +10 -7
- package/templates/todo/src/routes/+layout.server.ts +4 -4
- package/templates/todo/src/routes/+layout.svelte +2 -2
- package/templates/todo/src/routes/+page.svelte +44 -44
- package/templates/todo/template.json +1 -1
- package/templates/todo/tsconfig.json +20 -20
package/src/core/scanner.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readdirSync, existsSync } from "fs";
|
|
1
|
+
import { readdirSync, existsSync, readFileSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
-
import type { PageRoute, ApiRoute, RouteManifest } from "./types.ts";
|
|
3
|
+
import type { PageRoute, ApiRoute, RouteManifest, TrailingSlash } from "./types.ts";
|
|
4
4
|
|
|
5
5
|
// ─── Route Scanner ───────────────────────────────────────
|
|
6
6
|
// Walks src/routes/ and produces a RouteManifest.
|
|
@@ -17,101 +17,131 @@ import type { PageRoute, ApiRoute, RouteManifest } from "./types.ts";
|
|
|
17
17
|
|
|
18
18
|
const ROUTES_DIR = "./src/routes";
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Extract `export const trailingSlash = '...'` from a server module file via
|
|
22
|
+
* regex. Static-string read only — runtime expressions return null. Build-time
|
|
23
|
+
* scan avoids invoking server modules during the client bundle.
|
|
24
|
+
*/
|
|
25
|
+
function readTrailingSlash(filePath: string): TrailingSlash | null {
|
|
26
|
+
try {
|
|
27
|
+
const src = readFileSync(filePath, "utf-8");
|
|
28
|
+
const m = src.match(
|
|
29
|
+
/export\s+const\s+trailingSlash\s*(?::\s*[^=]+)?=\s*["'](never|always|ignore)["']/,
|
|
30
|
+
);
|
|
31
|
+
return (m?.[1] ?? null) as TrailingSlash | null;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
20
37
|
export function scanRoutes(): RouteManifest {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
38
|
+
const pages: PageRoute[] = [];
|
|
39
|
+
const apis: ApiRoute[] = [];
|
|
40
|
+
|
|
41
|
+
function walk(
|
|
42
|
+
dir: string,
|
|
43
|
+
urlSegments: string[],
|
|
44
|
+
layoutChain: string[],
|
|
45
|
+
layoutServerChain: { path: string; depth: number }[],
|
|
46
|
+
inheritedTrailingSlash: TrailingSlash,
|
|
47
|
+
) {
|
|
48
|
+
const fullDir = join(ROUTES_DIR, dir);
|
|
49
|
+
if (!existsSync(fullDir)) return;
|
|
50
|
+
|
|
51
|
+
const items = readdirSync(fullDir, { withFileTypes: true });
|
|
52
|
+
|
|
53
|
+
// Accumulate layouts for this level
|
|
54
|
+
const currentLayouts = [...layoutChain];
|
|
55
|
+
const currentLayoutServers = [...layoutServerChain];
|
|
56
|
+
let currentTrailingSlash = inheritedTrailingSlash;
|
|
57
|
+
|
|
58
|
+
if (items.some((i) => i.isFile() && i.name === "+layout.svelte")) {
|
|
59
|
+
currentLayouts.push(join(dir, "+layout.svelte"));
|
|
60
|
+
}
|
|
61
|
+
if (items.some((i) => i.isFile() && i.name === "+layout.server.ts")) {
|
|
62
|
+
const layoutServerPath = join(dir, "+layout.server.ts");
|
|
63
|
+
currentLayoutServers.push({
|
|
64
|
+
path: layoutServerPath,
|
|
65
|
+
depth: currentLayouts.length - 1,
|
|
66
|
+
});
|
|
67
|
+
const ts = readTrailingSlash(join(ROUTES_DIR, layoutServerPath));
|
|
68
|
+
if (ts) currentTrailingSlash = ts;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// API route (+server.ts)
|
|
72
|
+
if (items.some((i) => i.isFile() && i.name === "+server.ts")) {
|
|
73
|
+
apis.push({
|
|
74
|
+
pattern: toUrlPath(urlSegments),
|
|
75
|
+
server: join(dir, "+server.ts"),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Page route (+page.svelte)
|
|
80
|
+
if (items.some((i) => i.isFile() && i.name === "+page.svelte")) {
|
|
81
|
+
const pageServerFile = items.some((i) => i.isFile() && i.name === "+page.server.ts")
|
|
82
|
+
? join(dir, "+page.server.ts")
|
|
83
|
+
: null;
|
|
84
|
+
|
|
85
|
+
const pageTs = pageServerFile
|
|
86
|
+
? readTrailingSlash(join(ROUTES_DIR, pageServerFile))
|
|
87
|
+
: null;
|
|
88
|
+
const effectiveTs: TrailingSlash = pageTs ?? currentTrailingSlash;
|
|
89
|
+
|
|
90
|
+
pages.push({
|
|
91
|
+
pattern: toUrlPath(urlSegments),
|
|
92
|
+
page: join(dir, "+page.svelte"),
|
|
93
|
+
layouts: [...currentLayouts],
|
|
94
|
+
pageServer: pageServerFile,
|
|
95
|
+
layoutServers: [...currentLayoutServers],
|
|
96
|
+
trailingSlash: effectiveTs,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Recurse into subdirectories
|
|
101
|
+
for (const entry of items) {
|
|
102
|
+
if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules")
|
|
103
|
+
continue;
|
|
104
|
+
|
|
105
|
+
const dirName = entry.name;
|
|
106
|
+
// Route groups like (public), (auth) are invisible in URLs
|
|
107
|
+
const isGroup = /^\(.*\)$/.test(dirName);
|
|
108
|
+
|
|
109
|
+
walk(
|
|
110
|
+
dir ? join(dir, dirName) : dirName,
|
|
111
|
+
isGroup ? [...urlSegments] : [...urlSegments, dirName],
|
|
112
|
+
currentLayouts,
|
|
113
|
+
currentLayoutServers,
|
|
114
|
+
currentTrailingSlash,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
walk("", [], [], [], "never");
|
|
120
|
+
|
|
121
|
+
// Warn when a catch-all exists but no exact route covers its prefix.
|
|
122
|
+
// e.g. "/[...slug]" matches everything EXCEPT "/" (which needs its own +page.svelte).
|
|
123
|
+
const exactPatterns = new Set(
|
|
124
|
+
pages.filter((p) => !p.pattern.includes("[")).map((p) => p.pattern),
|
|
125
|
+
);
|
|
126
|
+
for (const p of pages) {
|
|
127
|
+
const m = p.pattern.match(/^(.*?)\/\[\.\.\.(\w+)\]$/);
|
|
128
|
+
if (m) {
|
|
129
|
+
const exactEquivalent = m[1] || "/";
|
|
130
|
+
if (!exactPatterns.has(exactEquivalent)) {
|
|
131
|
+
console.warn(
|
|
132
|
+
`⚠️ No exact route for "${exactEquivalent}" — the catch-all "${p.pattern}" will NOT match it.\n` +
|
|
133
|
+
` Add a +page.svelte at the "${exactEquivalent}" level to serve that URL.`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const errorPage = existsSync(join(ROUTES_DIR, "+error.svelte")) ? "+error.svelte" : null;
|
|
140
|
+
|
|
141
|
+
return { pages, apis, errorPage };
|
|
112
142
|
}
|
|
113
143
|
|
|
114
144
|
function toUrlPath(segments: string[]): string {
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
if (segments.length === 0) return "/";
|
|
146
|
+
return "/" + segments.join("/");
|
|
117
147
|
}
|