@marko/run 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,9 +16,12 @@ import createDebug from "debug";
16
16
  import { resolveToEsbuildTarget } from "esbuild-plugin-browserslist";
17
17
  import fs3 from "fs";
18
18
  import { glob } from "glob";
19
- import path4 from "path";
19
+ import path6 from "path";
20
20
  import { fileURLToPath } from "url";
21
- import { buildErrorMessage, mergeConfig } from "vite";
21
+ import {
22
+ buildErrorMessage,
23
+ mergeConfig
24
+ } from "vite";
22
25
 
23
26
  // src/adapter/utils.ts
24
27
  import kleur from "kleur";
@@ -46,7 +49,7 @@ function prepareError(err) {
46
49
  }
47
50
 
48
51
  // src/vite/codegen/index.ts
49
- import path from "path";
52
+ import path2 from "path";
50
53
 
51
54
  // src/vite/constants.ts
52
55
  var markoRunFilePrefix = "__marko-run__";
@@ -71,6 +74,12 @@ var RoutableFileTypes = {
71
74
  Error: "500"
72
75
  };
73
76
 
77
+ // src/vite/utils/fs.ts
78
+ import path from "path";
79
+ var POSIX_SEP = "/";
80
+ var WINDOWS_SEP = "\\";
81
+ var normalizePath = path.sep === WINDOWS_SEP ? (id) => id.replace(/\\/g, POSIX_SEP) : (id) => id;
82
+
74
83
  // src/vite/utils/route.ts
