@marko/run 0.6.5 → 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,33 +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 {
876
- [Run.ContentKeyFor<typeof import('${path5}')>]: Marko.Body;
877
- }`
911
+ export interface Input extends Run.LayoutInput<typeof import("${modulePath}")> {}`
878
912
  );
879
913
  break;
880
914
  case RoutableFileTypes.Error:
881
915
  writeModuleDeclaration(
882
916
  writer,
883
- path5,
917
+ modulePath,
884
918
  "globalThis.MarkoRun.Route",
885
919
  `
886
920
  export interface Input {
@@ -889,7 +923,7 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
889
923
  );
890
924
  break;
891
925
  case RoutableFileTypes.NotFound:
892
- writeModuleDeclaration(writer, path5, "Run.Route");
926
+ writeModuleDeclaration(writer, modulePath, "Run.Route");
893
927
  break;
894
928
  }
895
929
  }
@@ -897,40 +931,15 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
897
931
  middlewareWriter.join();
898
932
  pageWriter.join();
899
933
  layoutWriter.join();
900
- writer.writeBlockStart(`
901
- type Routes = {`);
902
- for (const route of routes.list) {
903
- const { meta, handler, page } = route;
904
- if (page || handler) {
905
- const verbs = [];
906
- if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
907
- verbs.push(`"get"`);
908
- }
909
- if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
910
- verbs.push(`"post"`);
911
- }
912
- let routeType = `{ verb: ${verbs.join(" | ")};`;
913
- if (meta) {
914
- const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
915
- let metaType = `typeof import("${metaPath}")`;
916
- if (/\.(ts|js|mjs)$/.test(meta.name)) {
917
- metaType += `["default"]`;
918
- }
919
- routeType += ` meta: ${metaType};`;
920
- }
921
- writer.writeLines(`"${route.key}": ${routeType} };`);
922
- }
923
- }
924
- writer.writeBlockEnd("}");
925
934
  return writer.end();
926
935
  }
927
- function writeModuleDeclaration(writer, path5, routeType, moduleTypes) {
928
- writer.writeLines("").write(`declare module "${stripTsExtension(path5)}" {`);
936
+ function writeModuleDeclaration(writer, name, routeType, moduleTypes) {
937
+ writer.writeLines("").write(`declare module "${name}" {`);
929
938
  if (moduleTypes) {
930
939
  writer.write(moduleTypes);
931
940
  }
932
941
  if (routeType) {
933
- const isMarko = path5.endsWith(".marko");
942
+ const isMarko = name.endsWith(".marko");
934
943
  writer.write(`
935
944
  namespace MarkoRun {
936
945
  export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
@@ -944,21 +953,15 @@ function writeModuleDeclaration(writer, path5, routeType, moduleTypes) {
944
953
  writer.writeLines(`
945
954
  }`);
946
955
  }
947
- function pathToURLPatternString(path5) {
948
- return path5.replace(/\/\$(\$?)([^/]*)/g, (_, catchAll, name) => {
949
- name = decodeURIComponent(name);
950
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
951
- });
952
- }
953
956
  function createRouteTrie(routes) {
954
957
  const root = {
955
958
  key: ""
956
959
  };
957
- function insert(path5, route) {
960
+ function insert(path7, route) {
958
961
  let node = root;
959
- for (const segment of path5.segments) {
962
+ for (const segment of path7.segments) {
960
963
  if (segment === "$$") {
961
- node.catchAll ?? (node.catchAll = { route, path: path5 });
964
+ node.catchAll ?? (node.catchAll = { route, path: path7 });
962
965
  return;
963
966
  } else if (segment === "$") {
964
967
  node = node.dynamic ?? (node.dynamic = {
@@ -976,17 +979,18 @@ function createRouteTrie(routes) {
976
979
  node = next;
977
980
  }
978
981
  }
979
- node.path ?? (node.path = path5);
982
+ node.path ?? (node.path = path7);
980
983
  node.route ?? (node.route = route);
981
984
  }
982
985
  for (const route of routes) {
983
- for (const path5 of route.paths) {
984
- insert(path5, route);
985
- }
986
+ insert(route.path, route);
986
987
  }
987
988
  return root;
988
989
  }
989
990
 
991
+ // src/vite/routes/builder.ts
992
+ import path3 from "path";
993
+
990
994
  // src/vite/routes/parse.ts
991
995
  function parseFlatRoute(pattern) {
992
996
  if (!pattern) throw new Error("Empty pattern");
@@ -1001,53 +1005,72 @@ function parseFlatRoute(pattern) {
1001
1005
  ]);
1002
1006
  function parse2(basePaths, group) {
1003
1007
  const pathMap = /* @__PURE__ */ new Map();
1004
- const delimiters = group ? ").," : ".,";
1008
+ const delimiters = group ? "`).," : "`.,";
1005
1009
  let charCode;
1006
1010
  let segmentStart = i;
1007
1011
  let type;
1008
1012
  let current;
1013
+ let escaped = "";
1014
+ let escapeStart = 0;
1009
1015
  do {
1010
1016
  charCode = pattern.charCodeAt(i);
1011
- 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) {
1012
1028
  break;
1013
- } else if (charCode === 44) {
1029
+ } else if (charCode === 44 /* Alternate */) {
1014
1030
  if (!current) {
1015
1031
  segmentEnd(
1016
- basePaths.map((path5) => ({
1017
- ...path5,
1018
- segments: path5.segments.slice()
1032
+ basePaths.map((path7) => ({
1033
+ ...path7,
1034
+ segments: path7.segments.slice()
1019
1035
  })),
1020
- "",
1036
+ escaped,
1021
1037
  "_",
1022
1038
  pathMap
1023
1039
  );
1024
1040
  } else {
1025
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1041
+ segmentEnd(
1042
+ current,
1043
+ escaped + pattern.slice(segmentStart, i),
1044
+ type,
1045
+ pathMap
1046
+ );
1026
1047
  }
1027
1048
  current = void 0;
1028
1049
  type = void 0;
1050
+ escaped = "";
1029
1051
  segmentStart = ++i;
1030
- } else if (charCode === 46) {
1052
+ } else if (charCode === 46 /* Directory */) {
1031
1053
  if (current) {
1032
- segmentEnd(current, pattern.slice(segmentStart, i), type);
1054
+ segmentEnd(current, escaped + pattern.slice(segmentStart, i), type);
1033
1055
  }
1034
1056
  type = void 0;
1057
+ escaped = "";
1035
1058
  segmentStart = ++i;
1036
- } else if (charCode === 40) {
1059
+ } else if (charCode === 40 /* GroupStart */) {
1037
1060
  const groupPaths = parse2(current || basePaths, ++i);
1038
1061
  if (groupPaths.length) {
1039
1062
  current = groupPaths;
1040
1063
  }
1041
1064
  segmentStart = ++i;
1042
1065
  } else {
1043
- if (charCode === 95) {
1066
+ if (charCode === 95 /* Pathless */) {
1044
1067
  type = "_";
1045
- } else if (charCode === 36) {
1068
+ } else if (charCode === 36 /* Dynamic */) {
1046
1069
  type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
1047
1070
  }
1048
- current ?? (current = basePaths.map((path5) => ({
1049
- ...path5,
1050
- segments: path5.segments.slice()
1071
+ current ?? (current = basePaths.map((path7) => ({
1072
+ ...path7,
1073
+ segments: path7.segments.slice()
1051
1074
  })));
1052
1075
  i = len;
1053
1076
  for (const char of delimiters) {
@@ -1058,7 +1081,12 @@ function parseFlatRoute(pattern) {
1058
1081
  }
1059
1082
  }
1060
1083
  } while (i < len);
1061
- 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 */) {
1062
1090
  throw new Error(
1063
1091
  `Invalid route pattern: group was not closed '${pattern.slice(
1064
1092
  group
@@ -1067,16 +1095,21 @@ function parseFlatRoute(pattern) {
1067
1095
  }
1068
1096
  if (!current) {
1069
1097
  segmentEnd(
1070
- basePaths.map((path5) => ({
1071
- ...path5,
1072
- segments: path5.segments.slice()
1098
+ basePaths.map((path7) => ({
1099
+ ...path7,
1100
+ segments: path7.segments.slice()
1073
1101
  })),
1074
- "",
1075
- "_",
1102
+ escaped,
1103
+ void 0,
1076
1104
  pathMap
1077
1105
  );
1078
1106
  } else {
1079
- segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
1107
+ segmentEnd(
1108
+ current,
1109
+ escaped + pattern.slice(segmentStart, i),
1110
+ type,
1111
+ pathMap
1112
+ );
1080
1113
  }
1081
1114
  return [...pathMap.values()];
1082
1115
  }
@@ -1085,17 +1118,17 @@ function parseFlatRoute(pattern) {
1085
1118
  if (raw) {
1086
1119
  segment = {
1087
1120
  raw,
1088
- name: raw,
1121
+ name: normalizeSegment(raw),
1089
1122
  type
1090
1123
  };
1091
1124
  if (type === "$" || type === "$$") {
1092
1125
  segment.name = type;
1093
- segment.param = raw.slice(type.length);
1126
+ segment.param = normalizeParam(raw.slice(type.length));
1094
1127
  }
1095
1128
  }
1096
- for (const path5 of paths) {
1129
+ for (const path7 of paths) {
1097
1130
  if (segment) {
1098
- if (path5.isCatchall) {
1131
+ if (path7.isCatchall) {
1099
1132
  throw new Error(
1100
1133
  `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
1101
1134
  0,
@@ -1103,26 +1136,36 @@ function parseFlatRoute(pattern) {
1103
1136
  )}' in '${pattern}'.`
1104
1137
  );
1105
1138
  }
1106
- path5.segments.push(segment);
1107
- path5.id += path5.id === "/" ? segment.name : `/${segment.name}`;
1139
+ path7.segments.push(segment);
1140
+ path7.id += path7.id === "/" ? segment.name : `/${segment.name}`;
1108
1141
  if (type === "$$") {
1109
- path5.isCatchall = true;
1142
+ path7.isCatchall = true;
1110
1143
  }
1111
1144
  }
1112
1145
  if (map) {
1113
- if (map.has(path5.id)) {
1114
- const existing = map.get(path5.id);
1146
+ if (map.has(path7.id)) {
1147
+ const existing = map.get(path7.id);
1115
1148
  const existingExpansion = existing.segments.map((s) => s.raw).join(".");
1116
- const currentExpansion = path5.segments.map((s) => s.raw).join(".");
1149
+ const currentExpansion = path7.segments.map((s) => s.raw).join(".");
1117
1150
  throw new Error(
1118
- `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}'.`
1119
1152
  );
1120
1153
  }
1121
- map.set(path5.id, path5);
1154
+ map.set(path7.id, path7);
1122
1155
  }
1123
1156
  }
1124
1157
  }
1125
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
+ }
1126
1169
 
1127
1170
  // src/vite/routes/vdir.ts
1128
1171
  var _dirs, _pathlessDirs;
@@ -1133,14 +1176,12 @@ var _VDir = class _VDir {
1133
1176
  __publicField(this, "parent");
1134
1177
  __publicField(this, "source");
1135
1178
  __publicField(this, "path");
1136
- __publicField(this, "fullPath");
1137
1179
  __publicField(this, "segment");
1138
1180
  __publicField(this, "files");
1139
1181
  if (!parent || !segment) {
1140
1182
  this.parent = null;
1141
1183
  this.source = null;
1142
1184
  this.path = "/";
1143
- this.fullPath = "/";
1144
1185
  this.segment = {
1145
1186
  raw: "",
1146
1187
  name: ""
@@ -1148,12 +1189,8 @@ var _VDir = class _VDir {
1148
1189
  } else {
1149
1190
  this.parent = parent;
1150
1191
  this.source = source;
1151
- this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
1152
- this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
1153
- if (segment.param) {
1154
- this.fullPath += segment.param;
1155
- }
1156
1192
  this.segment = segment;
1193
+ this.path = parent.path + (parent.path === "/" ? "" : "/") + segment.name;
1157
1194
  }
1158
1195
  }
1159
1196
  get pathInfo() {
@@ -1166,17 +1203,18 @@ var _VDir = class _VDir {
1166
1203
  for (const { segment } of this) {
1167
1204
  const { type, name, param } = segment;
1168
1205
  if (name && type !== "_") {
1169
- value.id += sep + (type || name);
1206
+ value.id += sep + name;
1170
1207
  value.path += sep + name;
1171
1208
  value.isEnd = type === "$$";
1172
1209
  if (param) {
1173
- value.path += param;
1210
+ const unescapedParam = param.charAt(0) === "`" ? param.slice(1, -1) : param;
1174
1211
  const index = type === "$$" ? null : value.segments.length;
1175
1212
  if (!value.params) {
1176
- value.params = { [param]: index };
1213
+ value.params = { [unescapedParam]: index };
1177
1214
  } else if (!(param in value.params)) {
1178
- value.params[param] = index;
1215
+ value.params[unescapedParam] = index;
1179
1216
  }
1217
+ value.path += param;
1180
1218
  }
1181
1219
  value.segments.push(name);
1182
1220
  sep = "/";
@@ -1188,11 +1226,11 @@ var _VDir = class _VDir {
1188
1226
  });
1189
1227
  return value;
1190
1228
  }
1191
- addDir(path5, segment) {
1229
+ addDir(path7, segment) {
1192
1230
  const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
1193
1231
  const key = segment.type === "$" ? segment.raw : segment.name;
1194
1232
  if (!map.has(key)) {
1195
- const dir = new _VDir(this, segment, path5);
1233
+ const dir = new _VDir(this, segment, path7);
1196
1234
  map.set(key, dir);
1197
1235
  return dir;
1198
1236
  }
@@ -1208,15 +1246,15 @@ var _VDir = class _VDir {
1208
1246
  const existing = this.files.get(file.type);
1209
1247
  if (existing !== file) {
1210
1248
  throw new Error(
1211
- `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}.`
1212
1250
  );
1213
1251
  } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
1214
1252
  throw new Error(
1215
- `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}`
1216
1254
  );
1217
1255
  }
1218
1256
  throw new Error(
1219
- `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}`
1220
1258
  );
1221
1259
  }
1222
1260
  }
@@ -1238,10 +1276,10 @@ var _VDir = class _VDir {
1238
1276
  const dirs = [];
1239
1277
  const unique = /* @__PURE__ */ new Map();
1240
1278
  for (const root of roots) {
1241
- for (const path5 of paths) {
1279
+ for (const path7 of paths) {
1242
1280
  let dir = root;
1243
- for (const segment of path5.segments) {
1244
- dir = dir.addDir(path5, segment);
1281
+ for (const segment of path7.segments) {
1282
+ dir = dir.addDir(path7, segment);
1245
1283
  }
1246
1284
  const existing = unique.get(dir.path);
1247
1285
  if (existing) {
@@ -1254,7 +1292,7 @@ var _VDir = class _VDir {
1254
1292
  }
1255
1293
  }
1256
1294
  throw new Error(
1257
- `Ambiguous directory structure: '${sourcePath}${path5.source}' defines '${dir.path}' multiple times.`
1295
+ `Ambiguous directory structure: ${sourcePath}${path7.source} defines ${dir.path} multiple times.`
1258
1296
  );
1259
1297
  } else {
1260
1298
  unique.set(dir.path, dir);
@@ -1280,13 +1318,11 @@ function matchRoutableFile(filename) {
1280
1318
  const match = filename.match(routeableFileRegex);
1281
1319
  return match && (match[1] || match[3]).toLowerCase();
1282
1320
  }
1283
- function isSpecialType(type) {
1284
- return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
1285
- }
1286
- async function buildRoutes(sources) {
1321
+ async function buildRoutes(sources, outDir) {
1287
1322
  const uniqueRoutes = /* @__PURE__ */ new Map();
1288
1323
  const routes = [];
1289
1324
  const special = {};
1325
+ const seenKeys = /* @__PURE__ */ new Map();
1290
1326
  const middlewares = /* @__PURE__ */ new Set();
1291
1327
  const unusedFiles = /* @__PURE__ */ new Set();
1292
1328
  const currentLayouts = /* @__PURE__ */ new Set();
@@ -1294,13 +1330,13 @@ async function buildRoutes(sources) {
1294
1330
  const root = new VDir();
1295
1331
  const dirStack = [];
1296
1332
  let basePath;
1297
- let importPrefix;
1298
1333
  let activeDirs;
1299
1334
  let isBaseDir;
1300
1335
  let nextFileId = 1;
1301
1336
  let nextRouteIndex = 1;
1302
1337
  const walkOptions = {
1303
- onEnter({ name }) {
1338
+ onEnter(dir) {
1339
+ let { name } = dir;
1304
1340
  const prevDirStackLength = dirStack.length;
1305
1341
  if (isBaseDir) {
1306
1342
  isBaseDir = false;
@@ -1319,15 +1355,16 @@ async function buildRoutes(sources) {
1319
1355
  dirStack.length = prevDirStackLength;
1320
1356
  };
1321
1357
  },
1322
- onFile({ name, path: path5 }) {
1358
+ onFile(file) {
1359
+ const { name } = file;
1323
1360
  const match = name.match(routeableFileRegex);
1324
1361
  if (!match) {
1325
1362
  return;
1326
1363
  }
1327
1364
  const type = (match[1] || match[3]).toLowerCase();
1328
- if (dirStack.length && isSpecialType(type)) {
1365
+ if (dirStack.length && (type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error)) {
1329
1366
  console.warn(
1330
- `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}`
1331
1368
  );
1332
1369
  return;
1333
1370
  }
@@ -1336,19 +1373,15 @@ async function buildRoutes(sources) {
1336
1373
  const paths = parseFlatRoute(name.slice(0, match.index));
1337
1374
  dirs = VDir.addPaths(activeDirs, paths);
1338
1375
  }
1339
- const dirPath = dirStack.join("/");
1340
- const relativePath = dirPath ? `${dirPath}/${name}` : name;
1341
- const file = {
1376
+ const routableFile = {
1342
1377
  id: String(nextFileId++),
1343
1378
  name,
1344
1379
  type,
1345
- filePath: path5,
1346
- relativePath,
1347
- importPath: `${importPrefix}/${relativePath}`,
1380
+ filePath: file.path,
1348
1381
  verbs: type === RoutableFileTypes.Page ? ["get", "head"] : void 0
1349
1382
  };
1350
1383
  for (const dir of dirs) {
1351
- dir.addFile(file);
1384
+ dir.addFile(routableFile);
1352
1385
  }
1353
1386
  }
1354
1387
  };
@@ -1356,7 +1389,6 @@ async function buildRoutes(sources) {
1356
1389
  sources = [sources];
1357
1390
  }
1358
1391
  for (const source of sources) {
1359
- importPrefix = source.importPrefix ? source.importPrefix.replace(/^\/+|\/+$/g, "") : "";
1360
1392
  basePath = source.basePath || "";
1361
1393
  activeDirs = [root];
1362
1394
  isBaseDir = true;
@@ -1376,7 +1408,8 @@ async function buildRoutes(sources) {
1376
1408
  layout = dir.files.get(RoutableFileTypes.Layout);
1377
1409
  const handler = dir.files.get(RoutableFileTypes.Handler);
1378
1410
  const page = dir.files.get(RoutableFileTypes.Page);
1379
- let hasSpecial = false;
1411
+ const pathInfo = dir.pathInfo;
1412
+ let layoutsUsed = false;
1380
1413
  if (middleware) {
1381
1414
  if (currentMiddleware.has(middleware)) {
1382
1415
  middleware = void 0;
@@ -1393,64 +1426,64 @@ async function buildRoutes(sources) {
1393
1426
  unusedFiles.add(layout);
1394
1427
  }
1395
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
+ }
1396
1445
  if (page || handler) {
1397
- const path5 = dir.pathInfo;
1398
- if (uniqueRoutes.has(path5.id)) {
1399
- const existing = uniqueRoutes.get(path5.id);
1446
+ if (uniqueRoutes.has(pathInfo.id)) {
1447
+ const existing = uniqueRoutes.get(pathInfo.id);
1400
1448
  const route = routes[existing.index];
1401
1449
  const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
1402
1450
  const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
1403
- throw new Error(`Duplicate routes for path '${path5.id}' were defined. A route established by:
1404
- ${existingFiles.join(" and ")} via '${existing.dir.fullPath}'
1405
- collides with
1406
- ${currentFiles.join(" and ")} via '${dir.fullPath}'
1407
- `);
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;
1408
1461
  }
1409
- uniqueRoutes.set(path5.id, { dir, index: routes.length });
1410
1462
  routes.push({
1411
1463
  index: nextRouteIndex++,
1412
- key: dir.fullPath,
1413
- paths: [path5],
1464
+ key,
1465
+ path: pathInfo,
1414
1466
  middleware: [...currentMiddleware],
1415
1467
  layouts: page ? [...currentLayouts] : [],
1416
1468
  meta: dir.files.get(RoutableFileTypes.Meta),
1417
1469
  page,
1418
1470
  handler,
1419
- 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
1420
1472
  });
1421
- }
1422
- if (dir === root) {
1423
- for (const [type, file] of dir.files) {
1424
- if (isSpecialType(type)) {
1425
- hasSpecial = true;
1426
- special[type] = {
1427
- index: 0,
1428
- key: type,
1429
- paths: [],
1430
- middleware: [],
1431
- layouts: [...currentLayouts],
1432
- page: file,
1433
- entryName: `${markoRunFilePrefix}special.${type}`
1434
- };
1435
- }
1436
- }
1437
- }
1438
- if (handler || page) {
1473
+ layoutsUsed = !!page;
1439
1474
  for (const middleware2 of currentMiddleware) {
1440
1475
  middlewares.add(middleware2);
1441
1476
  unusedFiles.delete(middleware2);
1442
1477
  }
1443
1478
  }
1444
- if (page || hasSpecial) {
1479
+ if (layoutsUsed) {
1445
1480
  for (const layout2 of currentLayouts) {
1446
1481
  unusedFiles.delete(layout2);
1447
1482
  }
1448
1483
  }
1449
1484
  }
1450
- if (dir.dirs) {
1451
- for (const child of dir.dirs()) {
1452
- traverse(child);
1453
- }
1485
+ for (const childDir of dir.dirs()) {
1486
+ traverse(childDir);
1454
1487
  }
1455
1488
  if (middleware) {
1456
1489
  currentMiddleware.delete(middleware);
@@ -1460,10 +1493,13 @@ async function buildRoutes(sources) {
1460
1493
  }
1461
1494
  }
1462
1495
  }
1496
+ function replaceInvalidFilenameChars(str) {
1497
+ return str.replace(/[<>:"/\\|?*]+/g, "_");
1498
+ }
1463
1499
 
1464
1500
  // src/vite/routes/walk.ts
1465
1501
  import fs from "fs";
1466
- import path2 from "path";
1502
+ import path4 from "path";
1467
1503
  function createFSWalker(dir) {
1468
1504
  return async function walkFS({
1469
1505
  onEnter,
@@ -1478,7 +1514,7 @@ function createFSWalker(dir) {
1478
1514
  const entries = await fs.promises.readdir(dir2.path, {
1479
1515
  withFileTypes: true
1480
1516
  });
1481
- const prefix = dir2.path + path2.sep;
1517
+ const prefix = dir2.path + path4.sep;
1482
1518
  for (const entry of entries) {
1483
1519
  const walkEntry = {
1484
1520
  name: entry.name,
@@ -1501,7 +1537,7 @@ function createFSWalker(dir) {
1501
1537
  await walk(
1502
1538
  {
1503
1539
  path: dir,
1504
- name: path2.basename(dir)
1540
+ name: path4.basename(dir)
1505
1541
  },
1506
1542
  maxDepth
1507
1543
  );
@@ -1618,36 +1654,34 @@ function logRoutesTable(routes, bundle) {
1618
1654
  style: { compact: true }
1619
1655
  });
1620
1656
  for (const route of routes.list) {
1621
- for (const path5 of route.paths) {
1622
- const verbs = getVerbs(route, true);
1623
- let firstRow = true;
1624
- for (const verb of verbs) {
1625
- const entryType = [];
1626
- let size = "";
1627
- let verbCell = verbColor(verb)(verb.toUpperCase());
1628
- if (verb === "get" && !verbs.includes("head")) {
1629
- verbCell += kleur2.dim(`,${verbColor(verb)("HEAD")}`);
1630
- }
1631
- if (route.handler) {
1632
- entryType.push(kleur2.blue("handler"));
1633
- }
1634
- if (route.page && (verb === "get" || verb === "head")) {
1635
- entryType.push(kleur2.yellow("page"));
1636
- if (verb === "get") {
1637
- size = prettySize(computeRouteSize(route, bundle));
1638
- }
1639
- }
1640
- const row = [verbCell];
1641
- if (verbs.length === 1 || firstRow) {
1642
- row.push({ rowSpan: verbs.length, content: prettyPath(path5.path) });
1643
- 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));
1644
1670
  }
1645
- row.push(entryType.join(" -> "));
1646
- hasMiddleware && row.push(route.middleware.length || "");
1647
- hasMeta && row.push(route.meta ? "\u2713" : "");
1648
- row.push(size || "");
1649
- table.push(row);
1650
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);
1651
1685
  }
1652
1686
  }
1653
1687
  for (const [key, route] of Object.entries(routes.special).sort()) {
@@ -1703,17 +1737,20 @@ function prettySize([bytes, compBytes]) {
1703
1737
  else str += kleur2.bold(kleur2.red(compSize));
1704
1738
  return str;
1705
1739
  }
1706
- function prettyPath(path5) {
1707
- 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
+ );
1708
1745
  }
1709
1746
 
1710
1747
  // src/vite/utils/read-once-persisted-store.ts
1711
1748
  import { promises as fs2 } from "fs";
1712
1749
  import os from "os";
1713
- import path3 from "path";
1750
+ import path5 from "path";
1714
1751
  var noop = () => {
1715
1752
  };
1716
- var tmpFile = path3.join(os.tmpdir(), "marko-run-storage.json");
1753
+ var tmpFile = path5.join(os.tmpdir(), "marko-run-storage.json");
1717
1754
  var values = /* @__PURE__ */ new Map();
1718
1755
  var loadedFromDisk;
1719
1756
  var ReadOncePersistedStore = class {
@@ -1755,17 +1792,17 @@ process.once("beforeExit", (code) => {
1755
1792
 
1756
1793
  // src/vite/plugin.ts
1757
1794
  var debug = createDebug("@marko/run");
1758
- var __dirname = path4.dirname(fileURLToPath(import.meta.url));
1795
+ var __dirname = path6.dirname(fileURLToPath(import.meta.url));
1759
1796
  var PLUGIN_NAME_PREFIX = "marko-run-vite";
1760
- var POSIX_SEP = "/";
1761
- var WINDOWS_SEP = "\\";
1762
1797
  var CLIENT_OUT_DIR = "public";
1763
1798
  var MIDDLEWARE_FILENAME = `${markoRunFilePrefix}middleware.js`;
1764
1799
  var ROUTER_FILENAME = `${markoRunFilePrefix}router.js`;
1765
1800
  var defaultPort = Number(process.env.PORT || 3e3);
1766
- var normalizePath = path4.sep === WINDOWS_SEP ? (id) => id.replace(/\\/g, POSIX_SEP) : (id) => id;
1767
1801
  function markoRun(opts = {}) {
1768
- let { routesDir, adapter, ...markoVitePluginOptions } = opts;
1802
+ let routesDir;
1803
+ let adapter;
1804
+ let trailingSlashes;
1805
+ const { ...markoVitePluginOptions } = opts;
1769
1806
  let store;
1770
1807
  let root;
1771
1808
  let shouldEmptyOutDir = false;
@@ -1798,12 +1835,8 @@ function markoRun(opts = {}) {
1798
1835
  root,
1799
1836
  "{.tsconfig*,tsconfig*.json}"
1800
1837
  )))) {
1801
- const filepath = path4.join(typesDir, "routes.d.ts");
1802
- const data = await renderRouteTypeInfo(
1803
- routes2,
1804
- normalizePath(path4.relative(typesDir, resolvedRoutesDir)),
1805
- adapter
1806
- );
1838
+ const filepath = path6.join(typesDir, "routes.d.ts");
1839
+ const data = await renderRouteTypeInfo(routes2, typesDir, adapter);
1807
1840
  if (data !== typesFile || !fs3.existsSync(filepath)) {
1808
1841
  await ensureDir(typesDir);
1809
1842
  await fs3.promises.writeFile(filepath, typesFile = data);
@@ -1814,20 +1847,25 @@ function markoRun(opts = {}) {
1814
1847
  function buildVirtualFiles() {
1815
1848
  return buildVirtualFilesResult ?? (buildVirtualFilesResult = (async () => {
1816
1849
  virtualFiles.clear();
1817
- routes = await buildRoutes({
1818
- walker: createFSWalker(resolvedRoutesDir),
1819
- importPrefix: routesDir
1820
- });
1850
+ routes = await buildRoutes(
1851
+ {
1852
+ walker: createFSWalker(resolvedRoutesDir)
1853
+ },
1854
+ entryFilesDir
1855
+ );
1821
1856
  if (!routes.list.length) {
1822
1857
  throw new Error("No routes generated");
1823
1858
  }
1824
1859
  for (const route of routes.list) {
1825
- virtualFiles.set(path4.posix.join(root, `${route.entryName}.js`), "");
1860
+ virtualFiles.set(
1861
+ path6.posix.join(root, getRouteVirtualFileName(route)),
1862
+ ""
1863
+ );
1826
1864
  }
1827
1865
  if (routes.middleware.length) {
1828
- virtualFiles.set(path4.posix.join(root, MIDDLEWARE_FILENAME), "");
1866
+ virtualFiles.set(path6.posix.join(root, MIDDLEWARE_FILENAME), "");
1829
1867
  }
1830
- virtualFiles.set(path4.posix.join(root, ROUTER_FILENAME), "");
1868
+ virtualFiles.set(path6.posix.join(root, ROUTER_FILENAME), "");
1831
1869
  return routes;
1832
1870
  })());
1833
1871
  }
@@ -1841,111 +1879,78 @@ function markoRun(opts = {}) {
1841
1879
  fs3.rmSync(entryFilesDir, { recursive: true });
1842
1880
  }
1843
1881
  for (const route of routes2.list) {
1844
- const { handler, page, layouts } = route;
1845
- if (handler) {
1846
- const exports = await getExportsFromFile(context, handler.filePath);
1847
- handler.verbs = [];
1882
+ if (route.handler) {
1883
+ const exports = await getExportsFromFile(
1884
+ context,
1885
+ route.handler.filePath
1886
+ );
1887
+ route.handler.verbs = [];
1848
1888
  for (const name of exports) {
1849
1889
  const verb = name.toLowerCase();
1850
1890
  if (name === verb.toUpperCase() && httpVerbs.includes(verb)) {
1851
- handler.verbs.push(verb);
1891
+ route.handler.verbs.push(verb);
1852
1892
  }
1853
1893
  }
1854
- if (!handler.verbs.length) {
1894
+ if (!route.handler.verbs.length) {
1855
1895
  context.warn(
1856
- `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(", ")}`
1857
1897
  );
1858
1898
  }
1859
1899
  }
1860
- if (page) {
1861
- if (layouts.length) {
1862
- const relativePath = path4.relative(
1863
- resolvedRoutesDir,
1864
- page.filePath
1865
- );
1866
- const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1867
- const routeFileRelativePathPosix = normalizePath(
1868
- path4.relative(routeFileDir, root)
1869
- );
1870
- fs3.mkdirSync(routeFileDir, { recursive: true });
1871
- const pageNameIndex = page.name.indexOf("+page");
1872
- const pageNamePrefix = pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : "";
1873
- fs3.writeFileSync(
1874
- route.templateFilePath = path4.join(
1875
- routeFileDir,
1876
- pageNamePrefix + "route.marko"
1877
- ),
1878
- renderRouteTemplate(
1879
- route,
1880
- (to) => path4.posix.join(routeFileRelativePathPosix, to)
1881
- )
1882
- );
1883
- } else {
1884
- route.templateFilePath = page.filePath;
1885
- }
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
+ );
1886
1908
  }
1887
1909
  virtualFiles.set(
1888
- path4.posix.join(root, `${route.entryName}.js`),
1889
- renderRouteEntry(route, relativeEntryFilesDirPosix)
1910
+ path6.posix.join(root, getRouteVirtualFileName(route)),
1911
+ renderRouteEntry(route, root)
1890
1912
  );
1891
1913
  }
1892
1914
  for (const route of Object.values(routes2.special)) {
1893
- const { page, layouts, key } = route;
1894
- if (page) {
1895
- if (layouts.length) {
1896
- const relativePath = path4.relative(
1897
- resolvedRoutesDir,
1898
- page.filePath
1899
- );
1900
- const routeFileDir = path4.join(entryFilesDir, relativePath, "..");
1901
- const routeFileRelativePathPosix = normalizePath(
1902
- path4.relative(routeFileDir, root)
1903
- );
1904
- fs3.mkdirSync(routeFileDir, { recursive: true });
1905
- fs3.writeFileSync(
1906
- route.templateFilePath = path4.join(
1907
- routeFileDir,
1908
- `route.${key}.marko`
1909
- ),
1910
- renderRouteTemplate(
1911
- route,
1912
- (to) => path4.posix.join(routeFileRelativePathPosix, to)
1913
- )
1914
- );
1915
- } else {
1916
- route.templateFilePath = page.filePath;
1917
- }
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
+ );
1918
1923
  }
1919
1924
  }
1920
1925
  if (routes2.middleware.length) {
1921
1926
  for (const middleware of routes2.middleware) {
1922
1927
  if (!(await getExportsFromFile(context, middleware.filePath)).includes("default")) {
1923
1928
  context.warn(
1924
- `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)}'`
1925
1930
  );
1926
1931
  }
1927
1932
  }
1928
1933
  virtualFiles.set(
1929
- path4.posix.join(root, MIDDLEWARE_FILENAME),
1930
- renderMiddleware(routes2.middleware)
1934
+ path6.posix.join(root, MIDDLEWARE_FILENAME),
1935
+ renderMiddleware(routes2.middleware, root)
1931
1936
  );
1932
1937
  }
1933
1938
  virtualFiles.set(
1934
- path4.posix.join(root, ROUTER_FILENAME),
1935
- renderRouter(routes2, relativeEntryFilesDirPosix, {
1936
- trailingSlashes: opts.trailingSlashes || "RedirectWithout"
1939
+ path6.posix.join(root, ROUTER_FILENAME),
1940
+ renderRouter(routes2, root, {
1941
+ trailingSlashes
1937
1942
  })
1938
1943
  );
1939
1944
  await writeTypesFile(routes2);
1940
1945
  if (adapter == null ? void 0 : adapter.routesGenerated) {
1941
- await adapter.routesGenerated(
1942
- routes2,
1943
- new Map(virtualFiles.entries()),
1944
- {
1946
+ await adapter.routesGenerated({
1947
+ routes: routes2,
1948
+ virtualFiles: new Map(virtualFiles.entries()),
1949
+ meta: {
1945
1950
  buildTime: times.routesBuild,
1946
1951
  renderTime: times.routesRender
1947
1952
  }
1948
- );
1953
+ });
1949
1954
  if (!isBuild) {
1950
1955
  await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes2.list));
1951
1956
  }
@@ -1955,7 +1960,7 @@ function markoRun(opts = {}) {
1955
1960
  throw err;
1956
1961
  }
1957
1962
  virtualFiles.set(
1958
- path4.posix.join(root, ROUTER_FILENAME),
1963
+ path6.posix.join(root, ROUTER_FILENAME),
1959
1964
  `throw ${JSON.stringify(prepareError(err))}`
1960
1965
  );
1961
1966
  }
@@ -1992,27 +1997,28 @@ function markoRun(opts = {}) {
1992
1997
  }
1993
1998
  }
1994
1999
  routesDir = opts.routesDir || "src/routes";
2000
+ trailingSlashes = opts.trailingSlashes || "RedirectWithout";
1995
2001
  store = new ReadOncePersistedStore(
1996
2002
  `vite-marko-run${opts.runtimeId ? `-${opts.runtimeId}` : ""}`
1997
2003
  );
1998
2004
  markoVitePluginOptions.runtimeId = opts.runtimeId;
1999
2005
  markoVitePluginOptions.basePathVar = opts.basePathVar;
2000
- resolvedRoutesDir = path4.resolve(root, routesDir);
2001
- outputDir = path4.join(root, ((_d = config2.build) == null ? void 0 : _d.outDir) || "dist");
2002
- 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");
2003
2009
  entryFilesDirPosix = normalizePath(entryFilesDir);
2004
2010
  relativeEntryFilesDirPosix = normalizePath(
2005
- path4.relative(root, entryFilesDir)
2011
+ path6.relative(root, entryFilesDir)
2006
2012
  );
2007
- typesDir = path4.join(root, ".marko-run");
2008
- devEntryFile = path4.join(root, "index.html");
2013
+ typesDir = path6.join(root, ".marko-run");
2014
+ devEntryFile = path6.join(root, "index.html");
2009
2015
  devEntryFilePosix = normalizePath(devEntryFile);
2010
2016
  let outDir = ((_e = config2.build) == null ? void 0 : _e.outDir) || "dist";
2011
2017
  const assetsDir = ((_f = config2.build) == null ? void 0 : _f.assetsDir) || "assets";
2012
2018
  let rollupOutputOptions = (_h = (_g = config2.build) == null ? void 0 : _g.rollupOptions) == null ? void 0 : _h.output;
2013
2019
  if (isBuild) {
2014
2020
  if (!isSSRBuild) {
2015
- outDir = path4.join(outDir, CLIENT_OUT_DIR);
2021
+ outDir = path6.join(outDir, CLIENT_OUT_DIR);
2016
2022
  }
2017
2023
  const defaultRollupOutputOptions = {
2018
2024
  assetFileNames({ name }) {
@@ -2137,7 +2143,7 @@ function markoRun(opts = {}) {
2137
2143
  devServer.watcher.on("all", async (type, filename) => {
2138
2144
  seenErrors.clear();
2139
2145
  const routableFileType = matchRoutableFile(
2140
- path4.parse(filename).base
2146
+ path6.parse(filename).base
2141
2147
  );
2142
2148
  if (filename.startsWith(resolvedRoutesDir) && routableFileType) {
2143
2149
  if (type === "add" || type === "unlink" || type === "change" && (routableFileType === RoutableFileTypes.Handler || routableFileType === RoutableFileTypes.Middleware)) {
@@ -2187,19 +2193,19 @@ function markoRun(opts = {}) {
2187
2193
  },
2188
2194
  async resolveId(importee, importer) {
2189
2195
  if (importee === "@marko/run/router") {
2190
- return normalizePath(path4.resolve(root, ROUTER_FILENAME));
2196
+ return normalizePath(path6.resolve(root, ROUTER_FILENAME));
2191
2197
  } else if (importee.endsWith(".marko") && importee.includes(relativeEntryFilesDirPosix)) {
2192
2198
  if (!importee.startsWith(root)) {
2193
- importee = path4.resolve(root, "." + importee);
2199
+ importee = path6.resolve(root, "." + importee);
2194
2200
  }
2195
2201
  return normalizePath(importee);
2196
2202
  }
2197
2203
  let virtualFilePath;
2198
2204
  if (importee.startsWith(virtualFilePrefix)) {
2199
2205
  virtualFilePath = importee.slice(virtualFilePrefix.length + 1);
2200
- importee = path4.resolve(root, virtualFilePath);
2206
+ importee = path6.resolve(root, virtualFilePath);
2201
2207
  } else if (!isBuild && importer && (importer === devEntryFile || normalizePath(importer) === devEntryFilePosix) && importee.startsWith(`/${markoRunFilePrefix}`)) {
2202
- importee = path4.resolve(root, "." + importee);
2208
+ importee = path6.resolve(root, "." + importee);
2203
2209
  }
2204
2210
  importee = normalizePath(importee);
2205
2211
  if (!buildVirtualFilesResult) {
@@ -2208,7 +2214,7 @@ function markoRun(opts = {}) {
2208
2214
  if (virtualFiles.has(importee)) {
2209
2215
  return importee;
2210
2216
  } else if (virtualFilePath) {
2211
- const filePath = path4.resolve(__dirname, "..", virtualFilePath);
2217
+ const filePath = path6.resolve(__dirname, "..", virtualFilePath);
2212
2218
  return await this.resolve(filePath, importer, {
2213
2219
  skipSelf: true
2214
2220
  });
@@ -2247,7 +2253,7 @@ function markoRun(opts = {}) {
2247
2253
  const builtEntries = Object.values(bundle).reduce(
2248
2254
  (acc, item) => {
2249
2255
  if (item.type === "chunk" && item.isEntry) {
2250
- acc.push(path4.join(options.dir, item.fileName));
2256
+ acc.push(path6.join(options.dir, item.fileName));
2251
2257
  }
2252
2258
  return acc;
2253
2259
  },
@@ -2275,12 +2281,12 @@ function markoRun(opts = {}) {
2275
2281
  fs3.rmSync(entryFilesDir, { recursive: true });
2276
2282
  }
2277
2283
  if ((adapter == null ? void 0 : adapter.buildEnd) && routes) {
2278
- await adapter.buildEnd(
2279
- resolvedConfig,
2280
- routes.list,
2281
- routeData.builtEntries,
2282
- routeData.sourceEntries
2283
- );
2284
+ await adapter.buildEnd({
2285
+ routes,
2286
+ config: resolvedConfig,
2287
+ builtEntries: routeData.builtEntries,
2288
+ sourceEntries: routeData.sourceEntries
2289
+ });
2284
2290
  }
2285
2291
  }
2286
2292
  }
@@ -2312,11 +2318,11 @@ async function ensureDir(dir) {
2312
2318
  }
2313
2319
  async function getPackageData(dir) {
2314
2320
  do {
2315
- const pkgPath = path4.join(dir, "package.json");
2321
+ const pkgPath = path6.join(dir, "package.json");
2316
2322
  if (fs3.existsSync(pkgPath)) {
2317
2323
  return JSON.parse(await fs3.promises.readFile(pkgPath, "utf-8"));
2318
2324
  }
2319
- } while (dir !== (dir = path4.dirname(dir)));
2325
+ } while (dir !== (dir = path6.dirname(dir)));
2320
2326
  return null;
2321
2327
  }
2322
2328
  async function resolveAdapter(root, options, log) {