@marko/run 0.5.13 → 0.5.15

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.
@@ -14,74 +14,66 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
14
14
  import sade from "sade";
15
15
 
16
16
  // src/cli/commands.ts
17
- import path5 from "path";
18
17
  import fs5 from "fs";
18
+ import path5 from "path";
19
19
  import { fileURLToPath as fileURLToPath2 } from "url";
20
20
  import {
21
21
  build as viteBuild,
22
22
  resolveConfig
23
23
  } from "vite";
24
24
 
25
- // src/vite/utils/config.ts
26
- var PluginConfigKey = "__MARKO_RUN_PLUGIN_CONFIG__";
27
- var AdapterConfigKey = "__MARKO_RUN_ADAPTER_CONFIG__";
28
- function getConfig(obj, key) {
29
- return obj[key];
30
- }
31
- function setConfig(obj, key, value) {
32
- obj[key] = value;
33
- return obj;
34
- }
35
- var getExternalPluginOptions = (viteConfig) => getConfig(viteConfig, PluginConfigKey);
36
- var setExternalPluginOptions = (viteConfig, value) => setConfig(viteConfig, PluginConfigKey, value);
37
- var getExternalAdapterOptions = (viteConfig) => getConfig(viteConfig, AdapterConfigKey);
38
- var setExternalAdapterOptions = (viteConfig, value) => setConfig(viteConfig, AdapterConfigKey, value);
25
+ // src/vite/plugin.ts
26
+ import markoVitePlugin from "@marko/vite";
27
+ import browserslist from "browserslist";
28
+ import { createHash } from "crypto";
29
+ import createDebug from "debug";
30
+ import { resolveToEsbuildTarget } from "esbuild-plugin-browserslist";
31
+ import fs3 from "fs";
32
+ import { glob } from "glob";
33
+ import path4 from "path";
34
+ import { fileURLToPath } from "url";
35
+ import { buildErrorMessage, mergeConfig } from "vite";
39
36
 
40
- // src/vite/utils/server.ts
41
- import net from "net";
42
- import cp from "child_process";
43
- import { parse, config } from "dotenv";
44
- import fs from "fs";
45
- import cluster from "cluster";
46
- async function getConnection(port) {
47
- return new Promise((resolve) => {
48
- const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
49
- connection.end();
50
- resolve(null);
51
- }).on("connect", () => {
52
- resolve(connection);
53
- });
54
- });
37
+ // src/adapter/utils.ts
38
+ import kleur from "kleur";
39
+ import supporsColor from "supports-color";
40
+ function stripAnsi(string) {
41
+ return string.replace(
42
+ /([\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><])/g,
43
+ ""
44
+ );
55
45
  }
