@marko/run 0.0.1-beta6 → 0.0.1-beta8

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.
@@ -160,7 +160,14 @@ async function buildRoutes(walk, basePath) {
160
160
  if (handler || page) {
161
161
  const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
162
162
  if (routes.has(key)) {
163
- console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
163
+ const existing = routes.get(key);
164
+ const existingFiles = [existing.handler, existing.page].filter(Boolean).map((f) => f.filePath);
165
+ const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
166
+ throw new Error(`Duplicate routes for path ${path3} were defined. A route established by:
167
+ ${existingFiles}
168
+ collides with
169
+ ${currentFiles.join(" and ")}
170
+ `);
164
171
  } else {
165
172
  const index = nextRouteIndex++;
166
173
  routes.set(key, {
@@ -208,14 +215,16 @@ async function buildRoutes(walk, basePath) {
208
215
  const prevChildren = children;
209
216
  const prevCurrent = current;
210
217
  const prevIsRoot = isRoot;
211
- if (name.charCodeAt(0) === 95 || name.charCodeAt(0) === 40 && name.charCodeAt(name.length - 1) === 41 || name.toLowerCase() === "index") {
218
+ if (name.charCodeAt(0) === 95) {
212
219
  } else {
213
220
  if (name.charCodeAt(0) === 36) {
214
221
  if (name.charCodeAt(1) === 36) {
215
- paramStack.push({
216
- name: name.slice(2) || "rest",
217
- index: -1
218
- });
222
+ if (name.length > 2) {
223
+ paramStack.push({
224
+ name: name.slice(2),
225
+ index: -1
226
+ });
227
+ }
219
228
  } else if (name.length > 1) {
220
229
  paramStack.push({
221
230
  name: name.slice(1),
@@ -534,7 +543,7 @@ function renderRouteEntry(route) {
534
543
  );
535
544
  }
536
545
  if (middleware.length) {
537
- const names = middleware.map((m) => `mware$${m.id}`);
546
+ const names = middleware.map((m) => `mware${m.id}`);
538
547
  imports.writeLines(
539
548
  `import { ${names.join(
540
549
  ", "
@@ -545,9 +554,9 @@ function renderRouteEntry(route) {
545
554
  writer.writeLines("");
546
555
  const names = [];
547
556
  for (const verb of handler.verbs) {
548
- const name = verb === "delete" ? "del" : verb;
549
- names.push(name);
550
- writer.writeLines(`const handler$${name} = normalize(${name});`);
557
+ const importName = verb.toUpperCase();
558
+ names.push(importName);
559
+ writer.writeLines(`const ${verb}Handler = normalize(${importName});`);
551
560
  }
552
561
  imports.writeLines(
553
562
  `import { ${names.join(", ")} } from './${handler.importPath}';`
@@ -560,7 +569,7 @@ function renderRouteEntry(route) {
560
569
  }
561
570
  if (meta) {
562
571
  imports.writeLines(
563
- `export { default as meta$${index} } from './${meta.importPath}';`
572
+ `export { default as meta${index} } from './${meta.importPath}';`
564
573
  );
565
574
  }
566
575
  for (const verb of verbs) {
@@ -591,14 +600,19 @@ function writeRouteEntryHandler(writer, route, verb) {
591
600
  let nextName;
592
601
  let currentName;
593
602
  let hasBody = false;
594
- writer.writeLines("").writeBlockStart(
595
- `export async function ${verb}$${index}(context, buildInput) {`
596
- );
603
+ writer.writeLines("");
604
+ if (page) {
605
+ writer.writeBlockStart(
606
+ `export async function ${verb}${index}(context, buildInput) {`
607
+ );
608
+ } else {
609
+ writer.writeBlockStart(`export async function ${verb}${index}(context) {`);
610
+ }
597
611
  const continuations = writer.branch("cont");
598
612
  if (page && verb === "get") {
599
613
  currentName = "__page";
600
614
  if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
601
- const name = `handler$${verb}`;
615
+ const name = `${verb}Handler`;
602
616
  writePageResponse(continuations, currentName);
603
617
  if (len) {
604
618
  nextName = currentName;
@@ -616,7 +630,7 @@ function writeRouteEntryHandler(writer, route, verb) {
616
630
  hasBody = true;
617
631
  }
618
632
  } else if (handler) {
619
- const name = `handler$${verb}`;
633
+ const name = `${verb}Handler`;
620
634
  currentName = `__${name}`;
621
635
  nextName = "noContent";
622
636
  if (len) {
@@ -632,7 +646,7 @@ function writeRouteEntryHandler(writer, route, verb) {
632
646
  let i = len;
633
647
  while (i--) {
634
648
  const { id } = middleware[i];
635
- const name = `mware$${id}`;
649
+ const name = `mware${id}`;
636
650
  nextName = currentName;
637
651
  currentName = i ? `__${name}` : "";
638
652
  writeMiddleware(continuations, name, nextName, currentName);
@@ -648,12 +662,12 @@ function renderRouter(routes, options = {
648
662
  writer.writeLines(`// @marko/run/router`);
649
663
  const imports = writer.branch("imports");
650
664
  imports.writeLines(
651
- `import { RequestNotHandled, RequestNotMatched, createInput } from 'virtual:marko-run/internal';`
665
+ `import { NotHandled, NotMatched, createInput } from 'virtual:marko-run/internal';`
652
666
  );
653
667
  for (const route of routes.list) {
654
668
  const verbs = getVerbs(route);
655
- const names = verbs.map((verb) => `${verb}$${route.index}`);
656
- route.meta && names.push(`meta$${route.index}`);
669
+ const names = verbs.map((verb) => `${verb}${route.index}`);
670
+ route.meta && names.push(`meta${route.index}`);
657
671
  imports.writeLines(
658
672
  `import { ${names.join(
659
673
  ", "
@@ -662,10 +676,16 @@ function renderRouter(routes, options = {
662
676
  }
663
677
  for (const { key } of Object.values(routes.special)) {
664
678
  imports.writeLines(
665
- `import page$${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
679
+ `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
666
680
  );
667
681
  }
668
- writer.writeLines(``).writeBlockStart(`function findRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
682
+ writer.writeLines(``).writeBlockStart(`export function match(method, pathname) {`).writeLines(
683
+ `if (!pathname) {
684
+ pathname = '/';
685
+ } else if (pathname.charAt(0) !== '/') {
686
+ pathname = '/' + pathname;
687
+ }`
688
+ ).writeBlockStart(`switch (method.toLowerCase()) {`);
669
689
  for (const verb of httpVerbs) {
670
690
  const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
671
691
  if (filteredRoutes.length) {
@@ -677,18 +697,14 @@ function renderRouter(routes, options = {
677
697
  }
678
698
  writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
679
699
  writer.write(`
680
- export function matchRoute(method, pathname) {
681
- if (!pathname) {
682
- pathname = '/';
683
- } else if (pathname.charAt(0) !== '/') {
684
- pathname = '/' + pathname;
685
- }
686
- return findRoute(method, pathname);
687
- }
688
-
689
- export async function invokeRoute(route, context) {
700
+ export async function invoke(route, request, platform, url = new URL(request.url)) {
701
+ const context = {
702
+ url,
703
+ request,
704
+ platform
705
+ };
706
+ const buildInput = createInput(context);
690
707
  try {
691
- const buildInput = createInput(context);
692
708
  if (route) {
693
709
  context.params = route.params;
694
710
  context.meta = route.meta;
@@ -696,9 +712,9 @@ export async function invokeRoute(route, context) {
696
712
  const response = await route.handler(context, buildInput);
697
713
  if (response) return response;
698
714
  } catch (error) {
699
- if (error === RequestNotHandled) {
715
+ if (error === NotHandled) {
700
716
  return;
701
- } else if (error !== RequestNotMatched) {
717
+ } else if (error !== NotMatched) {
702
718
  throw error;
703
719
  }
704
720
  }
@@ -710,7 +726,7 @@ export async function invokeRoute(route, context) {
710
726
  context.meta = {};
711
727
  }
712
728
  if (context.request.headers.get('Accept')?.includes('text/html')) {
713
- return new Response(page$404.stream(buildInput()), {
729
+ return new Response(page404.stream(buildInput()), {
714
730
  status: 404,
715
731
  headers: { "content-type": "text/html;charset=UTF-8" },
716
732
  });
@@ -726,7 +742,7 @@ export async function invokeRoute(route, context) {
726
742
  writer.writeBlockStart(
727
743
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
728
744
  ).writeBlock(
729
- `return new Response(page$500.stream(buildInput({ error })), {`,
745
+ `return new Response(page500.stream(buildInput({ error })), {`,
730
746
  [
731
747
  `status: 500,`,
732
748
  `headers: { "content-type": "text/html;charset=UTF-8" },`
@@ -735,9 +751,9 @@ export async function invokeRoute(route, context) {
735
751
  ).writeBlockEnd("}");
736
752
  }
737
753
  writer.writeLines(`throw error;`).writeBlockEnd("}").writeBlockEnd("}").write(`
738
- export async function router(context) {
754
+ export async function fetch(request, platform) {
739
755
  try {
740
- const { url, method } = context;
756
+ const url = new URL(request.url);
741
757
  let { pathname } = url;`);
742
758
  switch (options.trailingSlashes) {
743
759
  case "RedirectWithout":
@@ -769,8 +785,8 @@ export async function router(context) {
769
785
  }
770
786
  writer.write(`
771
787
 
772
- const route = matchRoute(method, pathname);
773
- return await invokeRoute(route, context);
788
+ const route = match(request.method, pathname);
789
+ return await invoke(route, request, platform, url);
774
790
  } catch (error) {
775
791
  const message = import.meta.env.DEV
776
792
  ? \`Internal Server Error (\${error.message})\`
@@ -948,9 +964,9 @@ function renderParamsInfoType(params) {
948
964
  }
949
965
  function renderMatch(verb, route, pathIndex) {
950
966
  var _a;
951
- const handler = `${verb}$${route.index}`;
967
+ const handler = `${verb}${route.index}`;
952
968
  const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
953
- const meta = route.meta ? `meta$${route.index}` : "{}";
969
+ const meta = route.meta ? `meta${route.index}` : "{}";
954
970
  return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
955
971
  }
956
972
  function renderMiddleware(middleware) {
@@ -962,9 +978,9 @@ function renderMiddleware(middleware) {
962
978
  imports.writeLines(`import { normalize } from 'virtual:marko-run/internal';`);
963
979
  writer.writeLines("");
964
980
  for (const { id, importPath } of middleware) {
965
- const importName = `mware${id}`;
981
+ const importName = `middleware${id}`;
966
982
  imports.writeLines(`import ${importName} from './${importPath}';`);
967
- writer.writeLines(`export const mware$${id} = normalize(${importName});`);
983
+ writer.writeLines(`export const mware${id} = normalize(${importName});`);
968
984
  }
969
985
  imports.join();
970
986
  return writer.end();
@@ -979,7 +995,7 @@ function stripTsExtension(path3) {
979
995
  }
980
996
  return path3;
981
997
  }
982
- function renderRouteTypeInfo(routes, pathPrefix = ".") {
998
+ function renderRouteTypeInfo(routes, pathPrefix = ".", adapterTypes = "") {
983
999
  var _a, _b;
984
1000
  const writer = createStringWriter();
985
1001
  writer.writeLines(
@@ -987,8 +1003,10 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
987
1003
  WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
988
1004
  Do NOT manually edit this file or your changes will be lost.
989
1005
  */
990
- `,
991
- `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";
1006
+ `,
1007
+ `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";`,
1008
+ adapterTypes,
1009
+ `
992
1010
 
993
1011
  declare global {
994
1012
  namespace MarkoRun {`
@@ -1058,7 +1076,7 @@ declare module '${pathPrefix}/${page.relativePath}' {
1058
1076
 
1059
1077
  namespace MarkoRun {
1060
1078
  type CurrentRoute = ${routeType};
1061
- type CurrentContext = RouteContext<CurrentRoute>;
1079
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1062
1080
  }
1063
1081
  }`);
1064
1082
  }
@@ -1123,7 +1141,7 @@ declare module '${pathPrefix}/${file.relativePath}' {
1123
1141
 
1124
1142
  namespace MarkoRun {
1125
1143
  type CurrentRoute = ${routeTypes.join(" | ")};
1126
- type CurrentContext = RouteContext<CurrentRoute>;
1144
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1127
1145
  }
1128
1146
  }`);
1129
1147
  }
@@ -1141,7 +1159,7 @@ declare module '${pathPrefix}/${route.page.relativePath}' {
1141
1159
 
1142
1160
  namespace MarkoRun {
1143
1161
  type CurrentRoute = Route;
1144
- type CurrentContext = RouteContext<CurrentRoute>;
1162
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1145
1163
  }
1146
1164
  }`);
1147
1165
  }
@@ -1154,7 +1172,7 @@ function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
1154
1172
  declare module '${pathPrefix}/${stripTsExtension(path3)}' {
1155
1173
  namespace MarkoRun {
1156
1174
  type CurrentRoute = ${routeType};
1157
- type CurrentContext = RouteContext<CurrentRoute>;
1175
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1158
1176
  type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
1159
1177
  function route(handler: Handler): typeof handler;
1160
1178
  function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
@@ -1385,7 +1403,7 @@ function markoServe(opts = {}) {
1385
1403
  ))) {
1386
1404
  const filepath = import_path2.default.join(typesDir, "routes.d.ts");
1387
1405
  const adapterTypeInfo = (adapter == null ? void 0 : adapter.writeTypeInfo) && await (adapter == null ? void 0 : adapter.writeTypeInfo());
1388
- const data = renderRouteTypeInfo(routes, import_path2.default.relative(typesDir, routesDir)) + adapterTypeInfo;
1406
+ const data = renderRouteTypeInfo(routes, import_path2.default.relative(typesDir, routesDir), adapterTypeInfo);
1389
1407
  if (data !== typesFile || !import_fs2.default.existsSync(filepath)) {
1390
1408
  await ensureDir(typesDir);
1391
1409
  await import_fs2.default.promises.writeFile(filepath, typesFile = data);
@@ -1652,8 +1670,8 @@ async function getVerbsFromFileBuild(context, filePath) {
1652
1670
  if (result) {
1653
1671
  const exportIds = getExportIdentifiers(result.ast);
1654
1672
  for (const id of exportIds) {
1655
- const verb = id === "del" ? "delete" : id;
1656
- if (httpVerbs.includes(verb)) {
1673
+ const verb = id.toLowerCase();
1674
+ if (id === verb.toUpperCase() && httpVerbs.includes(verb)) {
1657
1675
  verbs.push(verb);
1658
1676
  }
1659
1677
  }
@@ -1664,12 +1682,19 @@ async function getVerbsFromFileDev(devServer, filePath) {
1664
1682
  const verbs = [];
1665
1683
  const result = await devServer.transformRequest(filePath, { ssr: true });
1666
1684
  if (result && result.code) {
1667
- const verbMatchReg = /__vite_ssr_exports__,\s+["'](get|post|put|del)["']/g;
1685
+ const verbMatchReg = /__vite_ssr_exports__,\s+["'](GET|POST|PUT|DELETE)["']/gi;
1668
1686
  let match = verbMatchReg.exec(result.code);
1669
1687
  while (match) {
1670
- const verb = match[1] === "del" ? "delete" : match[1];
1688
+ const id = match[1];
1689
+ const verb = id.toLowerCase();
1671
1690
  if (httpVerbs.includes(verb)) {
1672
- verbs.push(verb);
1691
+ if (id === verb.toUpperCase()) {
1692
+ verbs.push(verb);
1693
+ } else {
1694
+ console.warn(
1695
+ `Found export '${id}' in handler ${filePath} which is close to '${verb.toUpperCase()}'. Exported handlers need to be uppercase: GET, POST, PUT or DELETE.`
1696
+ );
1697
+ }
1673
1698
  }
1674
1699
  match = verbMatchReg.exec(result.code);
1675
1700
  }