@marko/run 0.5.13 → 0.5.14

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