56
- async function isPortInUse(port) {
57
- return Boolean(await getConnection(port));
46
+ function cleanStack(stack) {
47
+ return stack.split(/\n/).filter((l) => /^\s*at/.test(l)).join("\n");
58
48
  }
59
- async function getAvailablePort(port) {
60
- if (port && !await isPortInUse(port)) {
61
- return port;
62
- }
63
- return new Promise((resolve) => {
64
- const server = net.createServer().listen(0, () => {
65
- const { port: port2 } = server.address();
66
- server.close(() => resolve(port2));
67
- });
68
- });
49
+ function prepareError(err) {
50
+ var _a;
51
+ return {
52
+ message: stripAnsi(err.message),
53
+ stack: stripAnsi(cleanStack(err.stack || "")),
54
+ id: err.id,
55
+ frame: stripAnsi(err.frame || ""),
56
+ plugin: err.plugin,
57
+ pluginCode: (_a = err.pluginCode) == null ? void 0 : _a.toString(),
58
+ loc: err.loc
59
+ };
69
60
  }
70
61
 
71
- // src/vite/plugin.ts
72
- import path4 from "path";
73
- import fs4 from "fs";
74
- import { glob } from "glob";
75
- import { fileURLToPath } from "url";
76
- import browserslist from "browserslist";
77
- import { resolveToEsbuildTarget } from "esbuild-plugin-browserslist";
78
- import { buildErrorMessage, mergeConfig } from "vite";
79
- import markoVitePlugin from "@marko/vite";
62
+ // src/vite/codegen/index.ts
63
+ import path from "path";
80
64
 
81
65
  // src/vite/constants.ts
82
66
  var markoRunFilePrefix = "__marko-run__";
83
67
  var virtualFilePrefix = "virtual:marko-run";
84
- var httpVerbs = ["get", "post", "put", "delete"];
68
+ var httpVerbs = [
69
+ "get",
70
+ "head",
71
+ "post",
72
+ "put",
73
+ "delete",
74
+ "patch",
75
+ "options"
76
+ ];
85
77
  var serverEntryQuery = "?marko-server-entry";
86
78
  var RoutableFileTypes = {
87
79
  Page: "page",
@@ -93,557 +85,62 @@ var RoutableFileTypes = {
93
85
  Error: "500"
94
86
  };
95
87
 
96
- // src/vite/routes/vdir.ts
97
- var _dirs, _pathlessDirs;
98
- var _VDir = class _VDir {
99
- constructor(parent, segment, source) {
100
- __privateAdd(this, _dirs);
101
- __privateAdd(this, _pathlessDirs);
102
- __publicField(this, "parent");
103
- __publicField(this, "source");
104
- __publicField(this, "path");
105
- __publicField(this, "fullPath");
106
- __publicField(this, "segment");
107
- __publicField(this, "files");
108
- if (!parent || !segment) {
109
- this.parent = null;
110
- this.source = null;
111
- this.path = "/";
112
- this.fullPath = "/";
113
- this.segment = {
114
- raw: "",
115
- name: ""
116
- };
117
- } else {
118
- this.parent = parent;
119
- this.source = source;
120
- this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
121
- this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
122
- if (segment.param) {
123
- this.fullPath += segment.param;
124
- }
125
- this.segment = segment;
126
- }
88
+ // src/vite/utils/route.ts
89
+ var httpVerbOrder = httpVerbs.reduce(
90
+ (order, verb, index) => {
91
+ order[verb] = index;
92
+ return order;
93
+ },
94
+ {}
95
+ );
96
+ function getVerbs(route, noAutoHead) {
97
+ var _a;
98
+ const verbs = new Set((_a = route.handler) == null ? void 0 : _a.verbs);
99
+ if (route.page) {
100
+ verbs.add("get");
127
101
  }
128
- get pathInfo() {
129
- const value = {
130
- id: "/",
131
- path: "/",
132
- segments: []
133
- };
134
- let sep = "";
135
- for (const { segment } of this) {
136
- const { type, name, param } = segment;
137
- if (name && type !== "_") {
138
- value.id += sep + (type || name);
139
- value.path += sep + name;
140
- value.isEnd = type === "$$";
141
- if (param) {
142
- value.path += param;
143
- let index = type === "$$" ? null : value.segments.length;
144
- if (!value.params) {
145
- value.params = { [param]: index };
146
- } else if (!(param in value.params)) {
147
- value.params[param] = index;
148
- }
149
- }
150
- value.segments.push(name);
151
- sep = "/";
152
- }
153
- }
154
- Object.defineProperty(this, "pathInfo", {
155
- value,
156
- enumerable: true
157
- });
158
- return value;
102
+ if (!noAutoHead && verbs.has("get")) {
103
+ verbs.add("head");
159
104
  }
160
- addDir(path6, segment) {
161
- const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
162
- if (!map.has(segment.name)) {
163
- const dir = new _VDir(this, segment, path6);
164
- map.set(segment.name, dir);
165
- return dir;
105
+ return [...verbs].sort((a, b) => httpVerbOrder[a] - httpVerbOrder[b]);
106
+ }
107
+ function hasVerb(route, verb) {
108
+ var _a, _b;
109
+ return verb === "get" && !!route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes(verb)) || verb === "head" && hasVerb(route, "get");
110
+ }
111
+
112
+ // src/vite/codegen/writer.ts
113
+ function createWriter(sink, options) {
114
+ let buffer = "";
115
+ let indentLevel = 0;
116
+ let indentString = "";
117
+ let firstOpenIndex = 0;
118
+ const branches = [];
119
+ const openWriters = /* @__PURE__ */ new Map();
120
+ function write(data) {
121
+ if (!writer.__isActive) {
122
+ throw new Error("Cannot write to branch that has been joined");
166
123
  }
167
- return map.get(segment.name);
168
- }
169
- addFile(file) {
170
- if (!this.files) {
171
- this.files = /* @__PURE__ */ new Map();
172
- this.files.set(file.type, file);
173
- } else if (!this.files.has(file.type)) {
174
- this.files.set(file.type, file);
124
+ if (openWriters.size) {
125
+ buffer += data;
175
126
  } else {
176
- const existing = this.files.get(file.type);
177
- if (existing !== file) {
178
- throw new Error(
179
- `Duplicate file type '${file.type}' added at path '${this.path}'. File '${file.importPath}' collides with '${existing.importPath}'.`
180
- );
181
- } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
182
- throw new Error(
183
- `Ambiguous path definition: route '${this.path}' is defined multiple times by ${file.importPath}`
184
- );
185
- }
186
- throw new Error(
187
- `Ambiguous path definition: file '${this.path}' is included multiple times by ${file.importPath}`
188
- );
189
- }
190
- }
191
- *dirs() {
192
- if (__privateGet(this, _pathlessDirs)) {
193
- yield* __privateGet(this, _pathlessDirs).values();
194
- }
195
- if (__privateGet(this, _dirs)) {
196
- yield* __privateGet(this, _dirs).values();
197
- }
198
- }
199
- *[Symbol.iterator]() {
200
- if (this.parent) {
201
- yield* this.parent;
127
+ sink(data);
202
128
  }
203
- yield this;
129
+ return writer;
204
130
  }
205
- static addPaths(roots, paths) {
206
- const dirs = [];
207
- const unique = /* @__PURE__ */ new Set();
208
- for (const root of roots) {
209
- for (const path6 of paths) {
210
- let dir = root;
211
- for (const segment of path6.segments) {
212
- dir = dir.addDir(path6, segment);
131
+ const writer = {
132
+ __isActive: true,
133
+ get indent() {
134
+ return indentLevel;
135
+ },
136
+ set indent(value) {
137
+ if (options == null ? void 0 : options.indentWith) {
138
+ if (value < 0) {
139
+ value = 0;
213
140
  }
214
- if (unique.has(dir.path)) {
215
- const sources = /* @__PURE__ */ new Set();
216
- let sourcePath = "";
217
- for (const { source } of dir) {
218
- if (source && !sources.has(source.source)) {
219
- sources.add(source.source);
220
- sourcePath += source.source + "/";
221
- }
222
- }
223
- throw new Error(
224
- `Ambiguous directory structure: '${sourcePath}${path6.source}' defines '${dir.path}' multiple times.`
225
- );
226
- } else {
227
- unique.add(dir.path);
228
- dirs.push(dir);
229
- }
230
- }
231
- }
232
- return dirs;
233
- }
234
- };
235
- _dirs = new WeakMap();
236
- _pathlessDirs = new WeakMap();
237
- var VDir = _VDir;
238
-
239
- // src/vite/routes/parse.ts
240
- function parseFlatRoute(pattern) {
241
- if (!pattern) throw new Error("Empty pattern");
242
- const len = pattern.length;
243
- let i = 0;
244
- return parse2([
245
- {
246
- id: "/",
247
- segments: [],
248
- source: pattern
249
- }
250
- ]);
251
- function parse2(basePaths, group) {
252
- const pathMap = /* @__PURE__ */ new Map();
253
- const delimiters = group ? ").," : ".,";
254
- let charCode;
255
- let segmentStart = i;
256
- let type;
257
- let current;
258
- do {
259
- charCode = pattern.charCodeAt(i);
260
- if (charCode === 41 && group) {
261
- break;
262
- } else if (charCode === 44) {
263
- if (!current) {
264
- segmentEnd(
265
- basePaths.map((path6) => ({
266
- ...path6,
267
- segments: path6.segments.slice()
268
- })),
269
- "",
270
- "_",
271
- pathMap
272
- );
273
- } else {
274
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
275
- }
276
- current = void 0;
277
- type = void 0;
278
- segmentStart = ++i;
279
- } else if (charCode === 46) {
280
- if (current) {
281
- segmentEnd(current, pattern.slice(segmentStart, i), type);
282
- }
283
- type = void 0;
284
- segmentStart = ++i;
285
- } else if (charCode === 40) {
286
- const groupPaths = parse2(current || basePaths, ++i);
287
- if (groupPaths.length) {
288
- current = groupPaths;
289
- }
290
- segmentStart = ++i;
291
- } else {
292
- if (charCode === 95) {
293
- type = "_";
294
- } else if (charCode === 36) {
295
- type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
296
- }
297
- current ?? (current = basePaths.map((path6) => ({
298
- ...path6,
299
- segments: path6.segments.slice()
300
- })));
301
- i = len;
302
- for (const char of delimiters) {
303
- const index = pattern.indexOf(char, segmentStart);
304
- if (index >= 0 && index < i) {
305
- i = index;
306
- }
307
- }
308
- }
309
- } while (i < len);
310
- if (group && charCode !== 41) {
311
- throw new Error(
312
- `Invalid route pattern: group was not closed '${pattern.slice(
313
- group
314
- )}' in '${pattern}'`
315
- );
316
- }
317
- if (!current) {
318
- segmentEnd(
319
- basePaths.map((path6) => ({
320
- ...path6,
321
- segments: path6.segments.slice()
322
- })),
323
- "",
324
- "_",
325
- pathMap
326
- );
327
- } else {
328
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
329
- }
330
- return [...pathMap.values()];
331
- }
332
- function segmentEnd(paths, raw, type, map) {
333
- let segment;
334
- if (raw) {
335
- segment = {
336
- raw,
337
- name: raw,
338
- type
339
- };
340
- if (type === "$" || type === "$$") {
341
- segment.name = type;
342
- segment.param = raw.slice(type.length);
343
- }
344
- }
345
- for (const path6 of paths) {
346
- if (segment) {
347
- if (path6.isCatchall) {
348
- throw new Error(
349
- `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
350
- 0,
351
- i
352
- )}' in '${pattern}'.`
353
- );
354
- }
355
- path6.segments.push(segment);
356
- path6.id += path6.id === "/" ? segment.name : `/${segment.name}`;
357
- if (type === "$$") {
358
- path6.isCatchall = true;
359
- }
360
- }
361
- if (map) {
362
- if (map.has(path6.id)) {
363
- const existing = map.get(path6.id);
364
- const existingExpansion = existing.segments.map((s) => s.raw).join(".");
365
- const currentExpansion = path6.segments.map((s) => s.raw).join(".");
366
- throw new Error(
367
- `Invalid route pattern: route '${path6.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
368
- );
369
- }
370
- map.set(path6.id, path6);
371
- }
372
- }
373
- }
374
- }
375
-
376
- // src/vite/routes/builder.ts
377
- var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
378
- var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
379
- var routeableFileRegex = new RegExp(
380
- `[+](?:${markoFiles}|${nonMarkoFiles})$`,
381
- "i"
382
- );
383
- function matchRoutableFile(filename) {
384
- const match = filename.match(routeableFileRegex);
385
- return match && (match[1] || match[3]).toLowerCase();
386
- }
387
- function isSpecialType(type) {
388
- return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
389
- }
390
- async function buildRoutes(sources) {
391
- const uniqueRoutes = /* @__PURE__ */ new Map();
392
- const routes = [];
393
- const special = {};
394
- const middlewares = /* @__PURE__ */ new Set();
395
- const unusedFiles = /* @__PURE__ */ new Set();
396
- const currentLayouts = /* @__PURE__ */ new Set();
397
- const currentMiddleware = /* @__PURE__ */ new Set();
398
- const root = new VDir();
399
- const dirStack = [];
400
- let basePath;
401
- let importPrefix;
402
- let activeDirs;
403
- let isBaseDir;
404
- let nextFileId = 1;
405
- let nextRouteIndex = 1;
406
- const walkOptions = {
407
- onEnter({ name }) {
408
- const prevDirStackLength = dirStack.length;
409
- if (isBaseDir) {
410
- isBaseDir = false;
411
- if (!basePath) {
412
- return;
413
- }
414
- name = basePath;
415
- } else {
416
- dirStack.push(name);
417
- }
418
- const previousDirs = activeDirs;
419
- const paths = parseFlatRoute(name);
420
- activeDirs = VDir.addPaths(previousDirs, paths);
421
- return () => {
422
- activeDirs = previousDirs;
423
- dirStack.length = prevDirStackLength;
424
- };
425
- },
426
- onFile({ name, path: path6 }) {
427
- const match = name.match(routeableFileRegex);
428
- if (!match) {
429
- return;
430
- }
431
- const type = (match[1] || match[3]).toLowerCase();
432
- if (dirStack.length && isSpecialType(type)) {
433
- console.warn(
434
- `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${path6}`
435
- );
436
- return;
437
- }
438
- let dirs = activeDirs;
439
- if (match.index) {
440
- const paths = parseFlatRoute(name.slice(0, match.index));
441
- dirs = VDir.addPaths(activeDirs, paths);
442
- }
443
- const dirPath = dirStack.join("/");
444
- const relativePath = dirPath ? `${dirPath}/${name}` : name;
445
- const file = {
446
- id: String(nextFileId++),
447
- name,
448
- type,
449
- filePath: path6,
450
- relativePath,
451
- importPath: `${importPrefix}/${relativePath}`,
452
- verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
453
- };
454
- for (const dir of dirs) {
455
- dir.addFile(file);
456
- }
457
- }
458
- };
459
- if (!Array.isArray(sources)) {
460
- sources = [sources];
461
- }
462
- for (const source of sources) {
463
- importPrefix = source.importPrefix ? source.importPrefix.replace(/^\/+|\/+$/g, "") : "";
464
- basePath = source.basePath || "";
465
- activeDirs = [root];
466
- isBaseDir = true;
467
- await source.walker(walkOptions);
468
- }
469
- traverse(root);
470
- return {
471
- list: routes,
472
- middleware: [...middlewares],
473
- special
474
- };
475
- function traverse(dir) {
476
- let middleware;
477
- let layout;
478
- if (dir.files) {
479
- middleware = dir.files.get(RoutableFileTypes.Middleware);
480
- layout = dir.files.get(RoutableFileTypes.Layout);
481
- const handler = dir.files.get(RoutableFileTypes.Handler);
482
- const page = dir.files.get(RoutableFileTypes.Page);
483
- let hasSpecial = false;
484
- if (middleware) {
485
- if (currentMiddleware.has(middleware)) {
486
- middleware = void 0;
487
- } else {
488
- currentMiddleware.add(middleware);
489
- unusedFiles.add(middleware);
490
- }
491
- }
492
- if (layout) {
493
- if (currentLayouts.has(layout)) {
494
- layout = void 0;
495
- } else {
496
- currentLayouts.add(layout);
497
- unusedFiles.add(layout);
498
- }
499
- }
500
- if (page || handler) {
501
- const path6 = dir.pathInfo;
502
- if (uniqueRoutes.has(path6.id)) {
503
- const existing = uniqueRoutes.get(path6.id);
504
- const route = routes[existing.index];
505
- const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
506
- const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
507
- throw new Error(`Duplicate routes for path '${path6.path}' were defined. A route established by:
508
- ${existingFiles.join(" and ")} via '${existing.dir.path}'
509
- collides with
510
- ${currentFiles.join(" and ")} via '${dir.path}'
511
- `);
512
- }
513
- uniqueRoutes.set(path6.id, { dir, index: routes.length });
514
- routes.push({
515
- index: nextRouteIndex++,
516
- key: dir.fullPath,
517
- paths: [path6],
518
- middleware: [...currentMiddleware],
519
- layouts: page ? [...currentLayouts] : [],
520
- meta: dir.files.get(RoutableFileTypes.Meta),
521
- page,
522
- handler,
523
- entryName: `${markoRunFilePrefix}route` + (dir.path !== "/" ? dir.fullPath.replace(/\//g, ".").replace(/(%[A-Fa-f0-9]{2})+/g, "_") : "")
524
- });
525
- }
526
- if (dir === root) {
527
- for (const [type, file] of dir.files) {
528
- if (isSpecialType(type)) {
529
- hasSpecial = true;
530
- special[type] = {
531
- index: 0,
532
- key: type,
533
- paths: [],
534
- middleware: [],
535
- layouts: [...currentLayouts],
536
- page: file,
537
- entryName: `${markoRunFilePrefix}special.${type}`
538
- };
539
- }
540
- }
541
- }
542
- if (handler || page) {
543
- for (const middleware2 of currentMiddleware) {
544
- middlewares.add(middleware2);
545
- unusedFiles.delete(middleware2);
546
- }
547
- }
548
- if (page || hasSpecial) {
549
- for (const layout2 of currentLayouts) {
550
- unusedFiles.delete(layout2);
551
- }
552
- }
553
- }
554
- if (dir.dirs) {
555
- for (const child of dir.dirs()) {
556
- traverse(child);
557
- }
558
- }
559
- if (middleware) {
560
- currentMiddleware.delete(middleware);
561
- }
562
- if (layout) {
563
- currentLayouts.delete(layout);
564
- }
565
- }
566
- }
567
-
568
- // src/vite/routes/walk.ts
569
- import fs2 from "fs";
570
- import path from "path";
571
- function createFSWalker(dir) {
572
- return async function walkFS({
573
- onEnter,
574
- onFile,
575
- onDir,
576
- maxDepth = 50
577
- }) {
578
- async function walk(dir2, depth) {
579
- const onExit = onEnter == null ? void 0 : onEnter(dir2);
580
- if (onExit !== false) {
581
- const dirs = [];
582
- const entries = await fs2.promises.readdir(dir2.path, {
583
- withFileTypes: true
584
- });
585
- const prefix = dir2.path + path.sep;
586
- for (const entry of entries) {
587
- const walkEntry = {
588
- name: entry.name,
589
- path: prefix + entry.name
590
- };
591
- if (entry.isDirectory()) {
592
- dirs.push(walkEntry);
593
- } else {
594
- onFile == null ? void 0 : onFile(walkEntry);
595
- }
596
- }
597
- if ((onDir == null ? void 0 : onDir()) !== false && --depth > 0) {
598
- for (const entry of dirs) {
599
- await walk(entry, depth);
600
- }
601
- }
602
- onExit == null ? void 0 : onExit();
603
- }
604
- }
605
- await walk(
606
- {
607
- path: dir,
608
- name: path.basename(dir)
609
- },
610
- maxDepth
611
- );
612
- };
613
- }
614
-
615
- // src/vite/codegen/writer.ts
616
- function createWriter(sink, options) {
617
- let buffer = "";
618
- let indentLevel = 0;
619
- let indentString = "";
620
- let firstOpenIndex = 0;
621
- const branches = [];
622
- const openWriters = /* @__PURE__ */ new Map();
623
- function write(data) {
624
- if (!writer.__isActive) {
625
- throw new Error("Cannot write to branch that has been joined");
626
- }
627
- if (openWriters.size) {
628
- buffer += data;
629
- } else {
630
- sink(data);
631
- }
632
- return writer;
633
- }
634
- const writer = {
635
- __isActive: true,
636
- get indent() {
637
- return indentLevel;
638
- },
639
- set indent(value) {
640
- if (options == null ? void 0 : options.indentWith) {
641
- if (value < 0) {
642
- value = 0;
643
- }
644
- if (value !== indentLevel) {
645
- indentLevel = value;
646
- indentString = options.indentWith.repeat(indentLevel);
141
+ if (value !== indentLevel) {
142
+ indentLevel = value;
143
+ indentString = options.indentWith.repeat(indentLevel);
647
144
  }
648
145
  }
649
146
  },
@@ -675,7 +172,7 @@ function createWriter(sink, options) {
675
172
  return writer.writeBlockStart(start).writeLines(...lines).writeBlockEnd(end);
676
173
  },
677
174
  branch(name) {
678
- let existing = openWriters.get(name);
175
+ const existing = openWriters.get(name);
679
176
  if (existing) {
680
177
  return existing;
681
178
  }
@@ -738,9 +235,12 @@ function createWriter(sink, options) {
738
235
  }
739
236
  function createStringWriter(opts) {
740
237
  let code = "";
741
- const writer = createWriter((data) => {
742
- code += data;
743
- }, { indentWith: " ", ...opts });
238
+ const writer = createWriter(
239
+ (data) => {
240
+ code += data;
241
+ },
242
+ { indentWith: " ", ...opts }
243
+ );
744
244
  return Object.assign(writer, {
745
245
  end() {
746
246
  writer.join(true);
@@ -749,22 +249,7 @@ function createStringWriter(opts) {
749
249
  });
750
250
  }
751
251
 
752
- // src/vite/utils/route.ts
753
- function getVerbs(route) {
754
- var _a, _b;
755
- const verbs = ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.slice()) || [];
756
- if (route.page && !verbs.includes("get")) {
757
- verbs.unshift("get");
758
- }
759
- return verbs;
760
- }
761
- function hasVerb(route, verb) {
762
- var _a, _b;
763
- return verb === "get" && route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes(verb));
764
- }
765
-
766
252
  // src/vite/codegen/index.ts
767
- import path2 from "path";
768
253
  function renderRouteTemplate(route, getRelativePath) {
769
254
  if (!route.page) {
770
255
  throw new Error(`Route ${route.key} has no page to render`);
@@ -825,12 +310,15 @@ function renderRouteEntry(route, entriesDir) {
825
310
  if (handler || middleware.length) {
826
311
  runtimeImports.push("call");
827
312
  }
828
- if (!page || verbs.length > 1) {
313
+ if (!page || verbs.some((verb) => verb !== "get" && verb !== "head")) {
829
314
  runtimeImports.push("noContent");
830
315
  }
831
316
  if (page) {
832
317
  runtimeImports.push("pageResponse");
833
318
  }
319
+ if (verbs.includes("head")) {
320
+ runtimeImports.push("stripResponseBody");
321
+ }
834
322
  if (runtimeImports.length) {
835
323
  imports.writeLines(
836
324
  `import { ${runtimeImports.join(
@@ -859,628 +347,1173 @@ function renderRouteEntry(route, entriesDir) {
859
347
  );
860
348
  }
861
349
  if (page) {
862
- const importPath = route.layouts.length ? `./${path2.posix.join(entriesDir, page.relativePath, "..", "route.marko")}` : `./${page.importPath}`;
350
+ const pageNameIndex = page.name.indexOf("+page");
351
+ const pageNamePrefix = pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : "";
352
+ const importPath = route.layouts.length ? `./${path.posix.join(entriesDir, page.relativePath, "..", pageNamePrefix + "route.marko")}` : `./${page.importPath}`;
863
353
  imports.writeLines(`import page from '${importPath}${serverEntryQuery}';`);
864
354
  }
865
- if (meta) {
355
+ if (meta) {
356
+ imports.writeLines(
357
+ `export { default as meta${index} } from './${meta.importPath}';`
358
+ );
359
+ }
360
+ for (const verb of verbs) {
361
+ writeRouteEntryHandler(writer, route, verb);
362
+ }
363
+ return writer.end();
364
+ }
365
+ function writeRouteEntryHandler(writer, route, verb) {
366
+ var _a, _b, _c, _d;
367
+ const { key, index, page, handler, middleware } = route;
368
+ const len = middleware.length;
369
+ let nextName;
370
+ let currentName;
371
+ let hasBody = false;
372
+ writer.writeLines("");
373
+ if (page && (verb === "get" || verb === "head")) {
374
+ writer.writeBlockStart(
375
+ `export function ${verb}${index}(context, buildInput) {`
376
+ );
377
+ } else {
378
+ writer.writeBlockStart(`export function ${verb}${index}(context) {`);
379
+ }
380
+ const continuations = writer.branch("cont");
381
+ if (page && (verb === "get" || verb === "head")) {
382
+ currentName = "__page";
383
+ if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
384
+ const name = `${verb}Handler`;
385
+ continuations.writeLines(
386
+ `const ${currentName} = () => pageResponse(page, buildInput());`
387
+ );
388
+ if (len) {
389
+ nextName = currentName;
390
+ currentName = `__${name}`;
391
+ continuations.writeLines(
392
+ `const ${currentName} = () => call(${name}, ${nextName}, context);`
393
+ );
394
+ } else {
395
+ if (verb === "head") {
396
+ writer.writeLines(
397
+ `return stripResponseBody(call(${name}, ${currentName}, context));`
398
+ );
399
+ } else {
400
+ writer.writeLines(`return call(${name}, ${currentName}, context);`);
401
+ }
402
+ hasBody = true;
403
+ }
404
+ } else if (verb === "head") {
405
+ writer.writeLines(
406
+ `return stripResponseBody(get${index}(context, buildInput));`
407
+ );
408
+ hasBody = true;
409
+ } else if (len) {
410
+ continuations.writeLines(
411
+ `const ${currentName} = () => pageResponse(page, buildInput());`
412
+ );
413
+ nextName = currentName;
414
+ } else {
415
+ writer.writeLines(`return pageResponse(page, buildInput());`);
416
+ hasBody = true;
417
+ }
418
+ } else if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes(verb)) {
419
+ const name = `${verb}Handler`;
420
+ currentName = `__${name}`;
421
+ nextName = "noContent";
422
+ if (len) {
423
+ continuations.writeLines(
424
+ `const ${currentName} = () => call(${name}, ${nextName}, context);`
425
+ );
426
+ } else {
427
+ if (verb === "head") {
428
+ writer.writeLines(
429
+ `return stripResponseBody(call(${name}, ${nextName}, context));`
430
+ );
431
+ } else {
432
+ writer.writeLines(`return call(${name}, ${nextName}, context);`);
433
+ }
434
+ hasBody = true;
435
+ }
436
+ } else if (verb === "head" && ((_d = (_c = route.handler) == null ? void 0 : _c.verbs) == null ? void 0 : _d.includes("get"))) {
437
+ writer.writeLines(`return stripResponseBody(get${index}(context));`);
438
+ hasBody = true;
439
+ } else {
440
+ throw new Error(`Route ${key} has no handler for ${verb} requests`);
441
+ }
442
+ if (!hasBody) {
443
+ let i = len;
444
+ while (i--) {
445
+ const { id } = middleware[i];
446
+ const name = `mware${id}`;
447
+ nextName = currentName;
448
+ currentName = i ? `__${name}` : "";
449
+ if (currentName) {
450
+ continuations.writeLines(
451
+ `const ${currentName} = () => call(${name}, ${nextName}, context);`
452
+ );
453
+ } else if (verb === "head") {
454
+ continuations.writeLines(
455
+ `return stripResponseBody(call(${name}, ${nextName}, context));`
456
+ );
457
+ } else {
458
+ continuations.writeLines(`return call(${name}, ${nextName}, context);`);
459
+ }
460
+ }
461
+ }
462
+ continuations.join();
463
+ writer.writeBlockEnd("}");
464
+ }
465
+ function renderRouter(routes, entriesDir, options = {
466
+ trailingSlashes: "RedirectWithout"
467
+ }) {
468
+ const writer = createStringWriter();
469
+ writer.writeLines(`// @marko/run/router`);
470
+ const imports = writer.branch("imports");
471
+ imports.writeLines(
472
+ `import { NotHandled, NotMatched, createContext } from '${virtualFilePrefix}/runtime/internal';`
473
+ );
474
+ for (const route of routes.list) {
475
+ const verbs = getVerbs(route);
476
+ const names = verbs.map((verb) => `${verb}${route.index}`);
477
+ route.meta && names.push(`meta${route.index}`);
478
+ imports.writeLines(
479
+ `import { ${names.join(", ")} } from '${virtualFilePrefix}/${route.entryName}.js';`
480
+ );
481
+ }
482
+ for (const route of Object.values(routes.special)) {
483
+ const importPath = route.layouts.length ? `./${path.posix.join(entriesDir, route.page.relativePath, "..", `route.${route.key}.marko`)}` : `./${route.page.importPath}`;
484
+ imports.writeLines(
485
+ `import page${route.key} from '${importPath}${serverEntryQuery}';`
486
+ );
487
+ }
488
+ writer.writeLines(
489
+ `
490
+ globalThis.__marko_run__ = { match, fetch, invoke };
491
+ `
492
+ ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
493
+ `if (!pathname) {
494
+ pathname = '/';
495
+ } else if (pathname.charAt(0) !== '/') {
496
+ pathname = '/' + pathname;
497
+ }`
498
+ ).writeBlockStart(`switch (method) {`);
499
+ for (const verb of httpVerbs) {
500
+ const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
501
+ if (filteredRoutes.length) {
502
+ const trie = createRouteTrie(filteredRoutes);
503
+ writer.writeLines(`case '${verb.toUpperCase()}':`);
504
+ writer.writeBlockStart(`case '${verb.toLowerCase()}': {`);
505
+ writeRouterVerb(writer, trie, verb);
506
+ writer.writeBlockEnd("}");
507
+ }
508
+ }
509
+ writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
510
+ writer.writeLines("").writeBlockStart(
511
+ "export async function invoke(route, request, platform, url) {"
512
+ ).writeLines(
513
+ "const [context, buildInput] = createContext(route, request, platform, url);"
514
+ );
515
+ const hasErrorPage = Boolean(routes.special[RoutableFileTypes.Error]);
516
+ if (hasErrorPage) {
517
+ writer.writeBlockStart("try {");
518
+ }
519
+ writer.writeBlockStart("if (route) {").writeBlockStart("try {").writeLines(
520
+ "const response = await route.handler(context, buildInput);",
521
+ "if (response) return response;"
522
+ ).indent--;
523
+ writer.writeBlockStart("} catch (error) {").writeLines(
524
+ "if (error === NotHandled) return;",
525
+ "if (error !== NotMatched) throw error;"
526
+ ).writeBlockEnd("}").writeBlockEnd("}");
527
+ if (routes.special[RoutableFileTypes.NotFound]) {
866
528
  imports.writeLines(
867
- `export { default as meta${index} } from './${meta.importPath}';`
529
+ `
530
+ const page404ResponseInit = {
531
+ status: 404,
532
+ headers: { "content-type": "text/html;charset=UTF-8" },
533
+ };`
868
534
  );
535
+ writer.write(`
536
+ if (context.request.headers.get('Accept')?.includes('text/html')) {
537
+ return new Response(page404.stream(buildInput()), page404ResponseInit);
538
+ }
539
+ `);
869
540
  }
870
- for (const verb of verbs) {
871
- writeRouteEntryHandler(writer, route, verb);
541
+ writer.indent--;
542
+ if (hasErrorPage) {
543
+ imports.writeLines(`
544
+ const page500ResponseInit = {
545
+ status: 500,
546
+ headers: { "content-type": "text/html;charset=UTF-8" },
547
+ };`);
548
+ writer.writeBlockStart(`} catch (error) {`).writeBlockStart(
549
+ `if (context.request.headers.get('Accept')?.includes('text/html')) {`
550
+ ).writeLines(
551
+ `return new Response(page500.stream(buildInput({ error })), page500ResponseInit);`
552
+ ).writeBlockEnd("}").writeLines("throw error;").writeBlockEnd("}");
872
553
  }
554
+ writer.writeBlockEnd("}");
555
+ renderFetch(writer, options);
873
556
  return writer.end();
874
557
  }
875
- function writePageResponse(writer, wrapFn) {
876
- writer.writeLines(
877
- `${wrapFn ? `const ${wrapFn} = () =>` : `return`} pageResponse(page, buildInput());`
878
- );
879
- }
880
- function writeMiddleware(writer, middleware, next, wrapFn) {
881
- if (wrapFn) {
882
- writer.writeLines(
883
- `const ${wrapFn} = () => call(${middleware}, ${next}, context);`
884
- );
885
- } else {
886
- writer.writeLines(`return call(${middleware}, ${next}, context);`);
558
+ function renderFetch(writer, options) {
559
+ writer.write(`
560
+ export async function fetch(request, platform) {
561
+ try {
562
+ const url = new URL(request.url);
563
+ let { pathname } = url;`);
564
+ switch (options.trailingSlashes) {
565
+ case "RedirectWithout":
566
+ writer.write(`
567
+ if (pathname !== '/' && pathname.endsWith('/')) {
568
+ url.pathname = pathname.slice(0, -1);
569
+ return Response.redirect(url);
570
+ }`);
571
+ break;
572
+ case "RedirectWith":
573
+ writer.write(`
574
+ if (pathname !== '/' && !pathname.endsWith('/')) {
575
+ url.pathname = pathname + '/';
576
+ return Response.redirect(url);
577
+ }`);
578
+ break;
579
+ case "RewriteWithout":
580
+ writer.write(`
581
+ if (pathname !== '/' && pathname.endsWith('/')) {
582
+ url.pathname = pathname = pathname.slice(0, -1);
583
+ }`);
584
+ break;
585
+ case "RewriteWith":
586
+ writer.write(`
587
+ if (pathname !== '/' && !pathname.endsWith('/')) {
588
+ url.pathname = pathname = pathname + '/';
589
+ }`);
590
+ break;
591
+ }
592
+ writer.write(`
593
+
594
+ const route = match(request.method, pathname);
595
+ return await invoke(route, request, platform, url);
596
+ } catch (error) {
597
+ if (import.meta.env.DEV) {
598
+ throw error;
599
+ }
600
+ return new Response(null, {
601
+ status: 500
602
+ });
887
603
  }
604
+ }`);
888
605
  }
889
- function writeRouteEntryHandler(writer, route, verb) {
890
- var _a;
891
- const { key, index, page, handler, middleware } = route;
892
- const len = middleware.length;
893
- let nextName;
894
- let currentName;
895
- let hasBody = false;
896
- writer.writeLines("");
897
- if (page) {
898
- writer.writeBlockStart(
899
- `export async function ${verb}${index}(context, buildInput) {`
900
- );
901
- } else {
902
- writer.writeBlockStart(`export async function ${verb}${index}(context) {`);
606
+ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
607
+ const { route, dynamic, catchAll } = trie;
608
+ let closeCount = 0;
609
+ if (level === 0) {
610
+ writer.writeLines(`const len = pathname.length;`);
611
+ if (route) {
612
+ writer.writeLines(
613
+ `if (len === 1) return ${renderMatch(verb, route, trie.path)}; // ${trie.path.path}`
614
+ );
615
+ } else if (trie.static || dynamic) {
616
+ writer.writeBlockStart(`if (len > 1) {`);
617
+ closeCount++;
618
+ }
903
619
  }
904
- const continuations = writer.branch("cont");
905
- if (page && verb === "get") {
906
- currentName = "__page";
907
- if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
908
- const name = `${verb}Handler`;
909
- writePageResponse(continuations, currentName);
910
- if (len) {
911
- nextName = currentName;
912
- currentName = `__${name}`;
913
- writeMiddleware(continuations, name, nextName, currentName);
914
- } else {
915
- writeMiddleware(writer, name, currentName);
916
- hasBody = true;
620
+ if (trie.static || dynamic) {
621
+ const next = level + 1;
622
+ const index = `i${next}`;
623
+ let terminal;
624
+ let children;
625
+ writer.writeLines(`const ${index} = pathname.indexOf('/', ${offset}) + 1;`);
626
+ if (trie.static) {
627
+ for (const child of trie.static.values()) {
628
+ if (child.route) {
629
+ (terminal ?? (terminal = [])).push(child);
630
+ }
631
+ if (child.static || child.dynamic || child.catchAll) {
632
+ (children ?? (children = [])).push(child);
633
+ }
917
634
  }
918
- } else if (len) {
919
- writePageResponse(continuations, currentName);
920
- nextName = currentName;
921
- } else {
922
- writePageResponse(continuations);
923
- hasBody = true;
924
635
  }
925
- } else if (handler) {
926
- const name = `${verb}Handler`;
927
- currentName = `__${name}`;
928
- nextName = "noContent";
929
- if (len) {
930
- writeMiddleware(continuations, name, nextName, currentName);
931
- } else {
932
- writeMiddleware(writer, name, nextName);
933
- hasBody = true;
636
+ if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
637
+ closeCount++;
638
+ writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
639
+ let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
640
+ if (dynamic == null ? void 0 : dynamic.route) {
641
+ const segment = `s${next}`;
642
+ writer.writeLines(`const ${segment} = decodeURIComponent(${value});`);
643
+ value = segment;
644
+ } else if (terminal == null ? void 0 : terminal.some(
645
+ (terminal2) => decodeURIComponent(terminal2.key) !== terminal2.key
646
+ )) {
647
+ value = `decodeURIComponent(${value})`;
648
+ }
649
+ if (terminal) {
650
+ const useSwitch = terminal.length > 1;
651
+ if (useSwitch) {
652
+ writer.writeBlockStart(`switch (${value}) {`);
653
+ }
654
+ for (const { key, path: path6, route: route2 } of terminal) {
655
+ const decodedKey = decodeURIComponent(key);
656
+ if (useSwitch) {
657
+ writer.write(`case '${decodedKey}': `, true);
658
+ } else {
659
+ writer.write(`if (${value} === '${decodedKey}') `, true);
660
+ }
661
+ writer.write(
662
+ `return ${renderMatch(verb, route2, path6)}; // ${path6.path}
663
+ `
664
+ );
665
+ }
666
+ if (useSwitch) {
667
+ writer.writeBlockEnd("}");
668
+ }
669
+ }
670
+ if (dynamic == null ? void 0 : dynamic.route) {
671
+ writer.writeLines(
672
+ `if (${value}) return ${renderMatch(
673
+ verb,
674
+ dynamic.route,
675
+ dynamic.path
676
+ )}; // ${dynamic.path.path}`
677
+ );
678
+ }
934
679
  }
935
- } else {
936
- throw new Error(`Route ${key} has no handler for ${verb} requests`);
680
+ if (children || (dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
681
+ if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
682
+ writer.writeBlockEnd("} else {").indent++;
683
+ } else {
684
+ writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
685
+ closeCount++;
686
+ }
687
+ let value = `pathname.slice(${offset}, ${index} - 1)`;
688
+ if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
689
+ const segment = `s${next}`;
690
+ writer.writeLines(`const ${segment} = decodeURIComponent(${value});`);
691
+ value = segment;
692
+ } else if (children == null ? void 0 : children.some((child) => decodeURIComponent(child.key) !== child.key)) {
693
+ value = `decodeURIComponent(${value})`;
694
+ }
695
+ if (children) {
696
+ const useSwitch = children.length > 1;
697
+ if (useSwitch) {
698
+ writer.writeBlockStart(`switch (${value}) {`);
699
+ }
700
+ for (const child of children) {
701
+ const decodedKey = decodeURIComponent(child.key);
702
+ if (useSwitch) {
703
+ writer.writeBlockStart(`case '${decodedKey}': {`);
704
+ } else {
705
+ writer.writeBlockStart(`if (${value} === '${decodedKey}') {`);
706
+ }
707
+ const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
708
+ writeRouterVerb(writer, child, verb, next, nextOffset);
709
+ if (useSwitch) {
710
+ writer.writeBlockEnd("} break;");
711
+ } else {
712
+ writer.writeBlockEnd("}");
713
+ }
714
+ }
715
+ if (useSwitch) {
716
+ writer.writeBlockEnd("}");
717
+ }
718
+ }
719
+ if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
720
+ writer.writeBlockStart(`if (${value}) {`);
721
+ writeRouterVerb(writer, dynamic, verb, next, index);
722
+ writer.writeBlockEnd(`}`);
723
+ }
724
+ }
725
+ }
726
+ while (closeCount--) {
727
+ writer.writeBlockEnd("}");
728
+ }
729
+ if (catchAll) {
730
+ writer.writeLines(
731
+ `return ${renderMatch(
732
+ verb,
733
+ catchAll.route,
734
+ catchAll.path,
735
+ String(offset)
736
+ )}; // ${catchAll.path.path}`
737
+ );
738
+ } else if (level === 0) {
739
+ writer.writeLines("return null;");
937
740
  }
938
- if (!hasBody) {
939
- let i = len;
940
- while (i--) {
941
- const { id } = middleware[i];
942
- const name = `mware${id}`;
943
- nextName = currentName;
944
- currentName = i ? `__${name}` : "";
945
- writeMiddleware(continuations, name, nextName, currentName);
741
+ }
742
+ function wrapPropertyName(name) {
743
+ name = decodeURIComponent(name);
744
+ return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
745
+ }
746
+ function renderParams(params, pathIndex) {
747
+ let result = "";
748
+ let catchAll = "";
749
+ let sep = "{";
750
+ for (const [name, index] of Object.entries(params)) {
751
+ if (typeof index === "number") {
752
+ result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
753
+ sep = ",";
754
+ } else if (pathIndex) {
755
+ catchAll = name;
946
756
  }
947
757
  }
948
- continuations.join();
949
- writer.writeBlockEnd("}");
758
+ if (catchAll) {
759
+ result += `${sep} ${wrapPropertyName(
760
+ catchAll
761
+ )}: pathname.slice(${pathIndex})`;
762
+ }
763
+ return result ? result + " }" : "{}";
950
764
  }
951
- function renderRouter(routes, entriesDir, options = {
952
- trailingSlashes: "RedirectWithout"
953
- }) {
765
+ function renderMatch(verb, route, path6, pathIndex) {
766
+ const handler = `${verb}${route.index}`;
767
+ const params = path6.params ? renderParams(path6.params, pathIndex) : "{}";
768
+ const meta = route.meta ? `meta${route.index}` : "{}";
769
+ const pathPattern = pathToURLPatternString(path6.path);
770
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${pathPattern}' }`;
771
+ }
772
+ function renderMiddleware(middleware) {
954
773
  const writer = createStringWriter();
955
- writer.writeLines(`// @marko/run/router`);
774
+ writer.writeLines(
775
+ `// ${virtualFilePrefix}/${markoRunFilePrefix}middleware.js`
776
+ );
956
777
  const imports = writer.branch("imports");
957
778
  imports.writeLines(
958
- `import { NotHandled, NotMatched, createContext } from '${virtualFilePrefix}/runtime/internal';`
779
+ `import { normalize } from '${virtualFilePrefix}/runtime/internal';`
959
780
  );
960
- for (const route of routes.list) {
961
- const verbs = getVerbs(route);
962
- const names = verbs.map((verb) => `${verb}${route.index}`);
963
- route.meta && names.push(`meta${route.index}`);
964
- imports.writeLines(
965
- `import { ${names.join(", ")} } from '${virtualFilePrefix}/${route.entryName}.js';`
966
- );
781
+ writer.writeLines("");
782
+ for (const { id, importPath } of middleware) {
783
+ const importName = `middleware${id}`;
784
+ imports.writeLines(`import ${importName} from './${importPath}';`);
785
+ writer.writeLines(`export const mware${id} = normalize(${importName});`);
967
786
  }
968
- for (const route of Object.values(routes.special)) {
969
- const importPath = route.layouts.length ? `./${path2.posix.join(entriesDir, route.page.relativePath, "..", `route.${route.key}.marko`)}` : `./${route.page.importPath}`;
970
- imports.writeLines(
971
- `import page${route.key} from '${importPath}${serverEntryQuery}';`
972
- );
787
+ imports.join();
788
+ return writer.end();
789
+ }
790
+ function stripTsExtension(path6) {
791
+ const index = path6.lastIndexOf(".");
792
+ if (index !== -1) {
793
+ const ext = path6.slice(index + 1);
794
+ if (ext.toLowerCase() === "ts") {
795
+ return path6.slice(0, index);
796
+ }
973
797
  }
798
+ return path6;
799
+ }
800
+ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
801
+ var _a, _b;
802
+ const writer = createStringWriter();
974
803
  writer.writeLines(
975
- `
976
- globalThis.__marko_run__ = { match, fetch, invoke };
977
- `
978
- ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
979
- `if (!pathname) {
980
- pathname = '/';
981
- } else if (pathname.charAt(0) !== '/') {
982
- pathname = '/' + pathname;
983
- }`
984
- ).writeBlockStart(`switch (method) {`);
985
- for (const verb of httpVerbs) {
986
- const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
987
- if (filteredRoutes.length) {
988
- const trie = createRouteTrie(filteredRoutes);
989
- writer.writeLines(`case '${verb.toUpperCase()}':`);
990
- writer.writeBlockStart(`case '${verb.toLowerCase()}': {`);
991
- writeRouterVerb(writer, trie, verb);
992
- writer.writeBlockEnd("}");
804
+ `/*
805
+ WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
806
+ Do NOT manually edit this file or your changes will be lost.
807
+ */
808
+ `,
809
+ `import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace";`,
810
+ `import type * as Run from "@marko/run";`
811
+ );
812
+ const headWriter = writer.branch("head");
813
+ writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
814
+ if (adapter && adapter.typeInfo) {
815
+ const platformType = await adapter.typeInfo(
816
+ (data) => headWriter.write(data)
817
+ );
818
+ if (platformType) {
819
+ writer.writeLines(`interface Platform extends ${platformType} {}
820
+ `);
993
821
  }
994
822
  }
995
- writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
996
- writer.writeLines("").writeBlockStart(
997
- "export async function invoke(route, request, platform, url) {"
998
- ).writeLines(
999
- "const [context, buildInput] = createContext(route, request, platform, url);"
1000
- );
1001
- const hasErrorPage = Boolean(routes.special[RoutableFileTypes.Error]);
1002
- if (hasErrorPage) {
1003
- writer.writeBlockStart("try {");
823
+ headWriter.join();
824
+ writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
825
+ const routesWriter = writer.branch("routes");
826
+ writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
827
+ const routeTypes = /* @__PURE__ */ new Map();
828
+ for (const route of routes.list) {
829
+ let routeType = "";
830
+ for (const path6 of route.paths) {
831
+ const pathType = `"${pathToURLPatternString(path6.path)}"`;
832
+ routeType += routeType ? " | " + pathType : pathType;
833
+ routesWriter.writeLines(`${pathType}: Routes["${route.key}"];`);
834
+ }
835
+ for (const file of [route.handler, route.page]) {
836
+ if (file) {
837
+ const existing = routeTypes.get(file);
838
+ if (!existing) {
839
+ routeTypes.set(file, [routeType]);
840
+ } else {
841
+ existing.push(routeType);
842
+ }
843
+ }
844
+ }
845
+ for (const files of [route.middleware, route.layouts]) {
846
+ if (files) {
847
+ for (const file of files) {
848
+ const existing = routeTypes.get(file);
849
+ if (!existing) {
850
+ routeTypes.set(file, [routeType]);
851
+ } else {
852
+ existing.push(routeType);
853
+ }
854
+ }
855
+ }
856
+ }
1004
857
  }
1005
- writer.writeBlockStart("if (route) {").writeBlockStart("try {").writeLines(
1006
- "const response = await route.handler(context, buildInput);",
1007
- "if (response) return response;"
1008
- ).indent--;
1009
- writer.writeBlockStart("} catch (error) {").writeLines(
1010
- "if (error === NotHandled) return;",
1011
- "if (error !== NotMatched) throw error;"
1012
- ).writeBlockEnd("}").writeBlockEnd("}");
1013
- if (routes.special[RoutableFileTypes.NotFound]) {
1014
- imports.writeLines(
1015
- `
1016
- const page404ResponseInit = {
1017
- status: 404,
1018
- headers: { "content-type": "text/html;charset=UTF-8" },
1019
- };`
1020
- );
1021
- writer.write(`
1022
- if (context.request.headers.get('Accept')?.includes('text/html')) {
1023
- return new Response(page404.stream(buildInput()), page404ResponseInit);
858
+ for (const special of Object.values(routes.special)) {
859
+ routeTypes.set(special.page, []);
860
+ }
861
+ routesWriter.join();
862
+ const handlerWriter = writer.branch("handler");
863
+ const middlewareWriter = writer.branch("middleware");
864
+ const pageWriter = writer.branch("page");
865
+ const layoutWriter = writer.branch("layout");
866
+ for (const [file, types] of routeTypes) {
867
+ const path6 = `${pathPrefix}/${file.relativePath}`;
868
+ const routeType = `Run.Routes[${types.join(" | ")}]`;
869
+ switch (file.type) {
870
+ case RoutableFileTypes.Handler:
871
+ writeModuleDeclaration(handlerWriter, path6, routeType);
872
+ break;
873
+ case RoutableFileTypes.Middleware:
874
+ writeModuleDeclaration(middlewareWriter, path6, routeType);
875
+ break;
876
+ case RoutableFileTypes.Page:
877
+ writeModuleDeclaration(pageWriter, path6, routeType);
878
+ break;
879
+ case RoutableFileTypes.Layout:
880
+ writeModuleDeclaration(
881
+ layoutWriter,
882
+ path6,
883
+ routeType,
884
+ `
885
+ export interface Input {
886
+ renderBody: Marko.Body;
887
+ }`
888
+ );
889
+ break;
890
+ case RoutableFileTypes.Error:
891
+ writeModuleDeclaration(
892
+ writer,
893
+ path6,
894
+ "globalThis.MarkoRun.Route",
895
+ `
896
+ export interface Input {
897
+ error: unknown;
898
+ }`
899
+ );
900
+ break;
901
+ case RoutableFileTypes.NotFound:
902
+ writeModuleDeclaration(writer, path6, "Run.Route");
903
+ break;
1024
904
  }
1025
- `);
1026
905
  }
1027
- writer.indent--;
1028
- if (hasErrorPage) {
1029
- imports.writeLines(`
1030
- const page500ResponseInit = {
1031
- status: 500,
1032
- headers: { "content-type": "text/html;charset=UTF-8" },
1033
- };`);
1034
- writer.writeBlockStart(`} catch (error) {`).writeBlockStart(
1035
- `if (context.request.headers.get('Accept')?.includes('text/html')) {`
1036
- ).writeLines(
1037
- `return new Response(page500.stream(buildInput({ error })), page500ResponseInit);`
1038
- ).writeBlockEnd("}").writeLines("throw error;").writeBlockEnd("}");
906
+ handlerWriter.join();
907
+ middlewareWriter.join();
908
+ pageWriter.join();
909
+ layoutWriter.join();
910
+ writer.writeBlockStart(`
911
+ type Routes = {`);
912
+ for (const route of routes.list) {
913
+ const { meta, handler, page } = route;
914
+ if (page || handler) {
915
+ const verbs = [];
916
+ if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
917
+ verbs.push(`"get"`);
918
+ }
919
+ if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
920
+ verbs.push(`"post"`);
921
+ }
922
+ let routeType = `{ verb: ${verbs.join(" | ")};`;
923
+ if (meta) {
924
+ const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
925
+ let metaType = `typeof import("${metaPath}")`;
926
+ if (/\.(ts|js|mjs)$/.test(meta.name)) {
927
+ metaType += `["default"]`;
928
+ }
929
+ routeType += ` meta: ${metaType};`;
930
+ }
931
+ writer.writeLines(`"${route.key}": ${routeType} };`);
932
+ }
1039
933
  }
1040
934
  writer.writeBlockEnd("}");
1041
- renderFetch(writer, options);
1042
935
  return writer.end();
1043
936
  }
1044
- function renderFetch(writer, options) {
1045
- writer.write(`
1046
- export async function fetch(request, platform) {
1047
- try {
1048
- const url = new URL(request.url);
1049
- let { pathname } = url;`);
1050
- switch (options.trailingSlashes) {
1051
- case "RedirectWithout":
1052
- writer.write(`
1053
- if (pathname !== '/' && pathname.endsWith('/')) {
1054
- url.pathname = pathname.slice(0, -1);
1055
- return Response.redirect(url);
1056
- }`);
1057
- break;
1058
- case "RedirectWith":
1059
- writer.write(`
1060
- if (pathname !== '/' && !pathname.endsWith('/')) {
1061
- url.pathname = pathname + '/';
1062
- return Response.redirect(url);
1063
- }`);
1064
- break;
1065
- case "RewriteWithout":
1066
- writer.write(`
1067
- if (pathname !== '/' && pathname.endsWith('/')) {
1068
- url.pathname = pathname = pathname.slice(0, -1);
1069
- }`);
1070
- break;
1071
- case "RewriteWith":
1072
- writer.write(`
1073
- if (pathname !== '/' && !pathname.endsWith('/')) {
1074
- url.pathname = pathname = pathname + '/';
1075
- }`);
1076
- break;
937
+ function writeModuleDeclaration(writer, path6, routeType, moduleTypes) {
938
+ writer.writeLines("").write(`declare module "${stripTsExtension(path6)}" {`);
939
+ if (moduleTypes) {
940
+ writer.write(moduleTypes);
1077
941
  }
1078
- writer.write(`
1079
-
1080
- const route = match(request.method, pathname);
1081
- return await invoke(route, request, platform, url);
1082
- } catch (error) {
1083
- if (import.meta.env.DEV) {
1084
- throw error;
1085
- }
1086
- return new Response(null, {
1087
- status: 500
1088
- });
942
+ if (routeType) {
943
+ const isMarko = path6.endsWith(".marko");
944
+ writer.write(`
945
+ namespace MarkoRun {
946
+ export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
947
+ export type Route = ${routeType};
948
+ export type Context = Run.MultiRouteContext<Route>${isMarko ? " & Marko.Global" : ""};
949
+ export type Handler = Run.HandlerLike<Route>;
950
+ /** @deprecated use \`((context, next) => { ... }) satisfies MarkoRun.Handler\` instead */
951
+ export const route: Run.HandlerTypeFn<Route>;
952
+ }`);
1089
953
  }
954
+ writer.writeLines(`
1090
955
  }`);
1091
956
  }
1092
- function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
1093
- const { route, dynamic, catchAll } = trie;
1094
- let closeCount = 0;
1095
- if (level === 0) {
1096
- writer.writeLines(`const len = pathname.length;`);
1097
- if (route) {
1098
- writer.writeLines(
1099
- `if (len === 1) return ${renderMatch(verb, route, trie.path)}; // ${trie.path.path}`
1100
- );
1101
- } else if (trie.static || dynamic) {
1102
- writer.writeBlockStart(`if (len > 1) {`);
1103
- closeCount++;
957
+ function pathToURLPatternString(path6) {
958
+ return path6.replace(/\/\$(\$?)([^/]*)/g, (_, catchAll, name) => {
959
+ name = decodeURIComponent(name);
960
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
961
+ });
962
+ }
963
+ function createRouteTrie(routes) {
964
+ const root = {
965
+ key: ""
966
+ };
967
+ function insert(path6, route) {
968
+ let node = root;
969
+ for (const segment of path6.segments) {
970
+ if (segment === "$$") {
971
+ node.catchAll ?? (node.catchAll = { route, path: path6 });
972
+ return;
973
+ } else if (segment === "$") {
974
+ node = node.dynamic ?? (node.dynamic = {
975
+ key: ""
976
+ });
977
+ } else {
978
+ node.static ?? (node.static = /* @__PURE__ */ new Map());
979
+ let next = node.static.get(segment);
980
+ if (!next) {
981
+ next = {
982
+ key: segment
983
+ };
984
+ node.static.set(segment, next);
985
+ }
986
+ node = next;
987
+ }
1104
988
  }
989
+ node.path ?? (node.path = path6);
990
+ node.route ?? (node.route = route);
1105
991
  }
1106
- if (trie.static || dynamic) {
1107
- const next = level + 1;
1108
- const index = `i${next}`;
1109
- let terminal;
1110
- let children;
1111
- writer.writeLines(`const ${index} = pathname.indexOf('/', ${offset}) + 1;`);
1112
- if (trie.static) {
1113
- for (const child of trie.static.values()) {
1114
- if (child.route) {
1115
- (terminal ?? (terminal = [])).push(child);
992
+ for (const route of routes) {
993
+ for (const path6 of route.paths) {
994
+ insert(path6, route);
995
+ }
996
+ }
997
+ return root;
998
+ }
999
+
1000
+ // src/vite/routes/parse.ts
1001
+ function parseFlatRoute(pattern) {
1002
+ if (!pattern) throw new Error("Empty pattern");
1003
+ const len = pattern.length;
1004
+ let i = 0;
1005
+ return parse2([
1006
+ {
1007
+ id: "/",
1008
+ segments: [],
1009
+ source: pattern
1010
+ }
1011
+ ]);
1012
+ function parse2(basePaths, group) {
1013
+ const pathMap = /* @__PURE__ */ new Map();
1014
+ const delimiters = group ? ").," : ".,";
1015
+ let charCode;
1016
+ let segmentStart = i;
1017
+ let type;
1018
+ let current;
1019
+ do {
1020
+ charCode = pattern.charCodeAt(i);
1021
+ if (charCode === 41 && group) {
1022
+ break;
1023
+ } else if (charCode === 44) {
1024
+ if (!current) {
1025
+ segmentEnd(
1026
+ basePaths.map((path6) => ({
1027
+ ...path6,
1028
+ segments: path6.segments.slice()
1029
+ })),
1030
+ "",
1031
+ "_",
1032
+ pathMap
1033
+ );
1034
+ } else {
1035
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1116
1036
  }
1117
- if (child.static || child.dynamic || child.catchAll) {
1118
- (children ?? (children = [])).push(child);
1037
+ current = void 0;
1038
+ type = void 0;
1039
+ segmentStart = ++i;
1040
+ } else if (charCode === 46) {
1041
+ if (current) {
1042
+ segmentEnd(current, pattern.slice(segmentStart, i), type);
1119
1043
  }
1120
- }
1121
- }
1122
- if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
1123
- closeCount++;
1124
- writer.writeBlockStart(`if (!${index} || ${index} === len) {`);
1125
- let value = `pathname.slice(${offset}, ${index} ? -1 : len)`;
1126
- if (dynamic == null ? void 0 : dynamic.route) {
1127
- const segment = `s${next}`;
1128
- writer.writeLines(`const ${segment} = decodeURIComponent(${value});`);
1129
- value = segment;
1130
- } else if (terminal == null ? void 0 : terminal.some(
1131
- (terminal2) => decodeURIComponent(terminal2.key) !== terminal2.key
1132
- )) {
1133
- value = `decodeURIComponent(${value})`;
1134
- }
1135
- if (terminal) {
1136
- const useSwitch = terminal.length > 1;
1137
- if (useSwitch) {
1138
- writer.writeBlockStart(`switch (${value}) {`);
1044
+ type = void 0;
1045
+ segmentStart = ++i;
1046
+ } else if (charCode === 40) {
1047
+ const groupPaths = parse2(current || basePaths, ++i);
1048
+ if (groupPaths.length) {
1049
+ current = groupPaths;
1139
1050
  }
1140
- for (const { key, path: path6, route: route2 } of terminal) {
1141
- const decodedKey = decodeURIComponent(key);
1142
- if (useSwitch) {
1143
- writer.write(`case '${decodedKey}': `, true);
1144
- } else {
1145
- writer.write(`if (${value} === '${decodedKey}') `, true);
1051
+ segmentStart = ++i;
1052
+ } else {
1053
+ if (charCode === 95) {
1054
+ type = "_";
1055
+ } else if (charCode === 36) {
1056
+ type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
1057
+ }
1058
+ current ?? (current = basePaths.map((path6) => ({
1059
+ ...path6,
1060
+ segments: path6.segments.slice()
1061
+ })));
1062
+ i = len;
1063
+ for (const char of delimiters) {
1064
+ const index = pattern.indexOf(char, segmentStart);
1065
+ if (index >= 0 && index < i) {
1066
+ i = index;
1146
1067
  }
1147
- writer.write(
1148
- `return ${renderMatch(verb, route2, path6)}; // ${path6.path}
1149
- `
1068
+ }
1069
+ }
1070
+ } while (i < len);
1071
+ if (group && charCode !== 41) {
1072
+ throw new Error(
1073
+ `Invalid route pattern: group was not closed '${pattern.slice(
1074
+ group
1075
+ )}' in '${pattern}'`
1076
+ );
1077
+ }
1078
+ if (!current) {
1079
+ segmentEnd(
1080
+ basePaths.map((path6) => ({
1081
+ ...path6,
1082
+ segments: path6.segments.slice()
1083
+ })),
1084
+ "",
1085
+ "_",
1086
+ pathMap
1087
+ );
1088
+ } else {
1089
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1090
+ }
1091
+ return [...pathMap.values()];
1092
+ }
1093
+ function segmentEnd(paths, raw, type, map) {
1094
+ let segment;
1095
+ if (raw) {
1096
+ segment = {
1097
+ raw,
1098
+ name: raw,
1099
+ type
1100
+ };
1101
+ if (type === "$" || type === "$$") {
1102
+ segment.name = type;
1103
+ segment.param = raw.slice(type.length);
1104
+ }
1105
+ }
1106
+ for (const path6 of paths) {
1107
+ if (segment) {
1108
+ if (path6.isCatchall) {
1109
+ throw new Error(
1110
+ `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
1111
+ 0,
1112
+ i
1113
+ )}' in '${pattern}'.`
1150
1114
  );
1151
1115
  }
1152
- if (useSwitch) {
1153
- writer.writeBlockEnd("}");
1116
+ path6.segments.push(segment);
1117
+ path6.id += path6.id === "/" ? segment.name : `/${segment.name}`;
1118
+ if (type === "$$") {
1119
+ path6.isCatchall = true;
1154
1120
  }
1155
1121
  }
1156
- if (dynamic == null ? void 0 : dynamic.route) {
1157
- writer.writeLines(
1158
- `if (${value}) return ${renderMatch(
1159
- verb,
1160
- dynamic.route,
1161
- dynamic.path
1162
- )}; // ${dynamic.path.path}`
1163
- );
1122
+ if (map) {
1123
+ if (map.has(path6.id)) {
1124
+ const existing = map.get(path6.id);
1125
+ const existingExpansion = existing.segments.map((s) => s.raw).join(".");
1126
+ const currentExpansion = path6.segments.map((s) => s.raw).join(".");
1127
+ throw new Error(
1128
+ `Invalid route pattern: route '${path6.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
1129
+ );
1130
+ }
1131
+ map.set(path6.id, path6);
1164
1132
  }
1165
1133
  }
1166
- if (children || (dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
1167
- if (terminal || (dynamic == null ? void 0 : dynamic.route)) {
1168
- writer.writeBlockEnd("} else {").indent++;
1169
- } else {
1170
- writer.writeBlockStart(`if (${index} && ${index} !== len) {`);
1171
- closeCount++;
1172
- }
1173
- let value = `pathname.slice(${offset}, ${index} - 1)`;
1174
- if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
1175
- const segment = `s${next}`;
1176
- writer.writeLines(`const ${segment} = decodeURIComponent(${value});`);
1177
- value = segment;
1178
- } else if (children == null ? void 0 : children.some((child) => decodeURIComponent(child.key) !== child.key)) {
1179
- value = `decodeURIComponent(${value})`;
1134
+ }
1135
+ }
1136
+
1137
+ // src/vite/routes/vdir.ts
1138
+ var _dirs, _pathlessDirs;
1139
+ var _VDir = class _VDir {
1140
+ constructor(parent, segment, source) {
1141
+ __privateAdd(this, _dirs);
1142
+ __privateAdd(this, _pathlessDirs);
1143
+ __publicField(this, "parent");
1144
+ __publicField(this, "source");
1145
+ __publicField(this, "path");
1146
+ __publicField(this, "fullPath");
1147
+ __publicField(this, "segment");
1148
+ __publicField(this, "files");
1149
+ if (!parent || !segment) {
1150
+ this.parent = null;
1151
+ this.source = null;
1152
+ this.path = "/";
1153
+ this.fullPath = "/";
1154
+ this.segment = {
1155
+ raw: "",
1156
+ name: ""
1157
+ };
1158
+ } else {
1159
+ this.parent = parent;
1160
+ this.source = source;
1161
+ this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
1162
+ this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
1163
+ if (segment.param) {
1164
+ this.fullPath += segment.param;
1180
1165
  }
1181
- if (children) {
1182
- const useSwitch = children.length > 1;
1183
- if (useSwitch) {
1184
- writer.writeBlockStart(`switch (${value}) {`);
1185
- }
1186
- for (const child of children) {
1187
- const decodedKey = decodeURIComponent(child.key);
1188
- if (useSwitch) {
1189
- writer.writeBlockStart(`case '${decodedKey}': {`);
1190
- } else {
1191
- writer.writeBlockStart(`if (${value} === '${decodedKey}') {`);
1192
- }
1193
- const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
1194
- writeRouterVerb(writer, child, verb, next, nextOffset);
1195
- if (useSwitch) {
1196
- writer.writeBlockEnd("} break;");
1197
- } else {
1198
- writer.writeBlockEnd("}");
1166
+ this.segment = segment;
1167
+ }
1168
+ }
1169
+ get pathInfo() {
1170
+ const value = {
1171
+ id: "/",
1172
+ path: "/",
1173
+ segments: []
1174
+ };
1175
+ let sep = "";
1176
+ for (const { segment } of this) {
1177
+ const { type, name, param } = segment;
1178
+ if (name && type !== "_") {
1179
+ value.id += sep + (type || name);
1180
+ value.path += sep + name;
1181
+ value.isEnd = type === "$$";
1182
+ if (param) {
1183
+ value.path += param;
1184
+ const index = type === "$$" ? null : value.segments.length;
1185
+ if (!value.params) {
1186
+ value.params = { [param]: index };
1187
+ } else if (!(param in value.params)) {
1188
+ value.params[param] = index;
1199
1189
  }
1200
1190
  }
1201
- if (useSwitch) {
1202
- writer.writeBlockEnd("}");
1203
- }
1204
- }
1205
- if ((dynamic == null ? void 0 : dynamic.static) || (dynamic == null ? void 0 : dynamic.dynamic) || (dynamic == null ? void 0 : dynamic.catchAll)) {
1206
- writer.writeBlockStart(`if (${value}) {`);
1207
- writeRouterVerb(writer, dynamic, verb, next, index);
1208
- writer.writeBlockEnd(`}`);
1191
+ value.segments.push(name);
1192
+ sep = "/";
1209
1193
  }
1210
1194
  }
1195
+ Object.defineProperty(this, "pathInfo", {
1196
+ value,
1197
+ enumerable: true
1198
+ });
1199
+ return value;
1211
1200
  }
1212
- while (closeCount--) {
1213
- writer.writeBlockEnd("}");
1214
- }
1215
- if (catchAll) {
1216
- writer.writeLines(
1217
- `return ${renderMatch(
1218
- verb,
1219
- catchAll.route,
1220
- catchAll.path,
1221
- String(offset)
1222
- )}; // ${catchAll.path.path}`
1223
- );
1224
- } else if (level === 0) {
1225
- writer.writeLines("return null;");
1226
- }
1227
- }
1228
- function wrapPropertyName(name) {
1229
- name = decodeURIComponent(name);
1230
- return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
1231
- }
1232
- function renderParams(params, pathIndex) {
1233
- let result = "";
1234
- let catchAll = "";
1235
- let sep = "{";
1236
- for (const [name, index] of Object.entries(params)) {
1237
- if (typeof index === "number") {
1238
- result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
1239
- sep = ",";
1240
- } else if (pathIndex) {
1241
- catchAll = name;
1201
+ addDir(path6, segment) {
1202
+ const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
1203
+ if (!map.has(segment.name)) {
1204
+ const dir = new _VDir(this, segment, path6);
1205
+ map.set(segment.name, dir);
1206
+ return dir;
1242
1207
  }
1208
+ return map.get(segment.name);
1243
1209
  }
1244
- if (catchAll) {
1245
- result += `${sep} ${wrapPropertyName(
1246
- catchAll
1247
- )}: pathname.slice(${pathIndex})`;
1248
- }
1249
- return result ? result + " }" : "{}";
1250
- }
1251
- function renderMatch(verb, route, path6, pathIndex) {
1252
- const handler = `${verb}${route.index}`;
1253
- const params = path6.params ? renderParams(path6.params, pathIndex) : "{}";
1254
- const meta = route.meta ? `meta${route.index}` : "{}";
1255
- const pathPattern = pathToURLPatternString(path6.path);
1256
- return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${pathPattern}' }`;
1257
- }
1258
- function renderMiddleware(middleware) {
1259
- const writer = createStringWriter();
1260
- writer.writeLines(
1261
- `// ${virtualFilePrefix}/${markoRunFilePrefix}middleware.js`
1262
- );
1263
- const imports = writer.branch("imports");
1264
- imports.writeLines(
1265
- `import { normalize } from '${virtualFilePrefix}/runtime/internal';`
1266
- );
1267
- writer.writeLines("");
1268
- for (const { id, importPath } of middleware) {
1269
- const importName = `middleware${id}`;
1270
- imports.writeLines(`import ${importName} from './${importPath}';`);
1271
- writer.writeLines(`export const mware${id} = normalize(${importName});`);
1272
- }
1273
- imports.join();
1274
- return writer.end();
1275
- }
1276
- function stripTsExtension(path6) {
1277
- const index = path6.lastIndexOf(".");
1278
- if (index !== -1) {
1279
- const ext = path6.slice(index + 1);
1280
- if (ext.toLowerCase() === "ts") {
1281
- return path6.slice(0, index);
1210
+ addFile(file) {
1211
+ if (!this.files) {
1212
+ this.files = /* @__PURE__ */ new Map();
1213
+ this.files.set(file.type, file);
1214
+ } else if (!this.files.has(file.type)) {
1215
+ this.files.set(file.type, file);
1216
+ } else {
1217
+ const existing = this.files.get(file.type);
1218
+ if (existing !== file) {
1219
+ throw new Error(
1220
+ `Duplicate file type '${file.type}' added at path '${this.path}'. File '${file.importPath}' collides with '${existing.importPath}'.`
1221
+ );
1222
+ } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
1223
+ throw new Error(
1224
+ `Ambiguous path definition: route '${this.path}' is defined multiple times by ${file.importPath}`
1225
+ );
1226
+ }
1227
+ throw new Error(
1228
+ `Ambiguous path definition: file '${this.path}' is included multiple times by ${file.importPath}`
1229
+ );
1282
1230
  }
1283
- }
1284
- return path6;
1285
- }
1286
- async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1287
- var _a, _b;
1288
- const writer = createStringWriter();
1289
- writer.writeLines(
1290
- `/*
1291
- WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
1292
- Do NOT manually edit this file or your changes will be lost.
1293
- */
1294
- `,
1295
- `import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace";`,
1296
- `import type * as Run from "@marko/run";`
1297
- );
1298
- const headWriter = writer.branch("head");
1299
- writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
1300
- if (adapter && adapter.typeInfo) {
1301
- const platformType = await adapter.typeInfo(
1302
- (data) => headWriter.write(data)
1303
- );
1304
- if (platformType) {
1305
- writer.writeLines(`interface Platform extends ${platformType} {}
1306
- `);
1231
+ }
1232
+ *dirs() {
1233
+ if (__privateGet(this, _pathlessDirs)) {
1234
+ yield* __privateGet(this, _pathlessDirs).values();
1235
+ }
1236
+ if (__privateGet(this, _dirs)) {
1237
+ yield* __privateGet(this, _dirs).values();
1307
1238
  }
1308
1239
  }
1309
- headWriter.join();
1310
- writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
1311
- const routesWriter = writer.branch("routes");
1312
- writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
1313
- const routeTypes = /* @__PURE__ */ new Map();
1314
- for (const route of routes.list) {
1315
- let routeType = "";
1316
- for (const path6 of route.paths) {
1317
- const pathType = `"${pathToURLPatternString(path6.path)}"`;
1318
- routeType += routeType ? " | " + pathType : pathType;
1319
- routesWriter.writeLines(`${pathType}: Routes["${route.key}"];`);
1240
+ *[Symbol.iterator]() {
1241
+ if (this.parent) {
1242
+ yield* this.parent;
1320
1243
  }
1321
- for (const file of [route.handler, route.page]) {
1322
- if (file) {
1323
- const existing = routeTypes.get(file);
1324
- if (!existing) {
1325
- routeTypes.set(file, [routeType]);
1326
- } else {
1327
- existing.push(routeType);
1244
+ yield this;
1245
+ }
1246
+ static addPaths(roots, paths) {
1247
+ const dirs = [];
1248
+ const unique = /* @__PURE__ */ new Set();
1249
+ for (const root of roots) {
1250
+ for (const path6 of paths) {
1251
+ let dir = root;
1252
+ for (const segment of path6.segments) {
1253
+ dir = dir.addDir(path6, segment);
1328
1254
  }
1329
- }
1330
- }
1331
- for (const files of [route.middleware, route.layouts]) {
1332
- if (files) {
1333
- for (const file of files) {
1334
- const existing = routeTypes.get(file);
1335
- if (!existing) {
1336
- routeTypes.set(file, [routeType]);
1337
- } else {
1338
- existing.push(routeType);
1255
+ if (unique.has(dir.path)) {
1256
+ const sources = /* @__PURE__ */ new Set();
1257
+ let sourcePath = "";
1258
+ for (const { source } of dir) {
1259
+ if (source && !sources.has(source.source)) {
1260
+ sources.add(source.source);
1261
+ sourcePath += source.source + "/";
1262
+ }
1339
1263
  }
1264
+ throw new Error(
1265
+ `Ambiguous directory structure: '${sourcePath}${path6.source}' defines '${dir.path}' multiple times.`
1266
+ );
1267
+ } else {
1268
+ unique.add(dir.path);
1269
+ dirs.push(dir);
1340
1270
  }
1341
1271
  }
1342
1272
  }
1273
+ return dirs;
1343
1274
  }
1344
- for (const special of Object.values(routes.special)) {
1345
- routeTypes.set(special.page, []);
1346
- }
1347
- routesWriter.join();
1348
- const handlerWriter = writer.branch("handler");
1349
- const middlewareWriter = writer.branch("middleware");
1350
- const pageWriter = writer.branch("page");
1351
- const layoutWriter = writer.branch("layout");
1352
- for (const [file, types] of routeTypes) {
1353
- const path6 = `${pathPrefix}/${file.relativePath}`;
1354
- const routeType = `Run.Routes[${types.join(" | ")}]`;
1355
- switch (file.type) {
1356
- case RoutableFileTypes.Handler:
1357
- writeModuleDeclaration(handlerWriter, path6, routeType);
1358
- break;
1359
- case RoutableFileTypes.Middleware:
1360
- writeModuleDeclaration(middlewareWriter, path6, routeType);
1361
- break;
1362
- case RoutableFileTypes.Page:
1363
- writeModuleDeclaration(pageWriter, path6, routeType);
1364
- break;
1365
- case RoutableFileTypes.Layout:
1366
- writeModuleDeclaration(
1367
- layoutWriter,
1368
- path6,
1369
- routeType,
1370
- `
1371
- export interface Input {
1372
- renderBody: Marko.Body;
1373
- }`
1374
- );
1375
- break;
1376
- case RoutableFileTypes.Error:
1377
- writeModuleDeclaration(
1378
- writer,
1379
- path6,
1380
- "globalThis.MarkoRun.Route",
1381
- `
1382
- export interface Input {
1383
- error: unknown;
1384
- }`
1275
+ };
1276
+ _dirs = new WeakMap();
1277
+ _pathlessDirs = new WeakMap();
1278
+ var VDir = _VDir;
1279
+
1280
+ // src/vite/routes/builder.ts
1281
+ var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
1282
+ var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
1283
+ var routeableFileRegex = new RegExp(
1284
+ `[+](?:${markoFiles}|${nonMarkoFiles})$`,
1285
+ "i"
1286
+ );
1287
+ function matchRoutableFile(filename) {
1288
+ const match = filename.match(routeableFileRegex);
1289
+ return match && (match[1] || match[3]).toLowerCase();
1290
+ }
1291
+ function isSpecialType(type) {
1292
+ return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
1293
+ }
1294
+ async function buildRoutes(sources) {
1295
+ const uniqueRoutes = /* @__PURE__ */ new Map();
1296
+ const routes = [];
1297
+ const special = {};
1298
+ const middlewares = /* @__PURE__ */ new Set();
1299
+ const unusedFiles = /* @__PURE__ */ new Set();
1300
+ const currentLayouts = /* @__PURE__ */ new Set();
1301
+ const currentMiddleware = /* @__PURE__ */ new Set();
1302
+ const root = new VDir();
1303
+ const dirStack = [];
1304
+ let basePath;
1305
+ let importPrefix;
1306
+ let activeDirs;
1307
+ let isBaseDir;
1308
+ let nextFileId = 1;
1309
+ let nextRouteIndex = 1;
1310
+ const walkOptions = {
1311
+ onEnter({ name }) {
1312
+ const prevDirStackLength = dirStack.length;
1313
+ if (isBaseDir) {
1314
+ isBaseDir = false;
1315
+ if (!basePath) {
1316
+ return;
1317
+ }
1318
+ name = basePath;
1319
+ } else {
1320
+ dirStack.push(name);
1321
+ }
1322
+ const previousDirs = activeDirs;
1323
+ const paths = parseFlatRoute(name);
1324
+ activeDirs = VDir.addPaths(previousDirs, paths);
1325
+ return () => {
1326
+ activeDirs = previousDirs;
1327
+ dirStack.length = prevDirStackLength;
1328
+ };
1329
+ },
1330
+ onFile({ name, path: path6 }) {
1331
+ const match = name.match(routeableFileRegex);
1332
+ if (!match) {
1333
+ return;
1334
+ }
1335
+ const type = (match[1] || match[3]).toLowerCase();
1336
+ if (dirStack.length && isSpecialType(type)) {
1337
+ console.warn(
1338
+ `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${path6}`
1385
1339
  );
1386
- break;
1387
- case RoutableFileTypes.NotFound:
1388
- writeModuleDeclaration(writer, path6, "Run.Route");
1389
- break;
1340
+ return;
1341
+ }
1342
+ let dirs = activeDirs;
1343
+ if (match.index) {
1344
+ const paths = parseFlatRoute(name.slice(0, match.index));
1345
+ dirs = VDir.addPaths(activeDirs, paths);
1346
+ }
1347
+ const dirPath = dirStack.join("/");
1348
+ const relativePath = dirPath ? `${dirPath}/${name}` : name;
1349
+ const file = {
1350
+ id: String(nextFileId++),
1351
+ name,
1352
+ type,
1353
+ filePath: path6,
1354
+ relativePath,
1355
+ importPath: `${importPrefix}/${relativePath}`,
1356
+ verbs: type === RoutableFileTypes.Page ? ["get", "head"] : void 0
1357
+ };
1358
+ for (const dir of dirs) {
1359
+ dir.addFile(file);
1360
+ }
1390
1361
  }
1362
+ };
1363
+ if (!Array.isArray(sources)) {
1364
+ sources = [sources];
1391
1365
  }
1392
- handlerWriter.join();
1393
- middlewareWriter.join();
1394
- pageWriter.join();
1395
- layoutWriter.join();
1396
- writer.writeBlockStart(`
1397
- type Routes = {`);
1398
- for (const route of routes.list) {
1399
- const { meta, handler, page } = route;
1400
- if (page || handler) {
1401
- const verbs = [];
1402
- if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
1403
- verbs.push(`"get"`);
1366
+ for (const source of sources) {
1367
+ importPrefix = source.importPrefix ? source.importPrefix.replace(/^\/+|\/+$/g, "") : "";
1368
+ basePath = source.basePath || "";
1369
+ activeDirs = [root];
1370
+ isBaseDir = true;
1371
+ await source.walker(walkOptions);
1372
+ }
1373
+ traverse(root);
1374
+ return {
1375
+ list: routes,
1376
+ middleware: [...middlewares],
1377
+ special
1378
+ };
1379
+ function traverse(dir) {
1380
+ let middleware;
1381
+ let layout;
1382
+ if (dir.files) {
1383
+ middleware = dir.files.get(RoutableFileTypes.Middleware);
1384
+ layout = dir.files.get(RoutableFileTypes.Layout);
1385
+ const handler = dir.files.get(RoutableFileTypes.Handler);
1386
+ const page = dir.files.get(RoutableFileTypes.Page);
1387
+ let hasSpecial = false;
1388
+ if (middleware) {
1389
+ if (currentMiddleware.has(middleware)) {
1390
+ middleware = void 0;
1391
+ } else {
1392
+ currentMiddleware.add(middleware);
1393
+ unusedFiles.add(middleware);
1394
+ }
1395
+ }
1396
+ if (layout) {
1397
+ if (currentLayouts.has(layout)) {
1398
+ layout = void 0;
1399
+ } else {
1400
+ currentLayouts.add(layout);
1401
+ unusedFiles.add(layout);
1402
+ }
1403
+ }
1404
+ if (page || handler) {
1405
+ const path6 = dir.pathInfo;
1406
+ if (uniqueRoutes.has(path6.id)) {
1407
+ const existing = uniqueRoutes.get(path6.id);
1408
+ const route = routes[existing.index];
1409
+ const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
1410
+ const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
1411
+ throw new Error(`Duplicate routes for path '${path6.path}' were defined. A route established by:
1412
+ ${existingFiles.join(" and ")} via '${existing.dir.path}'
1413
+ collides with
1414
+ ${currentFiles.join(" and ")} via '${dir.path}'
1415
+ `);
1416
+ }
1417
+ uniqueRoutes.set(path6.id, { dir, index: routes.length });
1418
+ routes.push({
1419
+ index: nextRouteIndex++,
1420
+ key: dir.fullPath,
1421
+ paths: [path6],
1422
+ middleware: [...currentMiddleware],
1423
+ layouts: page ? [...currentLayouts] : [],
1424
+ meta: dir.files.get(RoutableFileTypes.Meta),
1425
+ page,
1426
+ handler,
1427
+ entryName: `${markoRunFilePrefix}route` + (dir.path !== "/" ? dir.fullPath.replace(/\//g, ".").replace(/(%[A-Fa-f0-9]{2})+/g, "_") : "")
1428
+ });
1404
1429
  }
1405
- if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
1406
- verbs.push(`"post"`);
1430
+ if (dir === root) {
1431
+ for (const [type, file] of dir.files) {
1432
+ if (isSpecialType(type)) {
1433
+ hasSpecial = true;
1434
+ special[type] = {
1435
+ index: 0,
1436
+ key: type,
1437
+ paths: [],
1438
+ middleware: [],
1439
+ layouts: [...currentLayouts],
1440
+ page: file,
1441
+ entryName: `${markoRunFilePrefix}special.${type}`
1442
+ };
1443
+ }
1444
+ }
1407
1445
  }
1408
- let routeType = `{ verb: ${verbs.join(" | ")};`;
1409
- if (meta) {
1410
- const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1411
- let metaType = `typeof import("${metaPath}")`;
1412
- if (/\.(ts|js|mjs)$/.test(meta.name)) {
1413
- metaType += `["default"]`;
1446
+ if (handler || page) {
1447
+ for (const middleware2 of currentMiddleware) {
1448
+ middlewares.add(middleware2);
1449
+ unusedFiles.delete(middleware2);
1450
+ }
1451
+ }
1452
+ if (page || hasSpecial) {
1453
+ for (const layout2 of currentLayouts) {
1454
+ unusedFiles.delete(layout2);
1414
1455
  }
1415
- routeType += ` meta: ${metaType};`;
1416
1456
  }
1417
- writer.writeLines(`"${route.key}": ${routeType} };`);
1457
+ }
1458
+ if (dir.dirs) {
1459
+ for (const child of dir.dirs()) {
1460
+ traverse(child);
1461
+ }
1462
+ }
1463
+ if (middleware) {
1464
+ currentMiddleware.delete(middleware);
1465
+ }
1466
+ if (layout) {
1467
+ currentLayouts.delete(layout);
1418
1468
  }
1419
1469
  }
1420
- writer.writeBlockEnd("}");
1421
- return writer.end();
1422
- }
1423
- function writeModuleDeclaration(writer, path6, routeType, moduleTypes) {
1424
- writer.writeLines("").write(`declare module "${stripTsExtension(path6)}" {`);
1425
- if (moduleTypes) {
1426
- writer.write(moduleTypes);
1427
- }
1428
- if (routeType) {
1429
- const isMarko = path6.endsWith(".marko");
1430
- writer.write(`
1431
- namespace MarkoRun {
1432
- export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
1433
- export type Route = ${routeType};
1434
- export type Context = Run.MultiRouteContext<Route>${isMarko ? " & Marko.Global" : ""};
1435
- export type Handler = Run.HandlerLike<Route>;
1436
- /** @deprecated use \`((context, next) => { ... }) satisfies MarkoRun.Handler\` instead */
1437
- export const route: Run.HandlerTypeFn<Route>;
1438
- }`);
1439
- }
1440
- writer.writeLines(`
1441
- }`);
1442
- }
1443
- function pathToURLPatternString(path6) {
1444
- return path6.replace(/\/\$(\$?)([^\/]*)/g, (_, catchAll, name) => {
1445
- name = decodeURIComponent(name);
1446
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1447
- });
1448
1470
  }
1449
- function createRouteTrie(routes) {
1450
- const root = {
1451
- key: ""
1452
- };
1453
- function insert(path6, route) {
1454
- let node = root;
1455
- for (const segment of path6.segments) {
1456
- if (segment === "$$") {
1457
- node.catchAll ?? (node.catchAll = { route, path: path6 });
1458
- return;
1459
- } else if (segment === "$") {
1460
- node = node.dynamic ?? (node.dynamic = {
1461
- key: ""
1471
+
1472
+ // src/vite/routes/walk.ts
1473
+ import fs from "fs";
1474
+ import path2 from "path";
1475
+ function createFSWalker(dir) {
1476
+ return async function walkFS({
1477
+ onEnter,
1478
+ onFile,
1479
+ onDir,
1480
+ maxDepth = 50
1481
+ }) {
1482
+ async function walk(dir2, depth) {
1483
+ const onExit = onEnter == null ? void 0 : onEnter(dir2);
1484
+ if (onExit !== false) {
1485
+ const dirs = [];
1486
+ const entries = await fs.promises.readdir(dir2.path, {
1487
+ withFileTypes: true
1462
1488
  });
1463
- } else {
1464
- node.static ?? (node.static = /* @__PURE__ */ new Map());
1465
- let next = node.static.get(segment);
1466
- if (!next) {
1467
- next = {
1468
- key: segment
1489
+ const prefix = dir2.path + path2.sep;
1490
+ for (const entry of entries) {
1491
+ const walkEntry = {
1492
+ name: entry.name,
1493
+ path: prefix + entry.name
1469
1494
  };
1470
- node.static.set(segment, next);
1495
+ if (entry.isDirectory()) {
1496
+ dirs.push(walkEntry);
1497
+ } else {
1498
+ onFile == null ? void 0 : onFile(walkEntry);
1499
+ }
1471
1500
  }
1472
- node = next;
1501
+ if ((onDir == null ? void 0 : onDir()) !== false && --depth > 0) {
1502
+ for (const entry of dirs) {
1503
+ await walk(entry, depth);
1504
+ }
1505
+ }
1506
+ onExit == null ? void 0 : onExit();
1473
1507
  }
1474
1508
  }
1475
- node.path ?? (node.path = path6);
1476
- node.route ?? (node.route = route);
1477
- }
1478
- for (const route of routes) {
1479
- for (const path6 of route.paths) {
1480
- insert(path6, route);
1481
- }
1482
- }
1483
- return root;
1509
+ await walk(
1510
+ {
1511
+ path: dir,
1512
+ name: path2.basename(dir)
1513
+ },
1514
+ maxDepth
1515
+ );
1516
+ };
1484
1517
  }
1485
1518
 
1486
1519
  // src/vite/utils/ast.ts
@@ -1539,25 +1572,39 @@ function getViteSSRExportIdentifiers(astProgramNode, exportObjectName = "__vite_
1539
1572
  return result;
1540
1573
  }
1541
1574
 
1575
+ // src/vite/utils/config.ts
1576
+ var PluginConfigKey = "__MARKO_RUN_PLUGIN_CONFIG__";
1577
+ var AdapterConfigKey = "__MARKO_RUN_ADAPTER_CONFIG__";
1578
+ function getConfig(obj, key) {
1579
+ return obj[key];
1580
+ }
1581
+ function setConfig(obj, key, value) {
1582
+ obj[key] = value;
1583
+ return obj;
1584
+ }
1585
+ var getExternalPluginOptions = (viteConfig) => getConfig(viteConfig, PluginConfigKey);
1586
+ var setExternalPluginOptions = (viteConfig, value) => setConfig(viteConfig, PluginConfigKey, value);
1587
+ var getExternalAdapterOptions = (viteConfig) => getConfig(viteConfig, AdapterConfigKey);
1588
+ var setExternalAdapterOptions = (viteConfig, value) => setConfig(viteConfig, AdapterConfigKey, value);
1589
+
1542
1590
  // src/vite/utils/log.ts
1543
1591
  import zlib from "node:zlib";
1592
+ import { Blob } from "buffer";
1544
1593
  import Table from "cli-table3";
1545
- import kleur from "kleur";
1546
1594
  import format from "human-format";
1547
- import { Blob } from "buffer";
1595
+ import kleur2 from "kleur";
1548
1596
  var HttpVerbColors = {
1549
- get: kleur.green,
1550
- post: kleur.magenta,
1551
- put: kleur.cyan,
1552
- delete: kleur.red,
1553
- other: kleur.white
1554
- };
1555
- var HttpVerbOrder = {
1556
- get: 0,
1557
- post: 1,
1558
- put: 2,
1559
- delete: 3
1597
+ get: kleur2.green,
1598
+ head: kleur2.dim().green,
1599
+ post: kleur2.magenta,
1600
+ put: kleur2.cyan,
1601
+ delete: kleur2.red,
1602
+ patch: kleur2.yellow,
1603
+ options: kleur2.grey
1560
1604
  };
1605
+ function verbColor(verb) {
1606
+ return verb in HttpVerbColors ? HttpVerbColors[verb] : kleur2.gray;
1607
+ }
1561
1608
  function logRoutesTable(routes, bundle, options) {
1562
1609
  function getRouteChunkName(route) {
1563
1610
  return options.sanitizeFileName(`${route.entryName}.marko`);
@@ -1577,30 +1624,34 @@ function logRoutesTable(routes, bundle, options) {
1577
1624
  headings.push("Size/GZip");
1578
1625
  colAligns.push("right");
1579
1626
  const table = new Table({
1580
- head: headings.map((title) => kleur.bold(kleur.white(title.toUpperCase()))),
1627
+ head: headings.map((title) => kleur2.bold(kleur2.white(title.toUpperCase()))),
1581
1628
  wordWrap: true,
1582
1629
  colAligns,
1583
1630
  style: { compact: true }
1584
1631
  });
1585
1632
  for (const route of routes.list) {
1586
1633
  for (const path6 of route.paths) {
1587
- const verbs = getVerbs(route).sort(
1588
- (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
1589
- );
1634
+ const verbs = getVerbs(route, true);
1590
1635
  let firstRow = true;
1591
1636
  for (const verb of verbs) {
1592
- let size = "";
1593
1637
  const entryType = [];
1638
+ let size = "";
1639
+ let verbCell = verbColor(verb)(verb.toUpperCase());
1640
+ if (verb === "get" && !verbs.includes("head")) {
1641
+ verbCell += kleur2.dim(`,${verbColor(verb)("HEAD")}`);
1642
+ }
1594
1643
  if (route.handler) {
1595
- entryType.push(kleur.blue("handler"));
1644
+ entryType.push(kleur2.blue("handler"));
1596
1645
  }
1597
- if (verb === "get" && route.page) {
1598
- entryType.push(kleur.yellow("page"));
1599
- size = prettySize(computeRouteSize(getRouteChunkName(route), bundle));
1646
+ if (route.page && (verb === "get" || verb === "head")) {
1647
+ entryType.push(kleur2.yellow("page"));
1648
+ if (verb === "get") {
1649
+ size = prettySize(
1650
+ computeRouteSize(getRouteChunkName(route), bundle)
1651
+ );
1652
+ }
1600
1653
  }
1601
- const row = [
1602
- kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))
1603
- ];
1654
+ const row = [verbCell];
1604
1655
  if (verbs.length === 1 || firstRow) {
1605
1656
  row.push({ rowSpan: verbs.length, content: prettyPath(path6.path) });
1606
1657
  firstRow = false;
@@ -1614,7 +1665,7 @@ function logRoutesTable(routes, bundle, options) {
1614
1665
  }
1615
1666
  }
1616
1667
  for (const [key, route] of Object.entries(routes.special).sort()) {
1617
- const row = [kleur.bold(kleur.white("*")), key, kleur.yellow("page")];
1668
+ const row = [kleur2.bold(kleur2.white("*")), key, kleur2.yellow("page")];
1618
1669
  hasMiddleware && row.push("");
1619
1670
  hasMeta && row.push("");
1620
1671
  row.push(prettySize(computeRouteSize(getRouteChunkName(route), bundle)));
@@ -1653,27 +1704,24 @@ function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
1653
1704
  }
1654
1705
  function prettySize([bytes, compBytes]) {
1655
1706
  if (bytes <= 0) {
1656
- return kleur.gray("0.0 kB");
1707
+ return kleur2.gray("0.0 kB");
1657
1708
  }
1658
1709
  const [size, prefix] = format(bytes, { decimals: 1 }).split(/\s+/);
1659
1710
  const compSize = format(compBytes, { decimals: 1, prefix, unit: "B" });
1660
- let str = kleur.white(size) + kleur.gray("/");
1661
- if (compBytes < 20 * 1e3) str += kleur.green(compSize);
1662
- else if (compBytes < 50 * 1e3) str += kleur.yellow(compSize);
1663
- else str += kleur.bold(kleur.red(compSize));
1711
+ let str = kleur2.white(size) + kleur2.gray("/");
1712
+ if (compBytes < 20 * 1e3) str += kleur2.green(compSize);
1713
+ else if (compBytes < 50 * 1e3) str += kleur2.yellow(compSize);
1714
+ else str += kleur2.bold(kleur2.red(compSize));
1664
1715
  return str;
1665
1716
  }
1666
1717
  function prettyPath(path6) {
1667
- return path6.replace(/\/\$\$(.*)$/, (_, p) => "/" + kleur.bold(kleur.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + kleur.bold(kleur.dim(`:${p}`)));
1718
+ return path6.replace(/\/\$\$(.*)$/, (_, p) => "/" + kleur2.bold(kleur2.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + kleur2.bold(kleur2.dim(`:${p}`)));
1668
1719
  }
1669
1720
 
1670
- // src/vite/plugin.ts
1671
- import createDebug from "debug";
1672
-
1673
1721
  // src/vite/utils/read-once-persisted-store.ts
1722
+ import { promises as fs2 } from "fs";
1674
1723
  import os from "os";
1675
1724
  import path3 from "path";
1676
- import { promises as fs3 } from "fs";
1677
1725
  var noop = () => {
1678
1726
  };
1679
1727
  var tmpFile = path3.join(os.tmpdir(), "marko-run-storage.json");
@@ -1696,13 +1744,13 @@ var ReadOncePersistedStore = class {
1696
1744
  if (loadedFromDisk === true) {
1697
1745
  throw new Error(`Value for ${uid} could not be loaded.`);
1698
1746
  }
1699
- await (loadedFromDisk || (loadedFromDisk = fs3.readFile(tmpFile, "utf-8").then(syncDataFromDisk).catch(finishLoadFromDisk)));
1747
+ await (loadedFromDisk || (loadedFromDisk = fs2.readFile(tmpFile, "utf-8").then(syncDataFromDisk).catch(finishLoadFromDisk)));
1700
1748
  return this.read();
1701
1749
  }
1702
1750
  };
1703
1751
  function syncDataFromDisk(data) {
1704
1752
  finishLoadFromDisk();
1705
- fs3.unlink(tmpFile).catch(noop);
1753
+ fs2.unlink(tmpFile).catch(noop);
1706
1754
  for (const [k, v] of JSON.parse(data)) {
1707
1755
  values.set(k, v);
1708
1756
  }
@@ -1712,37 +1760,11 @@ function finishLoadFromDisk() {
1712
1760
  }
1713
1761
  process.once("beforeExit", (code) => {
1714
1762
  if (code === 0 && values.size) {
1715
- fs3.writeFile(tmpFile, JSON.stringify([...values])).catch(noop);
1763
+ fs2.writeFile(tmpFile, JSON.stringify([...values])).catch(noop);
1716
1764
  }
1717
1765
  });
1718
1766
 
1719
- // src/adapter/utils.ts
1720
- import supporsColor from "supports-color";
1721
- import kleur2 from "kleur";
1722
- function stripAnsi(string) {
1723
- return string.replace(
1724
- /([\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><])/g,
1725
- ""
1726
- );
1727
- }
1728
- function cleanStack(stack) {
1729
- return stack.split(/\n/).filter((l) => /^\s*at/.test(l)).join("\n");
1730
- }
1731
- function prepareError(err) {
1732
- var _a;
1733
- return {
1734
- message: stripAnsi(err.message),
1735
- stack: stripAnsi(cleanStack(err.stack || "")),
1736
- id: err.id,
1737
- frame: stripAnsi(err.frame || ""),
1738
- plugin: err.plugin,
1739
- pluginCode: (_a = err.pluginCode) == null ? void 0 : _a.toString(),
1740
- loc: err.loc
1741
- };
1742
- }
1743
-
1744
1767
  // src/vite/plugin.ts
1745
- import { createHash } from "crypto";
1746
1768
  var debug = createDebug("@marko/run");
1747
1769
  var __dirname = path4.dirname(fileURLToPath(import.meta.url));
1748
1770
  var PLUGIN_NAME_PREFIX = "marko-run-vite";
@@ -1774,7 +1796,7 @@ function markoRun(opts = {}) {
1774
1796
  let getExportsFromFile;
1775
1797
  let resolvedConfig;
1776
1798
  let typesFile;
1777
- let seenErrors = /* @__PURE__ */ new Set();
1799
+ const seenErrors = /* @__PURE__ */ new Set();
1778
1800
  const virtualFiles = /* @__PURE__ */ new Map();
1779
1801
  let times = {
1780
1802
  routesBuild: 0,
@@ -1791,73 +1813,77 @@ function markoRun(opts = {}) {
1791
1813
  normalizePath(path4.relative(typesDir, resolvedRoutesDir)),
1792
1814
  adapter
1793
1815
  );
1794
- if (data !== typesFile || !fs4.existsSync(filepath)) {
1816
+ if (data !== typesFile || !fs3.existsSync(filepath)) {
1795
1817
  await ensureDir(typesDir);
1796
- await fs4.promises.writeFile(filepath, typesFile = data);
1818
+ await fs3.promises.writeFile(filepath, typesFile = data);
1797
1819
  }
1798
1820
  }
1799
1821
  }
1800
1822
  let buildVirtualFilesResult;
1801
1823
  function buildVirtualFiles() {
1802
- return buildVirtualFilesResult ?? (buildVirtualFilesResult = new Promise(async (resolve, reject) => {
1803
- try {
1804
- virtualFiles.clear();
1805
- routes = await buildRoutes({
1806
- walker: createFSWalker(resolvedRoutesDir),
1807
- importPrefix: routesDir
1808
- });
1809
- if (!routes.list.length) {
1810
- throw new Error("No routes generated");
1811
- }
1812
- for (const route of routes.list) {
1813
- virtualFiles.set(path4.posix.join(root, `${route.entryName}.js`), "");
1814
- }
1815
- if (routes.middleware.length) {
1816
- virtualFiles.set(path4.posix.join(root, MIDDLEWARE_FILENAME), "");
1817
- }
1818
- virtualFiles.set(path4.posix.join(root, ROUTER_FILENAME), "");
1819
- resolve(routes);
1820
- } catch (err) {
1821
- reject(err);
1824
+ return buildVirtualFilesResult ?? (buildVirtualFilesResult = (async () => {
1825
+ virtualFiles.clear();
1826
+ routes = await buildRoutes({
1827
+ walker: createFSWalker(resolvedRoutesDir),
1828
+ importPrefix: routesDir
1829
+ });
1830
+ if (!routes.list.length) {
1831
+ throw new Error("No routes generated");
1822
1832
  }
1823
- }));
1833
+ for (const route of routes.list) {
1834
+ virtualFiles.set(path4.posix.join(root, `${route.entryName}.js`), "");
1835
+ }
1836
+ if (routes.middleware.length) {
1837
+ virtualFiles.set(path4.posix.join(root, MIDDLEWARE_FILENAME), "");
1838
+ }
1839
+ virtualFiles.set(path4.posix.join(root, ROUTER_FILENAME), "");
1840
+ return routes;
1841
+ })());
1824
1842
  }
1825
1843
  let renderVirtualFilesResult;
1826
1844
  function renderVirtualFiles(context) {
1827
- return renderVirtualFilesResult ?? (renderVirtualFilesResult = new Promise(async (resolve) => {
1845
+ return renderVirtualFilesResult ?? (renderVirtualFilesResult = (async () => {
1828
1846
  var _a;
1829
1847
  try {
1830
1848
  const routes2 = await buildVirtualFiles();
1831
- if (fs4.existsSync(entryFilesDir)) {
1832
- fs4.rmSync(entryFilesDir, { recursive: true });
1849
+ if (fs3.existsSync(entryFilesDir)) {
1850
+ fs3.rmSync(entryFilesDir, { recursive: true });
1833
1851
  }
1834
1852
  for (const route of routes2.list) {
1835
- if (route.handler) {
1836
- const exports = await getExportsFromFile(
1837
- context,
1838
- route.handler.filePath
1839
- );
1840
- route.handler.verbs = [];
1853
+ const { handler, page, layouts } = route;
1854
+ if (handler) {
1855
+ const exports = await getExportsFromFile(context, handler.filePath);
1856
+ handler.verbs = [];
1841
1857
  for (const name of exports) {
1842
1858
  const verb = name.toLowerCase();
1843
1859
  if (name === verb.toUpperCase() && httpVerbs.includes(verb)) {
1844
- route.handler.verbs.push(verb);
1860
+ handler.verbs.push(verb);
1845
1861
  }
1846
1862
  }
1847
- if (!route.handler.verbs.length) {
1863
+ if (!handler.verbs.length) {
1848
1864
  context.warn(
1849
- `Did not find any http verb exports in handler '${path4.relative(root, route.handler.filePath)}' - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`
1865
+ `Did not find any http verb exports in handler '${path4.relative(root, handler.filePath)}' - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`
1850
1866
  );
1851
1867
  }
1852
1868
  }
1853
- if (route.page && route.layouts.length) {
1854
- const relativePath = path4.relative(resolvedRoutesDir, route.page.filePath);
1869
+ if (page && layouts.length) {
1870
+ const relativePath = path4.relative(
1871
+ resolvedRoutesDir,
1872
+ page.filePath
1873
+ );
1855
1874
  const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1856
- const routeFileRelativePathPosix = normalizePath(path4.relative(routeFileDir, root));
1857
- fs4.mkdirSync(routeFileDir, { recursive: true });
1858
- fs4.writeFileSync(
1859
- path4.join(routeFileDir, "route.marko"),
1860
- renderRouteTemplate(route, (to) => path4.posix.join(routeFileRelativePathPosix, to))
1875
+ const routeFileRelativePathPosix = normalizePath(
1876
+ path4.relative(routeFileDir, root)
1877
+ );
1878
+ fs3.mkdirSync(routeFileDir, { recursive: true });
1879
+ const pageNameIndex = page.name.indexOf("+page");
1880
+ const pageNamePrefix = pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : "";
1881
+ fs3.writeFileSync(
1882
+ path4.join(routeFileDir, pageNamePrefix + "route.marko"),
1883
+ renderRouteTemplate(
1884
+ route,
1885
+ (to) => path4.posix.join(routeFileRelativePathPosix, to)
1886
+ )
1861
1887
  );
1862
1888
  }
1863
1889
  virtualFiles.set(
@@ -1866,14 +1892,23 @@ function markoRun(opts = {}) {
1866
1892
  );
1867
1893
  }
1868
1894
  for (const route of Object.values(routes2.special)) {
1869
- if (route.page && route.layouts.length) {
1870
- const relativePath = path4.relative(resolvedRoutesDir, route.page.filePath);
1895
+ const { page, layouts, key } = route;
1896
+ if (page && layouts.length) {
1897
+ const relativePath = path4.relative(
1898
+ resolvedRoutesDir,
1899
+ page.filePath
1900
+ );
1871
1901
  const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1872
- const routeFileRelativePathPosix = normalizePath(path4.relative(routeFileDir, root));
1873
- fs4.mkdirSync(routeFileDir, { recursive: true });
1874
- fs4.writeFileSync(
1875
- path4.join(routeFileDir, `route.${route.key}.marko`),
1876
- renderRouteTemplate(route, (to) => path4.posix.join(routeFileRelativePathPosix, to))
1902
+ const routeFileRelativePathPosix = normalizePath(
1903
+ path4.relative(routeFileDir, root)
1904
+ );
1905
+ fs3.mkdirSync(routeFileDir, { recursive: true });
1906
+ fs3.writeFileSync(
1907
+ path4.join(routeFileDir, `route.${key}.marko`),
1908
+ renderRouteTemplate(
1909
+ route,
1910
+ (to) => path4.posix.join(routeFileRelativePathPosix, to)
1911
+ )
1877
1912
  );
1878
1913
  }
1879
1914
  }
@@ -1919,8 +1954,7 @@ function markoRun(opts = {}) {
1919
1954
  `throw ${JSON.stringify(prepareError(err))}`
1920
1955
  );
1921
1956
  }
1922
- resolve();
1923
- }));
1957
+ })());
1924
1958
  }
1925
1959
  return [
1926
1960
  defaultConfigPlugin,
@@ -1965,7 +1999,9 @@ function markoRun(opts = {}) {
1965
1999
  createHash("shake256", { outputLength: 4 }).update(root).digest("hex")
1966
2000
  );
1967
2001
  entryFilesDirPosix = normalizePath(entryFilesDir);
1968
- relativeEntryFilesDirPosix = normalizePath(path4.relative(root, entryFilesDir));
2002
+ relativeEntryFilesDirPosix = normalizePath(
2003
+ path4.relative(root, entryFilesDir)
2004
+ );
1969
2005
  typesDir = path4.join(root, ".marko-run");
1970
2006
  devEntryFile = path4.join(root, "index.html");
1971
2007
  devEntryFilePosix = normalizePath(devEntryFile);
@@ -1986,7 +2022,7 @@ function markoRun(opts = {}) {
1986
2022
  entryFileNames(info) {
1987
2023
  let name = getEntryFileName(info.facadeModuleId);
1988
2024
  if (!name) {
1989
- for (let id of info.moduleIds) {
2025
+ for (const id of info.moduleIds) {
1990
2026
  name = getEntryFileName(id);
1991
2027
  if (name) {
1992
2028
  break;
@@ -2265,15 +2301,15 @@ async function globFileExists(root, pattern) {
2265
2301
  return (await glob(pattern, { root })).length > 0;
2266
2302
  }
2267
2303
  async function ensureDir(dir) {
2268
- if (!fs4.existsSync(dir)) {
2269
- await fs4.promises.mkdir(dir, { recursive: true });
2304
+ if (!fs3.existsSync(dir)) {
2305
+ await fs3.promises.mkdir(dir, { recursive: true });
2270
2306
  }
2271
2307
  }
2272
2308
  async function getPackageData(dir) {
2273
2309
  do {
2274
2310
  const pkgPath = path4.join(dir, "package.json");
2275
- if (fs4.existsSync(pkgPath)) {
2276
- return JSON.parse(await fs4.promises.readFile(pkgPath, "utf-8"));
2311
+ if (fs3.existsSync(pkgPath)) {
2312
+ return JSON.parse(await fs3.promises.readFile(pkgPath, "utf-8"));
2277
2313
  }
2278
2314
  } while (dir !== (dir = path4.dirname(dir)));
2279
2315
  return null;
@@ -2291,7 +2327,10 @@ async function resolveAdapter(root, options, log) {
2291
2327
  for (const name of dependecies) {
2292
2328
  if (name.startsWith("@marko/run-adapter") || name.indexOf("marko-run-adapter") !== -1) {
2293
2329
  try {
2294
- const module2 = await import(name);
2330
+ const module2 = await import(
2331
+ /* @vite-ignore */
2332
+ name
2333
+ );
2295
2334
  log && debug(
2296
2335
  `Using adapter ${name} listed in your package.json dependecies`
2297
2336
  );
@@ -2303,7 +2342,10 @@ async function resolveAdapter(root, options, log) {
2303
2342
  }
2304
2343
  }
2305
2344
  const defaultAdapter = "@marko/run/adapter";
2306
- const module = await import(defaultAdapter);
2345
+ const module = await import(
2346
+ /* @vite-ignore */
2347
+ defaultAdapter
2348
+ );
2307
2349
  log && debug("Using default adapter");
2308
2350
  return module.default();
2309
2351
  }
@@ -2351,6 +2393,37 @@ var defaultConfigPlugin = {
2351
2393
  }
2352
2394
  };
2353
2395
 
2396
+ // src/vite/utils/server.ts
2397
+ import cp from "child_process";
2398
+ import cluster from "cluster";
2399
+ import { config, parse } from "dotenv";
2400
+ import fs4 from "fs";
2401
+ import net from "net";
2402
+ async function getConnection(port) {
2403
+ return new Promise((resolve) => {
2404
+ const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => {
2405
+ connection.end();
2406
+ resolve(null);
2407
+ }).on("connect", () => {
2408
+ resolve(connection);
2409
+ });
2410
+ });
2411
+ }
2412
+ async function isPortInUse(port) {
2413
+ return Boolean(await getConnection(port));
2414
+ }
2415
+ async function getAvailablePort(port) {
2416
+ if (port && !await isPortInUse(port)) {
2417
+ return port;
2418
+ }
2419
+ return new Promise((resolve) => {
2420
+ const server = net.createServer().listen(0, () => {
2421
+ const { port: port2 } = server.address();
2422
+ server.close(() => resolve(port2));
2423
+ });
2424
+ });
2425
+ }
2426
+
2354
2427
  // src/cli/commands.ts
2355
2428
  var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
2356
2429
  var defaultConfigFileBases = ["serve.config", "vite.config"];