75
84
  var httpVerbOrder = httpVerbs.reduce(
76
85
  (order, verb, index) => {
@@ -94,6 +103,9 @@ function hasVerb(route, verb) {
94
103
  var _a, _b;
95
104
  return verb === "get" && !!route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes(verb)) || verb === "head" && hasVerb(route, "get");
96
105
  }
106
+ function getRouteVirtualFileName(route) {
107
+ return `${markoRunFilePrefix}${route.key.replace(/\//g, ".")}.js`;
108
+ }
97
109
 
98
110
  // src/vite/codegen/writer.ts
99
111
  function createWriter(sink, options) {
@@ -236,27 +248,34 @@ function createStringWriter(opts) {
236
248
  }
237
249
 
238
250
  // src/vite/codegen/index.ts
239
- function renderRouteTemplate(route, getRelativePath) {
251
+ function normalizedRelativePath(from, to) {
252
+ const relativePath = normalizePath(path2.relative(from, to));
253
+ return relativePath.startsWith(".") ? relativePath : "./" + relativePath;
254
+ }
255
+ function renderRouteTemplate(route, rootDir) {
240
256
  if (!route.page) {
241
257
  throw new Error(`Route ${route.key} has no page to render`);
242
258
  }
259
+ if (!route.templateFilePath) {
260
+ throw new Error(`Route ${route.key} has no template file path`);
261
+ }
243
262
  return renderEntryTemplate(
244
- route.entryName,
263
+ normalizedRelativePath(rootDir, route.templateFilePath),
245
264
  [...route.layouts, route.page].map(
246
- (file) => getRelativePath(file.importPath)
265
+ (file) => normalizedRelativePath(
266
+ path2.dirname(route.templateFilePath),
267
+ file.filePath
268
+ )
247
269
  ),
248
270
  route.key === RoutableFileTypes.Error ? ["error"] : []
249
271
  );
250
272
  }
251
273
  function renderEntryTemplate(name, files, pageInputs = []) {
252
- if (!name) {
253
- throw new Error(`Invalid argument - 'name' cannot be empty`);
254
- }
255
274
  if (!files.length) {
256
275
  throw new Error(`Invalid argument - 'files' cannot be empty`);
257
276
  }
258
277
  const writer = createStringWriter();
259
- writer.writeLines(`// ${name}.marko`);
278
+ writer.writeLines(`// ${name}`);
260
279
  writer.branch("imports");
261
280
  writer.writeLines("");
262
281
  writeEntryTemplateTag(writer, files, pageInputs);
@@ -266,7 +285,7 @@ function writeEntryTemplateTag(writer, [file, ...rest], pageInputs, index = 1) {
266
285
  if (file) {
267
286
  const isLast = !rest.length;
268
287
  const tag = isLast ? "Page" : `Layout${index}`;
269
- writer.branch("imports").writeLines(`import ${tag} from '${file}';`);
288
+ writer.branch("imports").writeLines(`import ${tag} from "${file}";`);
270
289
  if (isLast) {
271
290
  const attributes = pageInputs.length ? " " + pageInputs.map((name) => `${name}=input.${name}`).join(" ") : "";
272
291
  writer.writeLines(`<${tag}${attributes}/>`);
@@ -277,9 +296,9 @@ function writeEntryTemplateTag(writer, [file, ...rest], pageInputs, index = 1) {
277
296
  }
278
297
  }
279
298
  }
280
- function renderRouteEntry(route, entriesDir) {
299
+ function renderRouteEntry(route, rootDir) {
281
300
  var _a;
282
- const { key, index, handler, page, middleware, meta, entryName } = route;
301
+ const { key, index, handler, page, middleware, meta } = route;
283
302
  const verbs = getVerbs(route);
284
303
  if (!verbs) {
285
304
  throw new Error(
@@ -287,7 +306,7 @@ function renderRouteEntry(route, entriesDir) {
287
306
  );
288
307
  }
289
308
  const writer = createStringWriter();
290
- writer.writeLines(`// ${virtualFilePrefix}/${entryName}.js`);
309
+ writer.writeLines(`// ${virtualFilePrefix}${getRouteVirtualFileName(route)}`);
291
310
  const imports = writer.branch("imports");
292
311
  const runtimeImports = [];
293
312
  if (handler) {
@@ -299,9 +318,6 @@ function renderRouteEntry(route, entriesDir) {
299
318
  if (!page || verbs.some((verb) => verb !== "get" && verb !== "head")) {
300
319
  runtimeImports.push("noContent");
301
320
  }
302
- if (page) {
303
- runtimeImports.push("pageResponse");
304
- }
305
321
  if (verbs.includes("head")) {
306
322
  runtimeImports.push("stripResponseBody");
307
323
  }
@@ -309,7 +325,7 @@ function renderRouteEntry(route, entriesDir) {
309
325
  imports.writeLines(
310
326
  `import { ${runtimeImports.join(
311
327
  ", "
312
- )} } from '${virtualFilePrefix}/runtime/internal';`
328
+ )} } from "${virtualFilePrefix}/runtime/internal";`
313
329
  );
314
330
  }
315
331
  if (middleware.length) {
@@ -317,7 +333,7 @@ function renderRouteEntry(route, entriesDir) {
317
333
  imports.writeLines(
318
334
  `import { ${names.join(
319
335
  ", "
320
- )} } from '${virtualFilePrefix}/${markoRunFilePrefix}middleware.js';`
336
+ )} } from "${virtualFilePrefix}/${markoRunFilePrefix}middleware.js";`
321
337
  );
322
338
  }
323
339
  if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.length) {
@@ -329,18 +345,17 @@ function renderRouteEntry(route, entriesDir) {
329
345
  writer.writeLines(`const ${verb}Handler = normalize(${importName});`);
330
346
  }
331
347
  imports.writeLines(
332
- `import { ${names.join(", ")} } from './${handler.importPath}';`
348
+ `import { ${names.join(", ")} } from "${normalizedRelativePath(rootDir, handler.filePath)}";`
333
349
  );
334
350
  }
335
351
  if (page) {
336
- const pageNameIndex = page.name.indexOf("+page");
337
- const pageNamePrefix = pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : "";
338
- const importPath = route.layouts.length ? `./${path.posix.join(entriesDir, page.relativePath, "..", pageNamePrefix + "route.marko")}` : `./${page.importPath}`;
339
- imports.writeLines(`import page from '${importPath}${serverEntryQuery}';`);
352
+ imports.writeLines(
353
+ `import page from "${normalizedRelativePath(rootDir, route.templateFilePath || page.filePath)}${serverEntryQuery}";`
354
+ );
340
355
  }
341
356
  if (meta) {
342
357
  imports.writeLines(
343
- `export { default as meta${index} } from './${meta.importPath}';`
358
+ `export { default as meta${index} } from "${normalizedRelativePath(rootDir, meta.filePath)}";`
344
359
  );
345
360
  }
346
361
  for (const verb of verbs) {
@@ -357,9 +372,7 @@ function writeRouteEntryHandler(writer, route, verb) {
357
372
  let hasBody = false;
358
373
  writer.writeLines("");
359
374
  if (page && (verb === "get" || verb === "head")) {
360
- writer.writeBlockStart(
361
- `export function ${verb}${index}(context, buildInput) {`
362
- );
375
+ writer.writeBlockStart(`export function ${verb}${index}(context) {`);
363
376
  } else {
364
377
  writer.writeBlockStart(`export function ${verb}${index}(context) {`);
365
378
  }
@@ -369,7 +382,7 @@ function writeRouteEntryHandler(writer, route, verb) {
369
382
  if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
370
383
  const name = `${verb}Handler`;
371
384
  continuations.writeLines(
372
- `const ${currentName} = () => pageResponse(page, buildInput());`
385
+ `const ${currentName} = () => context.render(page, {});`
373
386
  );
374
387
  if (len) {
375
388
  nextName = currentName;
@@ -388,17 +401,15 @@ function writeRouteEntryHandler(writer, route, verb) {
388
401
  hasBody = true;
389
402
  }
390
403
  } else if (verb === "head") {
391
- writer.writeLines(
392
- `return stripResponseBody(get${index}(context, buildInput));`
393
- );
404
+ writer.writeLines(`return stripResponseBody(get${index}(context));`);
394
405
  hasBody = true;
395
406
  } else if (len) {
396
407
  continuations.writeLines(
397
- `const ${currentName} = () => pageResponse(page, buildInput());`
408
+ `const ${currentName} = () => context.render(page, {});`
398
409
  );
399
410
  nextName = currentName;
400
411
  } else {
401
- writer.writeLines(`return pageResponse(page, buildInput());`);
412
+ writer.writeLines(`return context.render(page, {});`);
402
413
  hasBody = true;
403
414
  }
404
415
  } else if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes(verb)) {
@@ -448,7 +459,7 @@ function writeRouteEntryHandler(writer, route, verb) {
448
459
  continuations.join();
449
460
  writer.writeBlockEnd("}");
450
461
  }
451
- function renderRouter(routes, entriesDir, options = {
462
+ function renderRouter(routes, rootDir, options = {
452
463
  trailingSlashes: "RedirectWithout"
453
464
  }) {
454
465
  const writer = createStringWriter();
@@ -457,20 +468,19 @@ function renderRouter(routes, entriesDir, options = {
457
468
  writer.writeLines(`// @marko/run/router`);
458
469
  const imports = writer.branch("imports");
459
470
  imports.writeLines(
460
- `import { NotHandled, NotMatched, createContext${hasErrorPage || hasNotFoundPage ? ", pageResponse" : ""} } from '${virtualFilePrefix}/runtime/internal';`
471
+ `import { NotHandled, NotMatched, createContext } from "${virtualFilePrefix}/runtime/internal";`
461
472
  );
462
473
  for (const route of routes.list) {
463
474
  const verbs = getVerbs(route);
464
475
  const names = verbs.map((verb) => `${verb}${route.index}`);
465
476
  route.meta && names.push(`meta${route.index}`);
466
477
  imports.writeLines(
467
- `import { ${names.join(", ")} } from '${virtualFilePrefix}/${route.entryName}.js';`
478
+ `import { ${names.join(", ")} } from "${virtualFilePrefix}/${getRouteVirtualFileName(route)}";`
468
479
  );
469
480
  }
470
481
  for (const route of Object.values(routes.special)) {
471
- const importPath = route.layouts.length ? `./${path.posix.join(entriesDir, route.page.relativePath, "..", `route.${route.key}.marko`)}` : `./${route.page.importPath}`;
472
482
  imports.writeLines(
473
- `import page${route.key} from '${importPath}${serverEntryQuery}';`
483
+ `import page${route.key} from "${normalizedRelativePath(rootDir, route.templateFilePath || route.page.filePath)}${serverEntryQuery}";`
474
484
  );
475
485
  }
476
486
  writer.writeLines(
@@ -478,11 +488,12 @@ function renderRouter(routes, entriesDir, options = {
478
488
  globalThis.__marko_run__ = { match, fetch, invoke };
479
489
  `
480
490
  ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
481
- `if (!pathname) {
482
- pathname = '/';
483
- } else if (pathname.charAt(0) !== '/') {
484
- pathname = '/' + pathname;
485
- }`
491
+ `const last = pathname.length - 1;
492
+ return match_internal(method, last && pathname.charAt(last) === '/' ? pathname.slice(0, last) : pathname)
493
+ };
494
+
495
+ function match_internal(method, pathname) {
496
+ const len = pathname.length;`
486
497
  ).writeBlockStart(`switch (method) {`);
487
498
  for (const verb of httpVerbs) {
488
499
  const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
@@ -498,13 +509,13 @@ globalThis.__marko_run__ = { match, fetch, invoke };
498
509
  writer.writeLines("").writeBlockStart(
499
510
  "export async function invoke(route, request, platform, url) {"
500
511
  ).writeLines(
501
- "const [context, buildInput] = createContext(route, request, platform, url);"
512
+ "const context = createContext(route, request, platform, url);"
502
513
  );
503
514
  if (hasErrorPage) {
504
515
  writer.writeBlockStart("try {");
505
516
  }
506
517
  writer.writeBlockStart("if (route) {").writeBlockStart("try {").writeLines(
507
- "const response = await route.handler(context, buildInput);",
518
+ "const response = await route.handler(context);",
508
519
  "if (response) return response;"
509
520
  ).indent--;
510
521
  writer.writeBlockStart("} catch (error) {").writeLines(
@@ -521,7 +532,7 @@ const page404ResponseInit = {
521
532
  );
522
533
  writer.write(`
523
534
  if (context.request.headers.get('Accept')?.includes('text/html')) {
524
- return pageResponse(page404, buildInput(), page404ResponseInit);
535
+ return context.render(page404, {}, page404ResponseInit);
525
536
  }`);
526
537
  }
527
538
  writer.indent--;
@@ -538,7 +549,7 @@ const page500ResponseInit = {
538
549
  writer.writeBlockStart(`} catch (error) {`).writeBlockStart(
539
550
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
540
551
  ).writeLines(
541
- `return pageResponse(page500, buildInput({ error }), page500ResponseInit);`
552
+ `return context.render(page500, { error }, page500ResponseInit);`
542
553
  ).writeBlockEnd("}").writeLines("throw error;").writeBlockEnd("}");
543
554
  }
544
555
  writer.writeBlockEnd("}");
@@ -550,38 +561,40 @@ function renderFetch(writer, options) {
550
561
  export async function fetch(request, platform) {
551
562
  try {
552
563
  const url = new URL(request.url);
553
- let { pathname } = url;`);
564
+ const { pathname } = url;
565
+ const last = pathname.length - 1;
566
+ const hasTrailingSlash = last && pathname.charAt(last) === '/';
567
+ const normalizedPathname = hasTrailingSlash ? pathname.slice(0, last) : pathname;
568
+ const route = match_internal(request.method, normalizedPathname);`);
554
569
  switch (options.trailingSlashes) {
555
570
  case "RedirectWithout":
556
571
  writer.write(`
557
- if (pathname !== '/' && pathname.endsWith('/')) {
558
- url.pathname = pathname.slice(0, -1);
572
+ if (route && hasTrailingSlash) {
573
+ url.pathname = normalizedPathname
559
574
  return Response.redirect(url);
560
575
  }`);
561
576
  break;
562
577
  case "RedirectWith":
563
578
  writer.write(`
564
- if (pathname !== '/' && !pathname.endsWith('/')) {
565
- url.pathname = pathname + '/';
579
+ if (route && pathname !== '/' && !hasTrailingSlash) {
580
+ url.pathname += '/';
566
581
  return Response.redirect(url);
567
582
  }`);
568
583
  break;
569
584
  case "RewriteWithout":
570
585
  writer.write(`
571
- if (pathname !== '/' && pathname.endsWith('/')) {
572
- url.pathname = pathname = pathname.slice(0, -1);
586
+ if (route && hasTrailingSlash) {
587
+ url.pathname = normalizedPathname;
573
588
  }`);
574
589
  break;
575
590
  case "RewriteWith":
576
591
  writer.write(`
577
- if (pathname !== '/' && !pathname.endsWith('/')) {
578
- url.pathname = pathname = pathname + '/';
592
+ if (route && pathname !== '/' && !hasTrailingSlash) {
593
+ url.pathname += '/';
579
594
  }`);
580
595
  break;
581
596
  }
582
597
  writer.write(`
583
-
584
- const route = match(request.method, pathname);
585
598
  return await invoke(route, request, platform, url);
586
599
  } catch (error) {
587
600
  if (import.meta.env.DEV) {
@@ -597,10 +610,9 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
597
610
  const { route, dynamic, catchAll } = trie;
598
611
  let closeCount = 0;
599
612
  if (level === 0) {
600
- writer.writeLines(`const len = pathname.length;`);
601
613
  if (route) {
602
614
  writer.writeLines(
603
- `if (len === 1) return ${renderMatch(verb, route, trie.path)}; // ${trie.path.path}`
615
+ `if (len === 1) return ${renderMatch(verb, route, trie.path)};`
604
616
  );
605
617
  } else if (trie.static || dynamic) {
606
618
  writer.writeBlockStart(`if (len > 1) {`);
@@ -641,17 +653,15 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
641
653
  if (useSwitch) {
642
654
  writer.writeBlockStart(`switch (${value}) {`);
643
655
  }
644
- for (const { key, path: path5, route: route2 } of terminal) {
656
+ for (const { key, path: path7, route: route2 } of terminal) {
645
657
  const decodedKey = decodeURIComponent(key);
646
658
  if (useSwitch) {
647
659
  writer.write(`case '${decodedKey}': `, true);
648
660
  } else {
649
661
  writer.write(`if (${value} === '${decodedKey}') `, true);
650
662
  }
651
- writer.write(
652
- `return ${renderMatch(verb, route2, path5)}; // ${path5.path}
653
- `
654
- );
663
+ writer.write(`return ${renderMatch(verb, route2, path7)};
664
+ `);
655
665
  }
656
666
  if (useSwitch) {
657
667
  writer.writeBlockEnd("}");
@@ -663,7 +673,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
663
673
  verb,
664
674
  dynamic.route,
665
675
  dynamic.path
666
- )}; // ${dynamic.path.path}`
676
+ )};`
667
677
  );
668
678
  }
669
679
  }
@@ -723,7 +733,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
723
733
  catchAll.route,
724
734
  catchAll.path,
725
735
  String(offset)
726
- )}; // ${catchAll.path.path}`
736
+ )};`
727
737
  );
728
738
  } else if (level === 0) {
729
739
  writer.writeLines("return null;");
@@ -752,43 +762,47 @@ function renderParams(params, pathIndex) {
752
762
  }
753
763
  return result ? result + " }" : "{}";
754
764
  }
755
- function renderMatch(verb, route, path5, pathIndex) {
765
+ function renderMatch(verb, route, path7, pathIndex) {
756
766
  const handler = `${verb}${route.index}`;
757
- const params = path5.params ? renderParams(path5.params, pathIndex) : "{}";
767
+ const params = path7.params ? renderParams(path7.params, pathIndex) : "{}";
758
768
  const meta = route.meta ? `meta${route.index}` : "{}";
759
- const pathPattern = pathToURLPatternString(path5.path);
760
- return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${pathPattern}' }`;
769
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${path7.path}' }`;
761
770
  }
762
- function renderMiddleware(middleware) {
771
+ function renderMiddleware(middleware, rootDir) {
763
772
  const writer = createStringWriter();
764
773
  writer.writeLines(
765
774
  `// ${virtualFilePrefix}/${markoRunFilePrefix}middleware.js`
766
775
  );
767
776
  const imports = writer.branch("imports");
768
777
  imports.writeLines(
769
- `import { normalize } from '${virtualFilePrefix}/runtime/internal';`
778
+ `import { normalize } from "${virtualFilePrefix}/runtime/internal";`
770
779
  );
771
780
  writer.writeLines("");
772
- for (const { id, importPath } of middleware) {
781
+ for (const { id, filePath } of middleware) {
773
782
  const importName = `middleware${id}`;
774
- imports.writeLines(`import ${importName} from './${importPath}';`);
783
+ imports.writeLines(
784
+ `import ${importName} from "${normalizedRelativePath(rootDir, filePath)}";`
785
+ );
775
786
  writer.writeLines(`export const mware${id} = normalize(${importName});`);
776
787
  }
777
788
  imports.join();
778
789
  return writer.end();
779
790
  }
780
- function stripTsExtension(path5) {
781
- const index = path5.lastIndexOf(".");
791
+ function stripTsExtension(path7) {
792
+ const index = path7.lastIndexOf(".");
782
793
  if (index !== -1) {
783
- const ext = path5.slice(index + 1);
794
+ const ext = path7.slice(index + 1);
784
795
  if (ext.toLowerCase() === "ts") {
785
- return path5.slice(0, index);
796
+ return path7.slice(0, index);
786
797
  }
787
798
  }
788
- return path5;
799
+ return path7;
789
800
  }
790
- async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
791
- var _a, _b;
801
+ function decodePath(path7) {
802
+ return path7;
803
+ }
804
+ async function renderRouteTypeInfo(routes, outDir, adapter) {
805
+ var _a, _b, _c, _d;
792
806
  const writer = createStringWriter();
793
807
  writer.writeLines(
794
808
  `/*
@@ -817,11 +831,31 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
817
831
  const routeTypes = /* @__PURE__ */ new Map();
818
832
  for (const route of routes.list) {
819
833
  let routeType = "";
820
- for (const path5 of route.paths) {
821
- const pathType = `"${pathToURLPatternString(path5.path)}"`;
822
- routeType += routeType ? " | " + pathType : pathType;
823
- routesWriter.writeLines(`${pathType}: Routes["${route.key}"];`);
834
+ let routeDefinition = "";
835
+ if (route.page || route.handler) {
836
+ const verbs = [];
837
+ if (route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes("get"))) {
838
+ verbs.push(`"get"`);
839
+ }
840
+ if ((_d = (_c = route.handler) == null ? void 0 : _c.verbs) == null ? void 0 : _d.includes("post")) {
841
+ verbs.push(`"post"`);
842
+ }
843
+ routeDefinition = `{ verb: ${verbs.join(" | ")};`;
844
+ if (route.meta) {
845
+ const metaPath = stripTsExtension(
846
+ normalizedRelativePath(outDir, route.meta.filePath)
847
+ );
848
+ let metaType = `typeof import("${metaPath}")`;
849
+ if (/\.(ts|js|mjs)$/.test(route.meta.name)) {
850
+ metaType += `["default"]`;
851
+ }
852
+ routeDefinition += ` meta: ${metaType};`;
853
+ }
854
+ routeDefinition += " }";
824
855
  }
856
+ const pathType = `"${decodePath(route.path.path)}"`;
857
+ routeType += routeType ? " | " + pathType : pathType;
858
+ routesWriter.writeLines(`${pathType}: ${routeDefinition};`);
825
859
  for (const file of [route.handler, route.page]) {
826
860
  if (file) {
827
861
  const existing = routeTypes.get(file);
@@ -854,31 +888,33 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
854
888
  const pageWriter = writer.branch("page");
855
889
  const layoutWriter = writer.branch("layout");
856
890
  for (const [file, types] of routeTypes) {
857
- const path5 = `${pathPrefix}/${file.relativePath}`;
891
+ const modulePath = stripTsExtension(
892
+ normalizedRelativePath(outDir, file.filePath)
893
+ );
858
894
  const routeType = `Run.Routes[${types.join(" | ")}]`;
859
895
  switch (file.type) {
860
896
  case RoutableFileTypes.Handler:
861
- writeModuleDeclaration(handlerWriter, path5, routeType);
897
+ writeModuleDeclaration(handlerWriter, modulePath, routeType);
862
898
  break;
863
899
  case RoutableFileTypes.Middleware:
864
- writeModuleDeclaration(middlewareWriter, path5, routeType);
900
+ writeModuleDeclaration(middlewareWriter, modulePath, routeType);
865
901
  break;
866
902
  case RoutableFileTypes.Page:
867
- writeModuleDeclaration(pageWriter, path5, routeType);
903
+ writeModuleDeclaration(pageWriter, modulePath, routeType);
868
904
  break;
869
905
  case RoutableFileTypes.Layout:
870
906
  writeModuleDeclaration(
871
907
  layoutWriter,
872
- path5,
908
+ modulePath,
873
909
  routeType,
874
910
  `
875
- export interface Input extends Run.LayoutInput<typeof import('${path5}')> {}`
911
+ export interface Input extends Run.LayoutInput<typeof import("${modulePath}")> {}`
876
912
  );
877
913
  break;
878
914
  case RoutableFileTypes.Error:
879
915
  writeModuleDeclaration(
880
916
  writer,
881
- path5,
917
+ modulePath,
882
918
  "globalThis.MarkoRun.Route",
883
919
  `
884
920
  export interface Input {
@@ -887,7 +923,7 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
887
923
  );
888
924
  break;
889
925
  case RoutableFileTypes.NotFound:
890
- writeModuleDeclaration(writer, path5, "Run.Route");
926
+ writeModuleDeclaration(writer, modulePath, "Run.Route");
891
927
  break;
892
928
  }
893
929
  }
@@ -895,40 +931,15 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
895
931
  middlewareWriter.join();
896
932
  pageWriter.join();
897
933
  layoutWriter.join();
898
- writer.writeBlockStart(`
899
- type Routes = {`);
900
- for (const route of routes.list) {
901
- const { meta, handler, page } = route;
902
- if (page || handler) {
903
- const verbs = [];
904
- if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
905
- verbs.push(`"get"`);
906
- }
907
- if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
908
- verbs.push(`"post"`);
909
- }
910
- let routeType = `{ verb: ${verbs.join(" | ")};`;
911
- if (meta) {
912
- const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
913
- let metaType = `typeof import("${metaPath}")`;
914
- if (/\.(ts|js|mjs)$/.test(meta.name)) {
915
- metaType += `["default"]`;
916
- }
917
- routeType += ` meta: ${metaType};`;
918
- }
919
- writer.writeLines(`"${route.key}": ${routeType} };`);
920
- }
921
- }
922
- writer.writeBlockEnd("}");
923
934
  return writer.end();
924
935
  }
925
- function writeModuleDeclaration(writer, path5, routeType, moduleTypes) {
926
- writer.writeLines("").write(`declare module "${stripTsExtension(path5)}" {`);
936
+ function writeModuleDeclaration(writer, name, routeType, moduleTypes) {
937
+ writer.writeLines("").write(`declare module "${name}" {`);
927
938
  if (moduleTypes) {
928
939
  writer.write(moduleTypes);
929
940
  }
930
941
  if (routeType) {
931
- const isMarko = path5.endsWith(".marko");
942
+ const isMarko = name.endsWith(".marko");
932
943
  writer.write(`
933
944
  namespace MarkoRun {
934
945
  export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
@@ -942,21 +953,15 @@ function writeModuleDeclaration(writer, path5, routeType, moduleTypes) {
942
953
  writer.writeLines(`
943
954
  }`);
944
955
  }
945
- function pathToURLPatternString(path5) {
946
- return path5.replace(/\/\$(\$?)([^/]*)/g, (_, catchAll, name) => {
947
- name = decodeURIComponent(name);
948
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
949
- });
950
- }
951
956
  function createRouteTrie(routes) {
952
957
  const root = {
953
958
  key: ""
954
959
  };
955
- function insert(path5, route) {
960
+ function insert(path7, route) {
956
961
  let node = root;
957
- for (const segment of path5.segments) {
962
+ for (const segment of path7.segments) {
958
963
  if (segment === "$$") {
959
- node.catchAll ?? (node.catchAll = { route, path: path5 });
964
+ node.catchAll ?? (node.catchAll = { route, path: path7 });
960
965
  return;
961
966
  } else if (segment === "$") {
962
967
  node = node.dynamic ?? (node.dynamic = {
@@ -974,17 +979,18 @@ function createRouteTrie(routes) {
974
979
  node = next;
975
980
  }
976
981
  }
977
- node.path ?? (node.path = path5);
982
+ node.path ?? (node.path = path7);
978
983
  node.route ?? (node.route = route);
979
984
  }
980
985
  for (const route of routes) {
981
- for (const path5 of route.paths) {
982
- insert(path5, route);
983
- }
986
+ insert(route.path, route);
984
987
  }
985
988
  return root;
986
989
  }
987
990
 
991
+ // src/vite/routes/builder.ts
992
+ import path3 from "path";
993
+
988
994
  // src/vite/routes/parse.ts
989
995
  function parseFlatRoute(pattern) {
990
996
  if (!pattern) throw new Error("Empty pattern");
@@ -999,53 +1005,72 @@ function parseFlatRoute(pattern) {
999
1005
  ]);
1000
1006
  function parse2(basePaths, group) {
1001
1007
  const pathMap = /* @__PURE__ */ new Map();
1002
- const delimiters = group ? ").," : ".,";
1008
+ const delimiters = group ? "`).," : "`.,";
1003
1009
  let charCode;
1004
1010
  let segmentStart = i;
1005
1011
  let type;
1006
1012
  let current;
1013
+ let escaped = "";
1014
+ let escapeStart = 0;
1007
1015
  do {
1008
1016
  charCode = pattern.charCodeAt(i);
1009
- if (charCode === 41 && group) {
1017
+ if (charCode === 96 /* Escape */) {
1018
+ if (escapeStart) {
1019
+ escaped += pattern.slice(segmentStart, escapeStart - 1) + pattern.slice(escapeStart, i);
1020
+ escapeStart = 0;
1021
+ segmentStart = ++i;
1022
+ } else {
1023
+ escapeStart = i + 1;
1024
+ i = pattern.indexOf("`", escapeStart);
1025
+ if (i < 0) break;
1026
+ }
1027
+ } else if (charCode === 41 /* GroupEnd */ && group) {
1010
1028
  break;
1011
- } else if (charCode === 44) {
1029
+ } else if (charCode === 44 /* Alternate */) {
1012
1030
  if (!current) {
1013
1031
  segmentEnd(
1014
- basePaths.map((path5) => ({
1015
- ...path5,
1016
- segments: path5.segments.slice()
1032
+ basePaths.map((path7) => ({
1033
+ ...path7,
1034
+ segments: path7.segments.slice()
1017
1035
  })),
1018
- "",
1036
+ escaped,
1019
1037
  "_",
1020
1038
  pathMap
1021
1039
  );
1022
1040
  } else {
1023
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1041
+ segmentEnd(
1042
+ current,
1043
+ escaped + pattern.slice(segmentStart, i),
1044
+ type,
1045
+ pathMap
1046
+ );
1024
1047
  }
1025
1048
  current = void 0;
1026
1049
  type = void 0;
1050
+ escaped = "";
1027
1051
  segmentStart = ++i;
1028
- } else if (charCode === 46) {
1052
+ } else if (charCode === 46 /* Directory */) {
1029
1053
  if (current) {
1030
- segmentEnd(current, pattern.slice(segmentStart, i), type);
1054
+ segmentEnd(current, escaped + pattern.slice(segmentStart, i), type);
1031
1055
  }
1032
1056
  type = void 0;
1057
+ escaped = "";
1033
1058
  segmentStart = ++i;
1034
- } else if (charCode === 40) {
1059
+ } else if (charCode === 40 /* GroupStart */) {
1035
1060
  const groupPaths = parse2(current || basePaths, ++i);
1036
1061
  if (groupPaths.length) {
1037
1062
  current = groupPaths;
1038
1063
  }
1039
1064
  segmentStart = ++i;
1040
1065
  } else {
1041
- if (charCode === 95) {
1066
+ if (charCode === 95 /* Pathless */) {
1042
1067
  type = "_";
1043
- } else if (charCode === 36) {
1068
+ } else if (charCode === 36 /* Dynamic */) {
1044
1069
  type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
1045
1070
  }
1046
- current ?? (current = basePaths.map((path5) => ({
1047
- ...path5,
1048
- segments: path5.segments.slice()
1071
+ current ?? (current = basePaths.map((path7) => ({
1072
+ ...path7,
1073
+ segments: path7.segments.slice()
1049
1074
  })));
1050
1075
  i = len;
1051
1076
  for (const char of delimiters) {
@@ -1056,7 +1081,12 @@ function parseFlatRoute(pattern) {
1056
1081
  }
1057
1082
  }
1058
1083
  } while (i < len);
1059
- if (group && charCode !== 41) {
1084
+ if (escapeStart) {
1085
+ throw new Error(
1086
+ `Invalid route pattern: unclosed escape '${pattern.slice(escapeStart)}' in '${pattern}'`
1087
+ );
1088
+ }
1089
+ if (group && charCode !== 41 /* GroupEnd */) {
1060
1090
  throw new Error(
1061
1091
  `Invalid route pattern: group was not closed '${pattern.slice(
1062
1092
  group
@@ -1065,16 +1095,21 @@ function parseFlatRoute(pattern) {
1065
1095
  }
1066
1096
  if (!current) {
1067
1097
  segmentEnd(
1068
- basePaths.map((path5) => ({
1069
- ...path5,
1070
- segments: path5.segments.slice()
1098
+ basePaths.map((path7) => ({
1099
+ ...path7,
1100
+ segments: path7.segments.slice()
1071
1101
  })),
1072
- "",
1073
- "_",
1102
+ escaped,
1103
+ void 0,
1074
1104
  pathMap
1075
1105
  );
1076
1106
  } else {
1077
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1107
+ segmentEnd(
1108
+ current,
1109
+ escaped + pattern.slice(segmentStart, i),
1110
+ type,
1111
+ pathMap
1112
+ );
1078
1113
  }
1079
1114
  return [...pathMap.values()];
1080
1115
  }
@@ -1083,17 +1118,17 @@ function parseFlatRoute(pattern) {
1083
1118
  if (raw) {
1084
1119
  segment = {
1085
1120
  raw,
1086
- name: raw,
1121
+ name: normalizeSegment(raw),
1087
1122
  type
1088
1123
  };
1089
1124
  if (type === "$" || type === "$$") {
1090
1125
  segment.name = type;
1091
- segment.param = raw.slice(type.length);
1126
+ segment.param = normalizeParam(raw.slice(type.length));
1092
1127
  }
1093
1128
  }
1094
- for (const path5 of paths) {
1129
+ for (const path7 of paths) {
1095
1130
  if (segment) {
1096
- if (path5.isCatchall) {
1131
+ if (path7.isCatchall) {
1097
1132
  throw new Error(
1098
1133
  `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
1099
1134
  0,
@@ -1101,26 +1136,36 @@ function parseFlatRoute(pattern) {
1101
1136
  )}' in '${pattern}'.`
1102
1137
  );
1103
1138
  }
1104
- path5.segments.push(segment);
1105
- path5.id += path5.id === "/" ? segment.name : `/${segment.name}`;
1139
+ path7.segments.push(segment);
1140
+ path7.id += path7.id === "/" ? segment.name : `/${segment.name}`;
1106
1141
  if (type === "$$") {
1107
- path5.isCatchall = true;
1142
+ path7.isCatchall = true;
1108
1143
  }
1109
1144
  }
1110
1145
  if (map) {
1111
- if (map.has(path5.id)) {
1112
- const existing = map.get(path5.id);
1146
+ if (map.has(path7.id)) {
1147
+ const existing = map.get(path7.id);
1113
1148
  const existingExpansion = existing.segments.map((s) => s.raw).join(".");
1114
- const currentExpansion = path5.segments.map((s) => s.raw).join(".");
1149
+ const currentExpansion = path7.segments.map((s) => s.raw).join(".");
1115
1150
  throw new Error(
1116
- `Invalid route pattern: route '${path5.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
1151
+ `Invalid route pattern: route '${path7.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
1117
1152
  );
1118
1153
  }
1119
- map.set(path5.id, path5);
1154
+ map.set(path7.id, path7);
1120
1155
  }
1121
1156
  }
1122
1157
  }
1123
1158
  }
1159
+ function normalizeParam(segment) {
1160
+ const normalized = normalizeSegment(segment);
1161
+ return /^\$/.test(normalized) ? `\`${normalized}\`` : normalized;
1162
+ }
1163
+ function normalizeSegment(segment) {
1164
+ return decodeURIComponent(segment).replace(
1165
+ /[/?#]/g,
1166
+ (char) => "%" + char.charCodeAt(0).toString(16)
1167
+ );
1168
+ }
1124
1169
 
1125
1170
  // src/vite/routes/vdir.ts
1126
1171
  var _dirs, _pathlessDirs;
@@ -1131,14 +1176,12 @@ var _VDir = class _VDir {
1131
1176
  __publicField(this, "parent");
1132
1177
  __publicField(this, "source");
1133
1178
  __publicField(this, "path");
1134
- __publicField(this, "fullPath");
1135
1179
  __publicField(this, "segment");
1136
1180
  __publicField(this, "files");
1137
1181
  if (!parent || !segment) {
1138
1182
  this.parent = null;
1139
1183
  this.source = null;
1140
1184
  this.path = "/";
1141
- this.fullPath = "/";
1142
1185
  this.segment = {
1143
1186
  raw: "",
1144
1187
  name: ""
@@ -1146,12 +1189,8 @@ var _VDir = class _VDir {
1146
1189
  } else {
1147
1190
  this.parent = parent;
1148
1191
  this.source = source;
1149
- this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
1150
- this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
1151
- if (segment.param) {
1152
- this.fullPath += segment.param;
1153
- }
1154
1192
  this.segment = segment;
1193
+ this.path = parent.path + (parent.path === "/" ? "" : "/") + segment.name;
1155
1194
  }
1156
1195
  }
1157
1196
  get pathInfo() {
@@ -1164,17 +1203,18 @@ var _VDir = class _VDir {
1164
1203
  for (const { segment } of this) {
1165
1204
  const { type, name, param } = segment;
1166
1205
  if (name && type !== "_") {
1167
- value.id += sep + (type || name);
1206
+ value.id += sep + name;
1168
1207
  value.path += sep + name;
1169
1208
  value.isEnd = type === "$$";
1170
1209
  if (param) {
1171
- value.path += param;
1210
+ const unescapedParam = param.charAt(0) === "`" ? param.slice(1, -1) : param;
1172
1211
  const index = type === "$$" ? null : value.segments.length;
1173
1212
  if (!value.params) {
1174
- value.params = { [param]: index };
1213
+ value.params = { [unescapedParam]: index };
1175
1214
  } else if (!(param in value.params)) {
1176
- value.params[param] = index;
1215
+ value.params[unescapedParam] = index;
1177
1216
  }
1217
+ value.path += param;
1178
1218
  }
1179
1219
  value.segments.push(name);
1180
1220
  sep = "/";
@@ -1186,11 +1226,11 @@ var _VDir = class _VDir {
1186
1226
  });
1187
1227
  return value;
1188
1228
  }
1189
- addDir(path5, segment) {
1229
+ addDir(path7, segment) {
1190
1230
  const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
1191
1231
  const key = segment.type === "$" ? segment.raw : segment.name;
1192
1232
  if (!map.has(key)) {
1193
- const dir = new _VDir(this, segment, path5);
1233
+ const dir = new _VDir(this, segment, path7);
1194
1234
  map.set(key, dir);
1195
1235
  return dir;
1196
1236
  }
@@ -1206,15 +1246,15 @@ var _VDir = class _VDir {
1206
1246
  const existing = this.files.get(file.type);
1207
1247
  if (existing !== file) {
1208
1248
  throw new Error(
1209
- `Duplicate file type '${file.type}' added at path '${this.path}'. File '${file.importPath}' collides with '${existing.importPath}'.`
1249
+ `Duplicate file type ${file.type} added at path ${this.path}. File ${file.filePath} collides with ${existing.filePath}.`
1210
1250
  );
1211
1251
  } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
1212
1252
  throw new Error(
1213
- `Ambiguous path definition: route '${this.path}' is defined multiple times by ${file.importPath}`
1253
+ `Ambiguous path definition: route ${this.path} is defined multiple times by ${file.filePath}`
1214
1254
  );
1215
1255
  }
1216
1256
  throw new Error(
1217
- `Ambiguous path definition: file '${this.path}' is included multiple times by ${file.importPath}`
1257
+ `Ambiguous path definition: file ${this.path} is included multiple times by ${file.filePath}`
1218
1258
  );
1219
1259
  }
1220
1260
  }
@@ -1236,10 +1276,10 @@ var _VDir = class _VDir {
1236
1276
  const dirs = [];
1237
1277
  const unique = /* @__PURE__ */ new Map();
1238
1278
  for (const root of roots) {
1239
- for (const path5 of paths) {
1279
+ for (const path7 of paths) {
1240
1280
  let dir = root;
1241
- for (const segment of path5.segments) {
1242
- dir = dir.addDir(path5, segment);
1281
+ for (const segment of path7.segments) {
1282
+ dir = dir.addDir(path7, segment);
1243
1283
  }
1244
1284
  const existing = unique.get(dir.path);
1245
1285
  if (existing) {
@@ -1252,7 +1292,7 @@ var _VDir = class _VDir {
1252
1292
  }
1253
1293
  }
1254
1294
  throw new Error(
1255
- `Ambiguous directory structure: '${sourcePath}${path5.source}' defines '${dir.path}' multiple times.`
1295
+ `Ambiguous directory structure: ${sourcePath}${path7.source} defines ${dir.path} multiple times.`
1256
1296
  );
1257
1297
  } else {
1258
1298
  unique.set(dir.path, dir);
@@ -1278,13 +1318,11 @@ function matchRoutableFile(filename) {
1278
1318
  const match = filename.match(routeableFileRegex);
1279
1319
  return match && (match[1] || match[3]).toLowerCase();
1280
1320
  }
1281
- function isSpecialType(type) {
1282
- return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
1283
- }
1284
- async function buildRoutes(sources) {
1321
+ async function buildRoutes(sources, outDir) {
1285
1322
  const uniqueRoutes = /* @__PURE__ */ new Map();
1286
1323
  const routes = [];
1287
1324
  const special = {};
1325
+ const seenKeys = /* @__PURE__ */ new Map();
1288
1326
  const middlewares = /* @__PURE__ */ new Set();
1289
1327
  const unusedFiles = /* @__PURE__ */ new Set();
1290
1328
  const currentLayouts = /* @__PURE__ */ new Set();
@@ -1292,13 +1330,13 @@ async function buildRoutes(sources) {
1292
1330
  const root = new VDir();
1293
1331
  const dirStack = [];
1294
1332
  let basePath;
1295
- let importPrefix;
1296
1333
  let activeDirs;
1297
1334
  let isBaseDir;
1298
1335
  let nextFileId = 1;
1299
1336
  let nextRouteIndex = 1;
1300
1337
  const walkOptions = {
1301
- onEnter({ name }) {
1338
+ onEnter(dir) {
1339
+ let { name } = dir;
1302
1340
  const prevDirStackLength = dirStack.length;
1303
1341
  if (isBaseDir) {
1304
1342
  isBaseDir = false;
@@ -1317,15 +1355,16 @@ async function buildRoutes(sources) {
1317
1355
  dirStack.length = prevDirStackLength;
1318
1356
  };
1319
1357
  },
1320
- onFile({ name, path: path5 }) {
1358
+ onFile(file) {
1359
+ const { name } = file;
1321
1360
  const match = name.match(routeableFileRegex);
1322
1361
  if (!match) {
1323
1362
  return;
1324
1363
  }
1325
1364
  const type = (match[1] || match[3]).toLowerCase();
1326
- if (dirStack.length && isSpecialType(type)) {
1365
+ if (dirStack.length && (type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error)) {
1327
1366
  console.warn(
1328
- `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${path5}`
1367
+ `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${file.path}`
1329
1368
  );
1330
1369
  return;
1331
1370
  }
@@ -1334,19 +1373,15 @@ async function buildRoutes(sources) {
1334
1373
  const paths = parseFlatRoute(name.slice(0, match.index));
1335
1374
  dirs = VDir.addPaths(activeDirs, paths);
1336
1375
  }
1337
- const dirPath = dirStack.join("/");
1338
- const relativePath = dirPath ? `${dirPath}/${name}` : name;
1339
- const file = {
1376
+ const routableFile = {
1340
1377
  id: String(nextFileId++),
1341
1378
  name,
1342
1379
  type,
1343
- filePath: path5,
1344
- relativePath,
1345
- importPath: `${importPrefix}/${relativePath}`,
1380
+ filePath: file.path,
1346
1381
  verbs: type === RoutableFileTypes.Page ? ["get", "head"] : void 0
1347
1382
  };
1348
1383
  for (const dir of dirs) {
1349
- dir.addFile(file);
1384
+ dir.addFile(routableFile);
1350
1385
  }
1351
1386
  }
1352
1387
  };
@@ -1354,7 +1389,6 @@ async function buildRoutes(sources) {
1354
1389
  sources = [sources];
1355
1390
  }
1356
1391
  for (const source of sources) {
1357
- importPrefix = source.importPrefix ? source.importPrefix.replace(/^\/+|\/+$/g, "") : "";
1358
1392
  basePath = source.basePath || "";
1359
1393
  activeDirs = [root];
1360
1394
  isBaseDir = true;
@@ -1374,7 +1408,8 @@ async function buildRoutes(sources) {
1374
1408
  layout = dir.files.get(RoutableFileTypes.Layout);
1375
1409
  const handler = dir.files.get(RoutableFileTypes.Handler);
1376
1410
  const page = dir.files.get(RoutableFileTypes.Page);
1377
- let hasSpecial = false;
1411
+ const pathInfo = dir.pathInfo;
1412
+ let layoutsUsed = false;
1378
1413
  if (middleware) {
1379
1414
  if (currentMiddleware.has(middleware)) {
1380
1415
  middleware = void 0;
@@ -1391,64 +1426,64 @@ async function buildRoutes(sources) {
1391
1426
  unusedFiles.add(layout);
1392
1427
  }
1393
1428
  }
1429
+ if (dir === root) {
1430
+ for (const [type, file] of dir.files) {
1431
+ if (type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error) {
1432
+ special[type] = {
1433
+ index: nextRouteIndex++,
1434
+ key: type,
1435
+ path: dir.pathInfo,
1436
+ middleware: [],
1437
+ layouts: [...currentLayouts],
1438
+ page: file,
1439
+ templateFilePath: currentLayouts.size ? path3.join(outDir, `${type}.marko`) : void 0
1440
+ };
1441
+ layoutsUsed = true;
1442
+ }
1443
+ }
1444
+ }
1394
1445
  if (page || handler) {
1395
- const path5 = dir.pathInfo;
1396
- if (uniqueRoutes.has(path5.id)) {
1397
- const existing = uniqueRoutes.get(path5.id);
1446
+ if (uniqueRoutes.has(pathInfo.id)) {
1447
+ const existing = uniqueRoutes.get(pathInfo.id);
1398
1448
  const route = routes[existing.index];
1399
1449
  const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
1400
1450
  const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
1401
- throw new Error(`Duplicate routes for path '${path5.id}' were defined. A route established by:
1402
- ${existingFiles.join(" and ")} via '${existing.dir.fullPath}'
1403
- collides with
1404
- ${currentFiles.join(" and ")} via '${dir.fullPath}'
1405
- `);
1451
+ throw new Error(
1452
+ `Duplicate routes for path ${pathInfo.id} were defined. A route established by: "${existingFiles.join(" and ")}" collides with "${currentFiles.join(" and ")}"`
1453
+ );
1454
+ }
1455
+ uniqueRoutes.set(pathInfo.id, { dir, index: routes.length });
1456
+ let key = pathInfo.segments.map(replaceInvalidFilenameChars).concat("route").join("/");
1457
+ const keyCount = (seenKeys.get(key) || 0) + 1;
1458
+ seenKeys.set(key, keyCount);
1459
+ if (keyCount > 1) {
1460
+ key += keyCount;
1406
1461
  }
1407
- uniqueRoutes.set(path5.id, { dir, index: routes.length });
1408
1462
  routes.push({
1409
1463
  index: nextRouteIndex++,
1410
- key: dir.fullPath,
1411
- paths: [path5],
1464
+ key,
1465
+ path: pathInfo,
1412
1466
  middleware: [...currentMiddleware],
1413
1467
  layouts: page ? [...currentLayouts] : [],
1414
1468
  meta: dir.files.get(RoutableFileTypes.Meta),
1415
1469
  page,
1416
1470
  handler,
1417
- entryName: `${markoRunFilePrefix}route` + (dir.path !== "/" ? dir.fullPath.replace(/\//g, ".").replace(/(%[A-Fa-f0-9]{2})+/g, "_") : "")
1471
+ templateFilePath: page && currentLayouts.size ? path3.join(outDir, key + ".marko") : void 0
1418
1472
  });
1419
- }
1420
- if (dir === root) {
1421
- for (const [type, file] of dir.files) {
1422
- if (isSpecialType(type)) {
1423
- hasSpecial = true;
1424
- special[type] = {
1425
- index: 0,
1426
- key: type,
1427
- paths: [],
1428
- middleware: [],
1429
- layouts: [...currentLayouts],
1430
- page: file,
1431
- entryName: `${markoRunFilePrefix}special.${type}`
1432
- };
1433
- }
1434
- }
1435
- }
1436
- if (handler || page) {
1473
+ layoutsUsed = !!page;
1437
1474
  for (const middleware2 of currentMiddleware) {
1438
1475
  middlewares.add(middleware2);
1439
1476
  unusedFiles.delete(middleware2);
1440
1477
  }
1441
1478
  }
1442
- if (page || hasSpecial) {
1479
+ if (layoutsUsed) {
1443
1480
  for (const layout2 of currentLayouts) {
1444
1481
  unusedFiles.delete(layout2);
1445
1482
  }
1446
1483
  }
1447
1484
  }
1448
- if (dir.dirs) {
1449
- for (const child of dir.dirs()) {
1450
- traverse(child);
1451
- }
1485
+ for (const childDir of dir.dirs()) {
1486
+ traverse(childDir);
1452
1487
  }
1453
1488
  if (middleware) {
1454
1489
  currentMiddleware.delete(middleware);
@@ -1458,10 +1493,13 @@ async function buildRoutes(sources) {
1458
1493
  }
1459
1494
  }
1460
1495
  }
1496
+ function replaceInvalidFilenameChars(str) {
1497
+ return str.replace(/[<>:"/\\|?*]+/g, "_");
1498
+ }
1461
1499
 
1462
1500
  // src/vite/routes/walk.ts
1463
1501
  import fs from "fs";
1464
- import path2 from "path";
1502
+ import path4 from "path";
1465
1503
  function createFSWalker(dir) {
1466
1504
  return async function walkFS({
1467
1505
  onEnter,
@@ -1476,7 +1514,7 @@ function createFSWalker(dir) {
1476
1514
  const entries = await fs.promises.readdir(dir2.path, {
1477
1515
  withFileTypes: true
1478
1516
  });
1479
- const prefix = dir2.path + path2.sep;
1517
+ const prefix = dir2.path + path4.sep;
1480
1518
  for (const entry of entries) {
1481
1519
  const walkEntry = {
1482
1520
  name: entry.name,
@@ -1499,7 +1537,7 @@ function createFSWalker(dir) {
1499
1537
  await walk(
1500
1538
  {
1501
1539
  path: dir,
1502
- name: path2.basename(dir)
1540
+ name: path4.basename(dir)
1503
1541
  },
1504
1542
  maxDepth
1505
1543
  );
@@ -1616,36 +1654,34 @@ function logRoutesTable(routes, bundle) {
1616
1654
  style: { compact: true }
1617
1655
  });
1618
1656
  for (const route of routes.list) {
1619
- for (const path5 of route.paths) {
1620
- const verbs = getVerbs(route, true);
1621
- let firstRow = true;
1622
- for (const verb of verbs) {
1623
- const entryType = [];
1624
- let size = "";
1625
- let verbCell = verbColor(verb)(verb.toUpperCase());
1626
- if (verb === "get" && !verbs.includes("head")) {
1627
- verbCell += kleur2.dim(`,${verbColor(verb)("HEAD")}`);
1628
- }
1629
- if (route.handler) {
1630
- entryType.push(kleur2.blue("handler"));
1631
- }
1632
- if (route.page && (verb === "get" || verb === "head")) {
1633
- entryType.push(kleur2.yellow("page"));
1634
- if (verb === "get") {
1635
- size = prettySize(computeRouteSize(route, bundle));
1636
- }
1637
- }
1638
- const row = [verbCell];
1639
- if (verbs.length === 1 || firstRow) {
1640
- row.push({ rowSpan: verbs.length, content: prettyPath(path5.path) });
1641
- firstRow = false;
1657
+ const verbs = getVerbs(route, true);
1658
+ let firstRow = true;
1659
+ for (const verb of verbs) {
1660
+ const entryType = [];
1661
+ let size = "";
1662
+ const verbCell = verbColor(verb)(verb.toUpperCase());
1663
+ if (route.handler) {
1664
+ entryType.push(kleur2.blue("handler"));
1665
+ }
1666
+ if (route.page && (verb === "get" || verb === "head")) {
1667
+ entryType.push(kleur2.yellow("page"));
1668
+ if (verb === "get") {
1669
+ size = prettySize(computeRouteSize(route, bundle));
1642
1670
  }
1643
- row.push(entryType.join(" -> "));
1644
- hasMiddleware && row.push(route.middleware.length || "");
1645
- hasMeta && row.push(route.meta ? "\u2713" : "");
1646
- row.push(size || "");
1647
- table.push(row);
1648
1671
  }
1672
+ const row = [verbCell];
1673
+ if (verbs.length === 1 || firstRow) {
1674
+ row.push({
1675
+ rowSpan: verbs.length,
1676
+ content: prettyPath(route.path.path)
1677
+ });
1678
+ firstRow = false;
1679
+ }
1680
+ row.push(entryType.join(" -> "));
1681
+ hasMiddleware && row.push(route.middleware.length || "");
1682
+ hasMeta && row.push(route.meta ? "\u2713" : "");
1683
+ row.push(size || "");
1684
+ table.push(row);
1649
1685
  }
1650
1686
  }
1651
1687
  for (const [key, route] of Object.entries(routes.special).sort()) {
@@ -1701,17 +1737,20 @@ function prettySize([bytes, compBytes]) {
1701
1737
  else str += kleur2.bold(kleur2.red(compSize));
1702
1738
  return str;
1703
1739
  }
1704
- function prettyPath(path5) {
1705
- return path5.replace(/\/\$\$(.*)$/, (_, p) => "/" + kleur2.bold(kleur2.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + kleur2.bold(kleur2.dim(`:${p}`)));
1740
+ function prettyPath(path7) {
1741
+ return path7.replace(
1742
+ /\/(\$\$?)(`?)([^/`]+)\2/g,
1743
+ (_, type, tick, key) => "/" + type + tick + kleur2.bold(kleur2.dim(key)) + tick
1744
+ );
1706
1745
  }
1707
1746
 
1708
1747
  // src/vite/utils/read-once-persisted-store.ts
1709
1748
  import { promises as fs2 } from "fs";
1710
1749
  import os from "os";
1711
- import path3 from "path";
1750
+ import path5 from "path";
1712
1751
  var noop = () => {
1713
1752
  };
1714
- var tmpFile = path3.join(os.tmpdir(), "marko-run-storage.json");
1753
+ var tmpFile = path5.join(os.tmpdir(), "marko-run-storage.json");
1715
1754
  var values = /* @__PURE__ */ new Map();
1716
1755
  var loadedFromDisk;
1717
1756
  var ReadOncePersistedStore = class {
@@ -1753,17 +1792,17 @@ process.once("beforeExit", (code) => {
1753
1792
 
1754
1793
  // src/vite/plugin.ts
1755
1794
  var debug = createDebug("@marko/run");
1756
- var __dirname = path4.dirname(fileURLToPath(import.meta.url));
1795
+ var __dirname = path6.dirname(fileURLToPath(import.meta.url));
1757
1796
  var PLUGIN_NAME_PREFIX = "marko-run-vite";
1758
- var POSIX_SEP = "/";
1759
- var WINDOWS_SEP = "\\";
1760
1797
  var CLIENT_OUT_DIR = "public";
1761
1798
  var MIDDLEWARE_FILENAME = `${markoRunFilePrefix}middleware.js`;
1762
1799
  var ROUTER_FILENAME = `${markoRunFilePrefix}router.js`;
1763
1800
  var defaultPort = Number(process.env.PORT || 3e3);
1764
- var normalizePath = path4.sep === WINDOWS_SEP ? (id) => id.replace(/\\/g, POSIX_SEP) : (id) => id;
1765
1801
  function markoRun(opts = {}) {
1766
- let { routesDir, adapter, ...markoVitePluginOptions } = opts;
1802
+ let routesDir;
1803
+ let adapter;
1804
+ let trailingSlashes;
1805
+ const { ...markoVitePluginOptions } = opts;
1767
1806
  let store;
1768
1807
  let root;
1769
1808
  let shouldEmptyOutDir = false;
@@ -1796,12 +1835,8 @@ function markoRun(opts = {}) {
1796
1835
  root,
1797
1836
  "{.tsconfig*,tsconfig*.json}"
1798
1837
  )))) {
1799
- const filepath = path4.join(typesDir, "routes.d.ts");
1800
- const data = await renderRouteTypeInfo(
1801
- routes2,
1802
- normalizePath(path4.relative(typesDir, resolvedRoutesDir)),
1803
- adapter
1804
- );
1838
+ const filepath = path6.join(typesDir, "routes.d.ts");
1839
+ const data = await renderRouteTypeInfo(routes2, typesDir, adapter);
1805
1840
  if (data !== typesFile || !fs3.existsSync(filepath)) {
1806
1841
  await ensureDir(typesDir);
1807
1842
  await fs3.promises.writeFile(filepath, typesFile = data);
@@ -1812,20 +1847,25 @@ function markoRun(opts = {}) {
1812
1847
  function buildVirtualFiles() {
1813
1848
  return buildVirtualFilesResult ?? (buildVirtualFilesResult = (async () => {
1814
1849
  virtualFiles.clear();
1815
- routes = await buildRoutes({
1816
- walker: createFSWalker(resolvedRoutesDir),
1817
- importPrefix: routesDir
1818
- });
1850
+ routes = await buildRoutes(
1851
+ {
1852
+ walker: createFSWalker(resolvedRoutesDir)
1853
+ },
1854
+ entryFilesDir
1855
+ );
1819
1856
  if (!routes.list.length) {
1820
1857
  throw new Error("No routes generated");
1821
1858
  }
1822
1859
  for (const route of routes.list) {
1823
- virtualFiles.set(path4.posix.join(root, `${route.entryName}.js`), "");
1860
+ virtualFiles.set(
1861
+ path6.posix.join(root, getRouteVirtualFileName(route)),
1862
+ ""
1863
+ );
1824
1864
  }
1825
1865
  if (routes.middleware.length) {
1826
- virtualFiles.set(path4.posix.join(root, MIDDLEWARE_FILENAME), "");
1866
+ virtualFiles.set(path6.posix.join(root, MIDDLEWARE_FILENAME), "");
1827
1867
  }
1828
- virtualFiles.set(path4.posix.join(root, ROUTER_FILENAME), "");
1868
+ virtualFiles.set(path6.posix.join(root, ROUTER_FILENAME), "");
1829
1869
  return routes;
1830
1870
  })());
1831
1871
  }
@@ -1839,111 +1879,78 @@ function markoRun(opts = {}) {
1839
1879
  fs3.rmSync(entryFilesDir, { recursive: true });
1840
1880
  }
1841
1881
  for (const route of routes2.list) {
1842
- const { handler, page, layouts } = route;
1843
- if (handler) {
1844
- const exports = await getExportsFromFile(context, handler.filePath);
1845
- handler.verbs = [];
1882
+ if (route.handler) {
1883
+ const exports = await getExportsFromFile(
1884
+ context,
1885
+ route.handler.filePath
1886
+ );
1887
+ route.handler.verbs = [];
1846
1888
  for (const name of exports) {
1847
1889
  const verb = name.toLowerCase();
1848
1890
  if (name === verb.toUpperCase() && httpVerbs.includes(verb)) {
1849
- handler.verbs.push(verb);
1891
+ route.handler.verbs.push(verb);
1850
1892
  }
1851
1893
  }
1852
- if (!handler.verbs.length) {
1894
+ if (!route.handler.verbs.length) {
1853
1895
  context.warn(
1854
- `Did not find any http verb exports in handler '${path4.relative(root, handler.filePath)}' - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`
1896
+ `Did not find any http verb exports in ${path6.relative(root, route.handler.filePath)} - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`
1855
1897
  );
1856
1898
  }
1857
1899
  }
1858
- if (page) {
1859
- if (layouts.length) {
1860
- const relativePath = path4.relative(
1861
- resolvedRoutesDir,
1862
- page.filePath
1863
- );
1864
- const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1865
- const routeFileRelativePathPosix = normalizePath(
1866
- path4.relative(routeFileDir, root)
1867
- );
1868
- fs3.mkdirSync(routeFileDir, { recursive: true });
1869
- const pageNameIndex = page.name.indexOf("+page");
1870
- const pageNamePrefix = pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : "";
1871
- fs3.writeFileSync(
1872
- route.templateFilePath = path4.join(
1873
- routeFileDir,
1874
- pageNamePrefix + "route.marko"
1875
- ),
1876
- renderRouteTemplate(
1877
- route,
1878
- (to) => path4.posix.join(routeFileRelativePathPosix, to)
1879
- )
1880
- );
1881
- } else {
1882
- route.templateFilePath = page.filePath;
1883
- }
1900
+ if (route.templateFilePath) {
1901
+ fs3.mkdirSync(path6.dirname(route.templateFilePath), {
1902
+ recursive: true
1903
+ });
1904
+ fs3.writeFileSync(
1905
+ route.templateFilePath,
1906
+ renderRouteTemplate(route, root)
1907
+ );
1884
1908
  }
1885
1909
  virtualFiles.set(
1886
- path4.posix.join(root, `${route.entryName}.js`),
1887
- renderRouteEntry(route, relativeEntryFilesDirPosix)
1910
+ path6.posix.join(root, getRouteVirtualFileName(route)),
1911
+ renderRouteEntry(route, root)
1888
1912
  );
1889
1913
  }
1890
1914
  for (const route of Object.values(routes2.special)) {
1891
- const { page, layouts, key } = route;
1892
- if (page) {
1893
- if (layouts.length) {
1894
- const relativePath = path4.relative(
1895
- resolvedRoutesDir,
1896
- page.filePath
1897
- );
1898
- const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1899
- const routeFileRelativePathPosix = normalizePath(
1900
- path4.relative(routeFileDir, root)
1901
- );
1902
- fs3.mkdirSync(routeFileDir, { recursive: true });
1903
- fs3.writeFileSync(
1904
- route.templateFilePath = path4.join(
1905
- routeFileDir,
1906
- `route.${key}.marko`
1907
- ),
1908
- renderRouteTemplate(
1909
- route,
1910
- (to) => path4.posix.join(routeFileRelativePathPosix, to)
1911
- )
1912
- );
1913
- } else {
1914
- route.templateFilePath = page.filePath;
1915
- }
1915
+ if (route.templateFilePath) {
1916
+ fs3.mkdirSync(path6.dirname(route.templateFilePath), {
1917
+ recursive: true
1918
+ });
1919
+ fs3.writeFileSync(
1920
+ route.templateFilePath,
1921
+ renderRouteTemplate(route, root)
1922
+ );
1916
1923
  }
1917
1924
  }
1918
1925
  if (routes2.middleware.length) {
1919
1926
  for (const middleware of routes2.middleware) {
1920
1927
  if (!(await getExportsFromFile(context, middleware.filePath)).includes("default")) {
1921
1928
  context.warn(
1922
- `Did not find a default export in middleware '${path4.relative(root, middleware.filePath)}'`
1929
+ `Did not find a default export in middleware '${path6.relative(root, middleware.filePath)}'`
1923
1930
  );
1924
1931
  }
1925
1932
  }
1926
1933
  virtualFiles.set(
1927
- path4.posix.join(root, MIDDLEWARE_FILENAME),
1928
- renderMiddleware(routes2.middleware)
1934
+ path6.posix.join(root, MIDDLEWARE_FILENAME),
1935
+ renderMiddleware(routes2.middleware, root)
1929
1936
  );
1930
1937
  }
1931
1938
  virtualFiles.set(
1932
- path4.posix.join(root, ROUTER_FILENAME),
1933
- renderRouter(routes2, relativeEntryFilesDirPosix, {
1934
- trailingSlashes: opts.trailingSlashes || "RedirectWithout"
1939
+ path6.posix.join(root, ROUTER_FILENAME),
1940
+ renderRouter(routes2, root, {
1941
+ trailingSlashes
1935
1942
  })
1936
1943
  );
1937
1944
  await writeTypesFile(routes2);
1938
1945
  if (adapter == null ? void 0 : adapter.routesGenerated) {
1939
- await adapter.routesGenerated(
1940
- routes2,
1941
- new Map(virtualFiles.entries()),
1942
- {
1946
+ await adapter.routesGenerated({
1947
+ routes: routes2,
1948
+ virtualFiles: new Map(virtualFiles.entries()),
1949
+ meta: {
1943
1950
  buildTime: times.routesBuild,
1944
1951
  renderTime: times.routesRender
1945
1952
  }
1946
- );
1953
+ });
1947
1954
  if (!isBuild) {
1948
1955
  await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes2.list));
1949
1956
  }
@@ -1953,7 +1960,7 @@ function markoRun(opts = {}) {
1953
1960
  throw err;
1954
1961
  }
1955
1962
  virtualFiles.set(
1956
- path4.posix.join(root, ROUTER_FILENAME),
1963
+ path6.posix.join(root, ROUTER_FILENAME),
1957
1964
  `throw ${JSON.stringify(prepareError(err))}`
1958
1965
  );
1959
1966
  }
@@ -1990,27 +1997,28 @@ function markoRun(opts = {}) {
1990
1997
  }
1991
1998
  }
1992
1999
  routesDir = opts.routesDir || "src/routes";
2000
+ trailingSlashes = opts.trailingSlashes || "RedirectWithout";
1993
2001
  store = new ReadOncePersistedStore(
1994
2002
  `vite-marko-run${opts.runtimeId ? `-${opts.runtimeId}` : ""}`
1995
2003
  );
1996
2004
  markoVitePluginOptions.runtimeId = opts.runtimeId;
1997
2005
  markoVitePluginOptions.basePathVar = opts.basePathVar;
1998
- resolvedRoutesDir = path4.resolve(root, routesDir);
1999
- outputDir = path4.join(root, ((_d = config2.build) == null ? void 0 : _d.outDir) || "dist");
2000
- entryFilesDir = path4.join(outputDir, ".marko-run");
2006
+ resolvedRoutesDir = path6.resolve(root, routesDir);
2007
+ outputDir = path6.join(root, ((_d = config2.build) == null ? void 0 : _d.outDir) || "dist");
2008
+ entryFilesDir = path6.join(outputDir, ".marko-run");
2001
2009
  entryFilesDirPosix = normalizePath(entryFilesDir);
2002
2010
  relativeEntryFilesDirPosix = normalizePath(
2003
- path4.relative(root, entryFilesDir)
2011
+ path6.relative(root, entryFilesDir)
2004
2012
  );
2005
- typesDir = path4.join(root, ".marko-run");
2006
- devEntryFile = path4.join(root, "index.html");
2013
+ typesDir = path6.join(root, ".marko-run");
2014
+ devEntryFile = path6.join(root, "index.html");
2007
2015
  devEntryFilePosix = normalizePath(devEntryFile);
2008
2016
  let outDir = ((_e = config2.build) == null ? void 0 : _e.outDir) || "dist";
2009
2017
  const assetsDir = ((_f = config2.build) == null ? void 0 : _f.assetsDir) || "assets";
2010
2018
  let rollupOutputOptions = (_h = (_g = config2.build) == null ? void 0 : _g.rollupOptions) == null ? void 0 : _h.output;
2011
2019
  if (isBuild) {
2012
2020
  if (!isSSRBuild) {
2013
- outDir = path4.join(outDir, CLIENT_OUT_DIR);
2021
+ outDir = path6.join(outDir, CLIENT_OUT_DIR);
2014
2022
  }
2015
2023
  const defaultRollupOutputOptions = {
2016
2024
  assetFileNames({ name }) {
@@ -2135,7 +2143,7 @@ function markoRun(opts = {}) {
2135
2143
  devServer.watcher.on("all", async (type, filename) => {
2136
2144
  seenErrors.clear();
2137
2145
  const routableFileType = matchRoutableFile(
2138
- path4.parse(filename).base
2146
+ path6.parse(filename).base
2139
2147
  );
2140
2148
  if (filename.startsWith(resolvedRoutesDir) && routableFileType) {
2141
2149
  if (type === "add" || type === "unlink" || type === "change" && (routableFileType === RoutableFileTypes.Handler || routableFileType === RoutableFileTypes.Middleware)) {
@@ -2185,19 +2193,19 @@ function markoRun(opts = {}) {
2185
2193
  },
2186
2194
  async resolveId(importee, importer) {
2187
2195
  if (importee === "@marko/run/router") {
2188
- return normalizePath(path4.resolve(root, ROUTER_FILENAME));
2196
+ return normalizePath(path6.resolve(root, ROUTER_FILENAME));
2189
2197
  } else if (importee.endsWith(".marko") && importee.includes(relativeEntryFilesDirPosix)) {
2190
2198
  if (!importee.startsWith(root)) {
2191
- importee = path4.resolve(root, "." + importee);
2199
+ importee = path6.resolve(root, "." + importee);
2192
2200
  }
2193
2201
  return normalizePath(importee);
2194
2202
  }
2195
2203
  let virtualFilePath;
2196
2204
  if (importee.startsWith(virtualFilePrefix)) {
2197
2205
  virtualFilePath = importee.slice(virtualFilePrefix.length + 1);
2198
- importee = path4.resolve(root, virtualFilePath);
2206
+ importee = path6.resolve(root, virtualFilePath);
2199
2207
  } else if (!isBuild && importer && (importer === devEntryFile || normalizePath(importer) === devEntryFilePosix) && importee.startsWith(`/${markoRunFilePrefix}`)) {
2200
- importee = path4.resolve(root, "." + importee);
2208
+ importee = path6.resolve(root, "." + importee);
2201
2209
  }
2202
2210
  importee = normalizePath(importee);
2203
2211
  if (!buildVirtualFilesResult) {
@@ -2206,7 +2214,7 @@ function markoRun(opts = {}) {
2206
2214
  if (virtualFiles.has(importee)) {
2207
2215
  return importee;
2208
2216
  } else if (virtualFilePath) {
2209
- const filePath = path4.resolve(__dirname, "..", virtualFilePath);
2217
+ const filePath = path6.resolve(__dirname, "..", virtualFilePath);
2210
2218
  return await this.resolve(filePath, importer, {
2211
2219
  skipSelf: true
2212
2220
  });
@@ -2245,7 +2253,7 @@ function markoRun(opts = {}) {
2245
2253
  const builtEntries = Object.values(bundle).reduce(
2246
2254
  (acc, item) => {
2247
2255
  if (item.type === "chunk" && item.isEntry) {
2248
- acc.push(path4.join(options.dir, item.fileName));
2256
+ acc.push(path6.join(options.dir, item.fileName));
2249
2257
  }
2250
2258
  return acc;
2251
2259
  },
@@ -2273,12 +2281,12 @@ function markoRun(opts = {}) {
2273
2281
  fs3.rmSync(entryFilesDir, { recursive: true });
2274
2282
  }
2275
2283
  if ((adapter == null ? void 0 : adapter.buildEnd) && routes) {
2276
- await adapter.buildEnd(
2277
- resolvedConfig,
2278
- routes.list,
2279
- routeData.builtEntries,
2280
- routeData.sourceEntries
2281
- );
2284
+ await adapter.buildEnd({
2285
+ routes,
2286
+ config: resolvedConfig,
2287
+ builtEntries: routeData.builtEntries,
2288
+ sourceEntries: routeData.sourceEntries
2289
+ });
2282
2290
  }
2283
2291
  }
2284
2292
  }
@@ -2310,11 +2318,11 @@ async function ensureDir(dir) {
2310
2318
  }
2311
2319
  async function getPackageData(dir) {
2312
2320
  do {
2313
- const pkgPath = path4.join(dir, "package.json");
2321
+ const pkgPath = path6.join(dir, "package.json");
2314
2322
  if (fs3.existsSync(pkgPath)) {
2315
2323
  return JSON.parse(await fs3.promises.readFile(pkgPath, "utf-8"));
2316
2324
  }
2317
- } while (dir !== (dir = path4.dirname(dir)));
2325
+ } while (dir !== (dir = path6.dirname(dir)));
2318
2326
  return null;
2319
2327
  }
2320
2328
  async function resolveAdapter(root, options, log) {