effect-start 0.19.0 → 0.20.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 +3 -3
- package/dist/Development.d.ts +3 -3
- package/dist/Development.js +3 -2
- package/dist/Effectify.d.ts +212 -0
- package/dist/Effectify.js +19 -0
- package/dist/FilePathPattern.d.ts +29 -0
- package/dist/FilePathPattern.js +86 -0
- package/dist/FileRouter.d.ts +39 -41
- package/dist/FileRouter.js +104 -158
- package/dist/FileRouterCodegen.d.ts +7 -8
- package/dist/FileRouterCodegen.js +97 -66
- package/dist/PlatformError.d.ts +46 -0
- package/dist/PlatformError.js +43 -0
- package/dist/PlatformRuntime.d.ts +23 -0
- package/dist/PlatformRuntime.js +42 -0
- package/dist/RouteBody.d.ts +1 -1
- package/dist/Start.d.ts +34 -3
- package/dist/Start.js +31 -6
- package/dist/bun/BunPlatformHttpServer.d.ts +10 -0
- package/dist/bun/BunPlatformHttpServer.js +53 -0
- package/dist/bun/BunRoute.d.ts +3 -5
- package/dist/bun/BunRoute.js +9 -17
- package/dist/bun/BunRuntime.d.ts +2 -1
- package/dist/bun/BunRuntime.js +10 -5
- package/dist/bun/BunServer.d.ts +33 -0
- package/dist/bun/BunServer.js +133 -0
- package/dist/bun/BunServerRequest.d.ts +60 -0
- package/dist/bun/BunServerRequest.js +252 -0
- package/dist/bun/index.d.ts +1 -1
- package/dist/bun/index.js +1 -1
- package/dist/datastar/actions/fetch.d.ts +30 -0
- package/dist/datastar/actions/fetch.js +411 -0
- package/dist/datastar/actions/peek.d.ts +1 -0
- package/dist/datastar/actions/peek.js +14 -0
- package/dist/datastar/actions/setAll.d.ts +1 -0
- package/dist/datastar/actions/setAll.js +13 -0
- package/dist/datastar/actions/toggleAll.d.ts +1 -0
- package/dist/datastar/actions/toggleAll.js +13 -0
- package/dist/datastar/attributes/attr.d.ts +1 -0
- package/dist/datastar/attributes/attr.js +49 -0
- package/dist/datastar/attributes/bind.d.ts +1 -0
- package/dist/datastar/attributes/bind.js +183 -0
- package/dist/datastar/attributes/class.d.ts +1 -0
- package/dist/datastar/attributes/class.js +50 -0
- package/dist/datastar/attributes/computed.d.ts +1 -0
- package/dist/datastar/attributes/computed.js +27 -0
- package/dist/datastar/attributes/effect.d.ts +1 -0
- package/dist/datastar/attributes/effect.js +10 -0
- package/dist/datastar/attributes/indicator.d.ts +1 -0
- package/dist/datastar/attributes/indicator.js +32 -0
- package/dist/datastar/attributes/init.d.ts +1 -0
- package/dist/datastar/attributes/init.js +27 -0
- package/dist/datastar/attributes/jsonSignals.d.ts +1 -0
- package/dist/datastar/attributes/jsonSignals.js +31 -0
- package/dist/datastar/attributes/on.d.ts +1 -0
- package/dist/datastar/attributes/on.js +59 -0
- package/dist/datastar/attributes/onIntersect.d.ts +1 -0
- package/dist/datastar/attributes/onIntersect.js +54 -0
- package/dist/datastar/attributes/onInterval.d.ts +1 -0
- package/dist/datastar/attributes/onInterval.js +31 -0
- package/dist/datastar/attributes/onSignalPatch.d.ts +1 -0
- package/dist/datastar/attributes/onSignalPatch.js +44 -0
- package/dist/datastar/attributes/ref.d.ts +1 -0
- package/dist/datastar/attributes/ref.js +11 -0
- package/dist/datastar/attributes/show.d.ts +1 -0
- package/dist/datastar/attributes/show.js +32 -0
- package/dist/datastar/attributes/signals.d.ts +1 -0
- package/dist/datastar/attributes/signals.js +18 -0
- package/dist/datastar/attributes/style.d.ts +1 -0
- package/dist/datastar/attributes/style.js +56 -0
- package/dist/datastar/attributes/text.d.ts +1 -0
- package/dist/datastar/attributes/text.js +27 -0
- package/dist/datastar/engine.d.ts +156 -0
- package/dist/datastar/engine.js +971 -0
- package/dist/datastar/index.d.ts +24 -0
- package/dist/datastar/index.js +24 -0
- package/dist/datastar/load.d.ts +24 -0
- package/dist/datastar/load.js +24 -0
- package/dist/datastar/utils.d.ts +51 -0
- package/dist/datastar/utils.js +205 -0
- package/dist/datastar/watchers/patchElements.d.ts +1 -0
- package/dist/datastar/watchers/patchElements.js +420 -0
- package/dist/datastar/watchers/patchSignals.d.ts +1 -0
- package/dist/datastar/watchers/patchSignals.js +15 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node/NodeFileSystem.d.ts +7 -0
- package/dist/node/NodeFileSystem.js +420 -0
- package/dist/node/NodeUtils.d.ts +2 -0
- package/dist/node/NodeUtils.js +20 -0
- package/dist/x/tailwind/plugin.js +1 -1
- package/package.json +11 -7
- package/src/Development.ts +26 -25
- package/src/{node/Effectify.ts → Effectify.ts} +10 -3
- package/src/FilePathPattern.ts +115 -0
- package/src/FileRouter.ts +178 -255
- package/src/FileRouterCodegen.ts +135 -92
- package/src/{node/PlatformError.ts → PlatformError.ts} +34 -19
- package/src/PlatformRuntime.ts +97 -0
- package/src/RouteBody.ts +1 -1
- package/src/RouteHttp.ts +3 -1
- package/src/Start.ts +62 -14
- package/src/bun/BunPlatformHttpServer.ts +88 -0
- package/src/bun/BunRoute.ts +12 -22
- package/src/bun/BunRuntime.ts +21 -5
- package/src/bun/BunServer.ts +228 -0
- package/src/bun/index.ts +1 -1
- package/src/datastar/README.md +18 -0
- package/src/datastar/actions/fetch.ts +609 -0
- package/src/datastar/actions/peek.ts +17 -0
- package/src/datastar/actions/setAll.ts +20 -0
- package/src/datastar/actions/toggleAll.ts +20 -0
- package/src/datastar/attributes/attr.ts +50 -0
- package/src/datastar/attributes/bind.ts +220 -0
- package/src/datastar/attributes/class.ts +57 -0
- package/src/datastar/attributes/computed.ts +33 -0
- package/src/datastar/attributes/effect.ts +11 -0
- package/src/datastar/attributes/indicator.ts +39 -0
- package/src/datastar/attributes/init.ts +35 -0
- package/src/datastar/attributes/jsonSignals.ts +38 -0
- package/src/datastar/attributes/on.ts +71 -0
- package/src/datastar/attributes/onIntersect.ts +65 -0
- package/src/datastar/attributes/onInterval.ts +39 -0
- package/src/datastar/attributes/onSignalPatch.ts +63 -0
- package/src/datastar/attributes/ref.ts +12 -0
- package/src/datastar/attributes/show.ts +33 -0
- package/src/datastar/attributes/signals.ts +22 -0
- package/src/datastar/attributes/style.ts +63 -0
- package/src/datastar/attributes/text.ts +30 -0
- package/src/datastar/engine.ts +1341 -0
- package/src/datastar/index.ts +25 -0
- package/src/datastar/utils.ts +286 -0
- package/src/datastar/watchers/patchElements.ts +554 -0
- package/src/datastar/watchers/patchSignals.ts +15 -0
- package/src/index.ts +1 -1
- package/src/node/{FileSystem.ts → NodeFileSystem.ts} +2 -2
- package/src/node/{Utils.ts → NodeUtils.ts} +2 -0
- package/src/x/tailwind/plugin.ts +1 -1
- package/src/FileRouterCodegen.todo.ts +0 -1133
- package/src/FileRouterPattern.ts +0 -59
- package/src/RouterPattern.ts +0 -416
- package/src/StartApp.ts +0 -47
- package/src/bun/BunHttpServer.ts +0 -303
- /package/src/bun/{BunHttpServer_web.ts → BunServerRequest.ts} +0 -0
package/src/FileRouterPattern.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import * as RouterPattern from "./RouterPattern.ts"
|
|
2
|
-
|
|
3
|
-
export type GroupSegment<
|
|
4
|
-
Name extends string = string,
|
|
5
|
-
> = {
|
|
6
|
-
_tag: "GroupSegment"
|
|
7
|
-
name: Name
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type Segment =
|
|
11
|
-
| RouterPattern.Segment
|
|
12
|
-
| GroupSegment
|
|
13
|
-
|
|
14
|
-
export function parse(pattern: string): Segment[] {
|
|
15
|
-
const trimmedPath = pattern.replace(/(^\/)|(\/$)/g, "")
|
|
16
|
-
|
|
17
|
-
if (trimmedPath === "") {
|
|
18
|
-
return []
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const segmentStrings = trimmedPath
|
|
22
|
-
.split("/")
|
|
23
|
-
.filter(s => s !== "")
|
|
24
|
-
|
|
25
|
-
if (segmentStrings.length === 0) {
|
|
26
|
-
return []
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const segments: (Segment | null)[] = segmentStrings.map(
|
|
30
|
-
(s): Segment | null => {
|
|
31
|
-
// (group) - Groups (FileRouter-specific)
|
|
32
|
-
const groupMatch = s.match(/^\((\w+)\)$/)
|
|
33
|
-
if (groupMatch) {
|
|
34
|
-
return { _tag: "GroupSegment", name: groupMatch[1] }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Delegate to RouterPattern for all other segment types
|
|
38
|
-
return RouterPattern.parseSegment(s)
|
|
39
|
-
},
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
if (segments.some((seg) => seg === null)) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`Invalid path segment in "${pattern}": contains invalid characters or format`,
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return segments as Segment[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function formatSegment(seg: Segment): string {
|
|
52
|
-
if (seg._tag === "GroupSegment") return `(${seg.name})`
|
|
53
|
-
return RouterPattern.formatSegment(seg)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function format(segments: Segment[]): `/${string}` {
|
|
57
|
-
const joined = segments.map(formatSegment).join("/")
|
|
58
|
-
return (joined ? `/${joined}` : "/") as `/${string}`
|
|
59
|
-
}
|
package/src/RouterPattern.ts
DELETED
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
export type RouterPattern = `/${string}`
|
|
2
|
-
|
|
3
|
-
export type ParamDelimiter = "_" | "-" | "." | "," | ";" | "!" | "@" | "~"
|
|
4
|
-
export type ParamPrefix = `${string}${ParamDelimiter}` | ""
|
|
5
|
-
export type ParamSuffix = `${ParamDelimiter}${string}` | ""
|
|
6
|
-
|
|
7
|
-
export type LiteralSegment<
|
|
8
|
-
Value extends string = string,
|
|
9
|
-
> = {
|
|
10
|
-
_tag: "LiteralSegment"
|
|
11
|
-
value: Value
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type ParamSegment<
|
|
15
|
-
Name extends string = string,
|
|
16
|
-
Optional extends boolean = boolean,
|
|
17
|
-
Prefix extends ParamPrefix = "",
|
|
18
|
-
Suffix extends ParamSuffix = "",
|
|
19
|
-
> = {
|
|
20
|
-
_tag: "ParamSegment"
|
|
21
|
-
name: Name
|
|
22
|
-
optional?: Optional
|
|
23
|
-
prefix?: Prefix
|
|
24
|
-
suffix?: Suffix
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type RestSegment<
|
|
28
|
-
Name extends string = string,
|
|
29
|
-
Optional extends boolean = boolean,
|
|
30
|
-
> = {
|
|
31
|
-
_tag: "RestSegment"
|
|
32
|
-
name: Name
|
|
33
|
-
optional?: Optional
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type Segment =
|
|
37
|
-
| LiteralSegment
|
|
38
|
-
| ParamSegment<
|
|
39
|
-
string,
|
|
40
|
-
boolean,
|
|
41
|
-
ParamPrefix,
|
|
42
|
-
ParamSuffix
|
|
43
|
-
>
|
|
44
|
-
| RestSegment
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Parses a route path string into a tuple of Segment types at compile time.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* type Usage = Segments<"/users/[id]/posts/[...rest]">
|
|
52
|
-
* type Expected = [
|
|
53
|
-
* LiteralSegment<"users">,
|
|
54
|
-
* ParamSegment<"id", false>,
|
|
55
|
-
* LiteralSegment<"posts">,
|
|
56
|
-
* RestSegment<"rest", false>
|
|
57
|
-
* ]
|
|
58
|
-
* ```
|
|
59
|
-
*
|
|
60
|
-
* Supports:
|
|
61
|
-
* - Literals: `users` → `LiteralSegment<"users">`
|
|
62
|
-
* - Params: `[id]` → `ParamSegment<"id", false>`
|
|
63
|
-
* - Params (optional): `[[id]]` → `ParamSegment<"id", true>`
|
|
64
|
-
* - Rest: `[...rest]` → `RestSegment<"rest", false>`
|
|
65
|
-
* - Rest (optional): `[[...rest]]` → `RestSegment<"rest", true>`
|
|
66
|
-
* - {Pre,Suf}fixed params: `prefix_[id]_suffix` → `ParamSegment<"id", false, "prefix_", "_suffix">`
|
|
67
|
-
* - Malformed segments: `pk_[id]foo` → `undefined` (suffix must start with delimiter)
|
|
68
|
-
*
|
|
69
|
-
* @limit Paths with more than 48 segments in TypeScript 5.9.3 will fail with
|
|
70
|
-
* `TS2589: Type instantiation is excessively deep and possibly infinite`.
|
|
71
|
-
*/
|
|
72
|
-
export type Segments<Path extends string> = Path extends `/${infer PathRest}`
|
|
73
|
-
? Segments<PathRest>
|
|
74
|
-
: Path extends `${infer Head}/${infer Tail}`
|
|
75
|
-
? [ExtractSegment<Head>, ...Segments<Tail>]
|
|
76
|
-
: Path extends "" ? []
|
|
77
|
-
: [ExtractSegment<Path>]
|
|
78
|
-
|
|
79
|
-
const PARAM_PATTERN =
|
|
80
|
-
/^(?<prefix>.*[^a-zA-Z0-9])?\[(?<name>[^\]]+)\](?<suffix>[^a-zA-Z0-9].*)?$/
|
|
81
|
-
|
|
82
|
-
export function parseSegment(segment: string): Segment | null {
|
|
83
|
-
if (
|
|
84
|
-
segment.startsWith("[[...")
|
|
85
|
-
&& segment.endsWith("]]")
|
|
86
|
-
) {
|
|
87
|
-
return {
|
|
88
|
-
_tag: "RestSegment",
|
|
89
|
-
name: segment.slice(5, -2),
|
|
90
|
-
optional: true,
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
segment.startsWith("[...")
|
|
96
|
-
&& segment.endsWith("]")
|
|
97
|
-
) {
|
|
98
|
-
return {
|
|
99
|
-
_tag: "RestSegment",
|
|
100
|
-
name: segment.slice(4, -1),
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
segment.startsWith("[[")
|
|
106
|
-
&& segment.endsWith("]]")
|
|
107
|
-
) {
|
|
108
|
-
return {
|
|
109
|
-
_tag: "ParamSegment",
|
|
110
|
-
name: segment.slice(2, -2),
|
|
111
|
-
optional: true,
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const match = segment.match(PARAM_PATTERN)
|
|
116
|
-
if (match?.groups) {
|
|
117
|
-
const { prefix, name, suffix } = match.groups
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
_tag: "ParamSegment",
|
|
121
|
-
name,
|
|
122
|
-
prefix: (prefix as ParamPrefix) || undefined,
|
|
123
|
-
suffix: (suffix as ParamSuffix) || undefined,
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (/^[\p{L}\p{N}._~-]+$/u.test(segment)) {
|
|
128
|
-
return { _tag: "LiteralSegment", value: segment }
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return null
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function parse(pattern: string): Segment[] {
|
|
135
|
-
const segments = pattern.split("/").filter(Boolean).map(parseSegment)
|
|
136
|
-
|
|
137
|
-
if (segments.some((seg) => seg === null)) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
`Invalid path segment in "${pattern}": contains invalid characters or format`,
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return segments as Segment[]
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function formatSegment(seg: Segment): string {
|
|
147
|
-
switch (seg._tag) {
|
|
148
|
-
case "LiteralSegment":
|
|
149
|
-
return seg.value
|
|
150
|
-
case "ParamSegment": {
|
|
151
|
-
const param = seg.optional ? `[[${seg.name}]]` : `[${seg.name}]`
|
|
152
|
-
return (seg.prefix ?? "") + param + (seg.suffix ?? "")
|
|
153
|
-
}
|
|
154
|
-
case "RestSegment":
|
|
155
|
-
return seg.optional ? `[[...${seg.name}]]` : `[...${seg.name}]`
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function format(segments: Segment[]): `/${string}` {
|
|
160
|
-
const joined = segments.map(formatSegment).join("/")
|
|
161
|
-
return (joined ? `/${joined}` : "/") as `/${string}`
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function buildPaths(
|
|
165
|
-
segments: Segment[],
|
|
166
|
-
mapper: (seg: Segment) => string,
|
|
167
|
-
restWildcard: string,
|
|
168
|
-
): string[] {
|
|
169
|
-
const optionalRestIndex = segments.findIndex(
|
|
170
|
-
(s) => s._tag === "RestSegment" && s.optional,
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
if (optionalRestIndex !== -1) {
|
|
174
|
-
const before = segments.slice(0, optionalRestIndex)
|
|
175
|
-
const beforeJoined = before.map(mapper).join("/")
|
|
176
|
-
const basePath = beforeJoined ? "/" + beforeJoined : "/"
|
|
177
|
-
const withWildcard = basePath === "/"
|
|
178
|
-
? restWildcard
|
|
179
|
-
: basePath + restWildcard
|
|
180
|
-
return [basePath, withWildcard]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const joined = segments.map(mapper).join("/")
|
|
184
|
-
return [joined ? "/" + joined : "/"]
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function colonParamSegment(segment: Segment): string {
|
|
188
|
-
switch (segment._tag) {
|
|
189
|
-
case "LiteralSegment":
|
|
190
|
-
return segment.value
|
|
191
|
-
case "ParamSegment": {
|
|
192
|
-
const param = `:${segment.name}${segment.optional ? "?" : ""}`
|
|
193
|
-
return (segment.prefix ?? "") + param + (segment.suffix ?? "")
|
|
194
|
-
}
|
|
195
|
-
case "RestSegment":
|
|
196
|
-
return "*"
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Converts to colon-style path pattern (used by Hono, Bun, itty-router).
|
|
202
|
-
*
|
|
203
|
-
* - `[param]` → `:param`
|
|
204
|
-
* - `[[param]]` → `:param?`
|
|
205
|
-
* - `[...param]` → `*`
|
|
206
|
-
* - `[[...param]]` → `/`, `/*`
|
|
207
|
-
* - `pk_[id]` → `pk_:id`
|
|
208
|
-
*/
|
|
209
|
-
export function toColon(path: RouterPattern): string[] {
|
|
210
|
-
return buildPaths(parse(path), colonParamSegment, "/*")
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export const toHono = toColon
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Converts to Express path pattern.
|
|
217
|
-
*
|
|
218
|
-
* - `[param]` → `:param`
|
|
219
|
-
* - `[[param]]` → `{/:param}`
|
|
220
|
-
* - `[...param]` → `/*param`
|
|
221
|
-
* - `[[...param]]` → `/`, `/*param`
|
|
222
|
-
* - `pk_[id]` → `pk_:id`
|
|
223
|
-
*/
|
|
224
|
-
export function toExpress(path: RouterPattern): string[] {
|
|
225
|
-
const segments = parse(path)
|
|
226
|
-
const optionalRestIndex = segments.findIndex(
|
|
227
|
-
(s) => s._tag === "RestSegment" && s.optional,
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
const mapper = (segment: Segment): string => {
|
|
231
|
-
switch (segment._tag) {
|
|
232
|
-
case "LiteralSegment":
|
|
233
|
-
return segment.value
|
|
234
|
-
case "ParamSegment": {
|
|
235
|
-
const param = `:${segment.name}`
|
|
236
|
-
return (segment.prefix ?? "") + param + (segment.suffix ?? "")
|
|
237
|
-
}
|
|
238
|
-
case "RestSegment":
|
|
239
|
-
return `*${segment.name}`
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (optionalRestIndex !== -1) {
|
|
244
|
-
const before = segments.slice(0, optionalRestIndex)
|
|
245
|
-
const rest = segments[optionalRestIndex]
|
|
246
|
-
if (rest._tag !== "RestSegment") throw new Error("unreachable")
|
|
247
|
-
const restName = rest.name
|
|
248
|
-
const beforeJoined = before.map(mapper).join("/")
|
|
249
|
-
const basePath = beforeJoined ? "/" + beforeJoined : "/"
|
|
250
|
-
const withWildcard = basePath === "/"
|
|
251
|
-
? `/*${restName}`
|
|
252
|
-
: basePath + `/*${restName}`
|
|
253
|
-
return [basePath, withWildcard]
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
let result = ""
|
|
257
|
-
for (let i = 0; i < segments.length; i++) {
|
|
258
|
-
const segment = segments[i]
|
|
259
|
-
const isFirst = i === 0
|
|
260
|
-
switch (segment._tag) {
|
|
261
|
-
case "LiteralSegment":
|
|
262
|
-
result += "/" + segment.value
|
|
263
|
-
break
|
|
264
|
-
case "ParamSegment":
|
|
265
|
-
if (segment.optional && !segment.prefix && !segment.suffix) {
|
|
266
|
-
result += isFirst
|
|
267
|
-
? "/{/:$name}".replace("$name", segment.name)
|
|
268
|
-
: `{/:${segment.name}}`
|
|
269
|
-
} else {
|
|
270
|
-
const param = `:${segment.name}`
|
|
271
|
-
result += "/"
|
|
272
|
-
+ (segment.prefix ?? "")
|
|
273
|
-
+ param
|
|
274
|
-
+ (segment.suffix ?? "")
|
|
275
|
-
}
|
|
276
|
-
break
|
|
277
|
-
case "RestSegment":
|
|
278
|
-
result += `/*${segment.name}`
|
|
279
|
-
break
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return [result || "/"]
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Converts to Effect HttpRouter/find-my-way path pattern.
|
|
287
|
-
*
|
|
288
|
-
* - `[param]` → `:param`
|
|
289
|
-
* - `[[param]]` → `:param?` (must be final segment)
|
|
290
|
-
* - `[...param]` → `*`
|
|
291
|
-
* - `[[...param]]` → `/`, `/*`
|
|
292
|
-
* - `pk_[id]` → `pk_:id`
|
|
293
|
-
*/
|
|
294
|
-
export function toEffect(path: RouterPattern): string[] {
|
|
295
|
-
return buildPaths(parse(path), colonParamSegment, "/*")
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Converts to URLPattern path pattern.
|
|
300
|
-
*
|
|
301
|
-
* - `[param]` → `:param`
|
|
302
|
-
* - `[[param]]` → `:param?`
|
|
303
|
-
* - `[...param]` → `:param+`
|
|
304
|
-
* - `[[...param]]` → `:param*`
|
|
305
|
-
* - `pk_[id]` → `pk_:id`
|
|
306
|
-
*/
|
|
307
|
-
export function toURLPattern(path: RouterPattern): string[] {
|
|
308
|
-
const segments = parse(path)
|
|
309
|
-
const joined = segments
|
|
310
|
-
.map((segment) => {
|
|
311
|
-
switch (segment._tag) {
|
|
312
|
-
case "LiteralSegment":
|
|
313
|
-
return segment.value
|
|
314
|
-
case "ParamSegment": {
|
|
315
|
-
const param = `:${segment.name}${segment.optional ? "?" : ""}`
|
|
316
|
-
return (segment.prefix ?? "") + param + (segment.suffix ?? "")
|
|
317
|
-
}
|
|
318
|
-
case "RestSegment":
|
|
319
|
-
return `:${segment.name}${segment.optional ? "*" : "+"}`
|
|
320
|
-
}
|
|
321
|
-
})
|
|
322
|
-
.join("/")
|
|
323
|
-
return [joined ? "/" + joined : "/"]
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Converts to Remix path pattern.
|
|
328
|
-
*
|
|
329
|
-
* - `[param]` → `$param`
|
|
330
|
-
* - `[[param]]` → `($param)`
|
|
331
|
-
* - `[...param]` → `$`
|
|
332
|
-
* - `[[...param]]` → `/`, `$`
|
|
333
|
-
* - `pk_[id]` → (not supported, emits `pk_$id`)
|
|
334
|
-
*/
|
|
335
|
-
export function toRemix(path: RouterPattern): string[] {
|
|
336
|
-
const segments = parse(path)
|
|
337
|
-
const optionalRestIndex = segments.findIndex(
|
|
338
|
-
(s) => s._tag === "RestSegment" && s.optional,
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
const mapper = (segment: Segment): string => {
|
|
342
|
-
switch (segment._tag) {
|
|
343
|
-
case "LiteralSegment":
|
|
344
|
-
return segment.value
|
|
345
|
-
case "ParamSegment": {
|
|
346
|
-
const param = segment.optional
|
|
347
|
-
? `($${segment.name})`
|
|
348
|
-
: `$${segment.name}`
|
|
349
|
-
return (segment.prefix ?? "") + param + (segment.suffix ?? "")
|
|
350
|
-
}
|
|
351
|
-
case "RestSegment":
|
|
352
|
-
return "$"
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (optionalRestIndex !== -1) {
|
|
357
|
-
const before = segments.slice(0, optionalRestIndex)
|
|
358
|
-
const beforeJoined = before.map(mapper).join("/")
|
|
359
|
-
const basePath = beforeJoined ? "/" + beforeJoined : "/"
|
|
360
|
-
const withWildcard = basePath === "/" ? "$" : basePath + "/$"
|
|
361
|
-
return [basePath, withWildcard]
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const joined = segments.map(mapper).join("/")
|
|
365
|
-
return [joined ? "/" + joined : "/"]
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Converts to Bun.serve path pattern.
|
|
370
|
-
*
|
|
371
|
-
* Since Bun doesn't support optional params (`:param?`), optional segments
|
|
372
|
-
* are expanded into multiple routes recursively.
|
|
373
|
-
*
|
|
374
|
-
* - `[param]` → `:param`
|
|
375
|
-
* - `[[param]]` → `/`, `/:param` (two routes)
|
|
376
|
-
* - `[...param]` → `*`
|
|
377
|
-
* - `[[...param]]` → `/`, `/*` (two routes)
|
|
378
|
-
* - `pk_[id]` → `pk_:id`
|
|
379
|
-
*/
|
|
380
|
-
export function toBun(path: RouterPattern): string[] {
|
|
381
|
-
const segments = parse(path)
|
|
382
|
-
|
|
383
|
-
const optionalIndex = segments.findIndex(
|
|
384
|
-
(s) =>
|
|
385
|
-
(s._tag === "ParamSegment" || s._tag === "RestSegment") && s.optional,
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
if (optionalIndex === -1) {
|
|
389
|
-
return buildPaths(segments, colonParamSegment, "/*")
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const before = segments.slice(0, optionalIndex)
|
|
393
|
-
const optional = { ...segments[optionalIndex], optional: false }
|
|
394
|
-
const after = segments.slice(optionalIndex + 1)
|
|
395
|
-
|
|
396
|
-
return [
|
|
397
|
-
...toBun(format(before)),
|
|
398
|
-
...toBun(format([...before, optional, ...after])),
|
|
399
|
-
]
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
type ExtractSegment<S extends string> = S extends `[[...${infer Name}]]`
|
|
403
|
-
? RestSegment<Name, true>
|
|
404
|
-
: S extends `[...${infer Name}]` ? RestSegment<Name, false>
|
|
405
|
-
: S extends `[[${infer Name}]]` ? ParamSegment<Name, true, "", "">
|
|
406
|
-
: S extends
|
|
407
|
-
`${infer Pre
|
|
408
|
-
extends `${string}${ParamDelimiter}`}[${infer Name}]${infer Suf}`
|
|
409
|
-
? Suf extends `${infer Delim extends ParamDelimiter}${infer SufRest}`
|
|
410
|
-
? ParamSegment<Name, false, Pre, `${Delim}${SufRest}`>
|
|
411
|
-
: Suf extends "" ? ParamSegment<Name, false, Pre, "">
|
|
412
|
-
: undefined
|
|
413
|
-
: S extends `[${infer Name}]${infer Suf extends `${ParamDelimiter}${string}`}`
|
|
414
|
-
? ParamSegment<Name, false, "", Suf>
|
|
415
|
-
: S extends `[${infer Name}]` ? ParamSegment<Name, false, "", "">
|
|
416
|
-
: LiteralSegment<S>
|
package/src/StartApp.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import * as HttpApp from "@effect/platform/HttpApp"
|
|
2
|
-
import * as Context from "effect/Context"
|
|
3
|
-
import * as Effect from "effect/Effect"
|
|
4
|
-
import * as Function from "effect/Function"
|
|
5
|
-
import * as Layer from "effect/Layer"
|
|
6
|
-
import * as PubSub from "effect/PubSub"
|
|
7
|
-
import * as Ref from "effect/Ref"
|
|
8
|
-
|
|
9
|
-
type StartMiddleware = <E, R>(
|
|
10
|
-
self: HttpApp.Default<E, R>,
|
|
11
|
-
) => HttpApp.Default<never, never>
|
|
12
|
-
|
|
13
|
-
export class StartApp extends Context.Tag("effect-start/StartApp")<
|
|
14
|
-
StartApp,
|
|
15
|
-
{
|
|
16
|
-
readonly env: "development" | "production" | string
|
|
17
|
-
readonly addMiddleware: (
|
|
18
|
-
middleware: StartMiddleware,
|
|
19
|
-
) => Effect.Effect<void>
|
|
20
|
-
readonly middleware: Ref.Ref<StartMiddleware>
|
|
21
|
-
readonly events: PubSub.PubSub<any>
|
|
22
|
-
}
|
|
23
|
-
>() {
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function layer(options?: {
|
|
27
|
-
env?: string
|
|
28
|
-
}) {
|
|
29
|
-
return Layer.effect(
|
|
30
|
-
StartApp,
|
|
31
|
-
Effect.gen(function*() {
|
|
32
|
-
const env = options?.env ?? process.env.NODE_ENV ?? "development"
|
|
33
|
-
const middleware = yield* Ref.make(
|
|
34
|
-
Function.identity as StartMiddleware,
|
|
35
|
-
)
|
|
36
|
-
const events = yield* PubSub.unbounded()
|
|
37
|
-
|
|
38
|
-
return StartApp.of({
|
|
39
|
-
env,
|
|
40
|
-
middleware,
|
|
41
|
-
addMiddleware: (f) =>
|
|
42
|
-
Ref.update(middleware, (prev) => (app) => f(prev(app))),
|
|
43
|
-
events,
|
|
44
|
-
})
|
|
45
|
-
}),
|
|
46
|
-
)
|
|
47
|
-
}
|