@marko/run 0.1.6 → 0.1.8

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.
package/README.md CHANGED
@@ -481,9 +481,25 @@ express()
481
481
 
482
482
  **`MarkoRun.Handler`** - Type that represents a handler function to be exported by a +handler or +middleware file
483
483
 
484
- **`MarkoRun.CurrentRoute`** - Type of the route's params and metadata
484
+ **`MarkoRun.Route`** - Type of the route's params and metadata
485
485
 
486
- **`MarkoRun.CurrentContext`** - Type of the request context object in a handler and `out.global` in your Marko files
486
+ **`MarkoRun.Context`** - Type of the request context object in a handler and `$global` in your Marko files. This type can be extended using TypeScript's module and interface merging by declaring a `Context` interface on the `@marko/run` module within your applcation code
487
+ ```ts
488
+ declare module "@marko/run" {
489
+ interface Context {
490
+ customPropery: MyCustomThing // will be globally defined on MarkoRun.Context
491
+ }
492
+ }
493
+ ```
494
+
495
+ **`MarkoRun.Platform`** - Type of the platform object provided by the adapter in use. This interface can be extended in that same way as `Context` (see above) by declaring a `Platform` interface:
496
+ ```ts
497
+ declare module "@marko/run" {
498
+ interface Platform {
499
+ customPropery: MyCustomThing // will be globally defined on MarkoRun.Platform
500
+ }
501
+ }
502
+ ```
487
503
 
488
504
 
489
505
  ### Generated Types
@@ -493,13 +509,13 @@ If a [TSConfig](https://www.typescriptlang.org/tsconfig) file is discovered in t
493
509
  These types are replaced with more specific versions per routable file:
494
510
 
495
511
  **`MarkoRun.Handler`**
496
- - Overrides context with specific MarkoRun.CurrentContext
512
+ - Overrides context with specific MarkoRun.Context
497
513
 
498
- **`MarkoRun.CurrentRoute`**
514
+ **`MarkoRun.Route`**
499
515
  - Adds specific parameters and meta types
500
516
  - In middleware and layouts which are used in many routes, this type will be a union of all possible routes that the file will see
501
517
 
502
- **`MarkoRun.CurrentContext`**
518
+ **`MarkoRun.Context`**
503
519
  - In middleware and layouts which are used in many routes, this type will be a union of all possible routes that the file will see.
504
520
  - When an adapter is used, it can provide types for the platform
505
521
 
@@ -1,15 +1,10 @@
1
- import type { HandlerLike, ParamsObject, Route as AnyRoute, Context as AnyContext, RuntimeModule } from "./types";
1
+ import { NotHandled, NotMatched } from "./namespace";
2
+ import { GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform, HandlerTypeFn, RuntimeModule, AnyRoute, AnyContext, AnyHandler } from "./types";
2
3
  declare global {
3
4
  var __marko_run__: RuntimeModule;
4
5
  namespace MarkoRun {
5
- const NotHandled: unique symbol;
6
- const NotMatched: unique symbol;
7
- interface Route extends AnyRoute {
8
- }
9
- interface Context extends AnyContext {
10
- }
11
- type Handler<Params extends ParamsObject = {}, Meta = unknown> = HandlerLike<AnyRoute<Params, Meta, string>>;
12
- function route<Params extends ParamsObject = {}, Meta = unknown>(handler: Handler<Params, Meta>): typeof handler;
6
+ export const route: HandlerTypeFn;
7
+ export { GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform, NotHandled, NotMatched, AnyRoute as Route, AnyContext as Context, AnyHandler as Handler, };
13
8
  }
14
9
  }
15
- export type { Context, ContextExtensions, Fetch, HandlerLike, InputObject, Invoke, Match, NextFunction, ParamsObject, PathTemplate, Route, RouteHandler, RouteWithHandler, RuntimeModule, ValidateHref, ValidatePath, } from "./types";
10
+ export type { AppData, Context, DefineApp, Fetch, HandlerTypeFn, HandlerLike, InputObject, Invoke, Match, MultiRouteContext, NextFunction, ParamsObject, Platform, Route, Routes, RouteHandler, RouteWithHandler, RuntimeModule, } from "./types";
@@ -1,9 +1,9 @@
1
- import type { InputObject, NextFunction, Route, Context, RouteHandler } from "./types";
1
+ import type { InputObject, NextFunction, AnyRoute, Context, MultiRouteContext, RouteHandler, Platform } from "./types";
2
2
  export declare function pageResponse(template: any, input: Record<PropertyKey, unknown>): Response;
3
3
  export declare const NotHandled: typeof MarkoRun.NotHandled;
4
4
  export declare const NotMatched: typeof MarkoRun.NotMatched;
5
- export declare function createContext<Platform, TRoute extends Route>(route: TRoute | undefined, request: Request, platform: Platform, url?: URL): [Context, (data?: InputObject) => InputObject];
6
- export declare function call(handler: RouteHandler<Route>, next: NextFunction, context: Context): Promise<Response>;
5
+ export declare function createContext<TRoute extends AnyRoute>(route: TRoute | undefined, request: Request, platform: Platform, url?: URL): [Context<TRoute>, (data?: InputObject) => InputObject];
6
+ export declare function call<TRoute extends AnyRoute>(handler: RouteHandler<TRoute>, next: NextFunction, context: MultiRouteContext<TRoute>): Promise<Response>;
7
7
  export declare function compose(handlers: RouteHandler[]): RouteHandler;
8
8
  export declare function normalize(obj: RouteHandler | RouteHandler[] | Promise<RouteHandler | RouteHandler[]>): RouteHandler;
9
9
  export declare function noContent(): Response;
@@ -0,0 +1,3 @@
1
+ export declare const NotHandled: unique symbol;
2
+ export declare const NotMatched: unique symbol;
3
+ export type { GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "./types";
@@ -1,3 +1,3 @@
1
- export declare const fetch: <Platform = unknown>(request: Request, platform: Platform) => Promise<void | Response>;
2
- export declare const match: (method: string, pathname: string) => import("./types").RouteWithHandler<{}, unknown, string> | null;
3
- export declare const invoke: <Platform = unknown>(route: import("./types").RouteWithHandler<{}, unknown, string> | null, request: Request, platform: Platform) => Promise<void | Response>;
1
+ export declare const fetch: <TPlatform extends import("./types").Platform = import("./types").Platform>(request: Request, platform: TPlatform) => Promise<void | Response>;
2
+ export declare const match: import("./types").Match;
3
+ export declare const invoke: <TPlatform extends import("./types").Platform = import("./types").Platform>(route: import("./types").RouteWithHandler<import("./types").ParamsObject, unknown, string> | null, request: Request, platform: TPlatform) => Promise<void | Response>;
@@ -1,8 +1,9 @@
1
1
  type Awaitable<T> = Promise<T> | T;
2
2
  type OneOrMany<T> = T | T[];
3
- export interface ContextExtensions {
3
+ type NoParams = {};
4
+ export interface Platform {
4
5
  }
5
- export type Context<Platform = unknown, TRoute extends Route = Route> = ContextExtensions & {
6
+ export interface Context<TRoute extends AnyRoute = AnyRoute> {
6
7
  readonly url: URL;
7
8
  readonly request: Request;
8
9
  readonly route: TRoute["path"];
@@ -10,34 +11,87 @@ export type Context<Platform = unknown, TRoute extends Route = Route> = ContextE
10
11
  readonly meta: TRoute["meta"];
11
12
  readonly platform: Platform;
12
13
  readonly serializedGlobals: Record<string, boolean>;
13
- };
14
+ }
15
+ export type MultiRouteContext<TRoute extends AnyRoute> = TRoute extends any ? Context<TRoute> : never;
14
16
  export type ParamsObject = Record<string, string>;
15
17
  export type InputObject = Record<PropertyKey, any>;
16
18
  export type NextFunction = () => Awaitable<Response>;
17
- export type HandlerLike<TRoute extends Route = Route> = Awaitable<OneOrMany<RouteHandler<TRoute>>>;
18
- export type RouteHandler<TRoute extends Route = Route> = (context: Context<unknown, TRoute>, next: NextFunction) => Awaitable<Response | null | void>;
19
- export interface Route<Params extends ParamsObject = {}, Meta = unknown, Path extends string = string> {
19
+ export type HandlerLike<TRoute extends AnyRoute = AnyRoute> = Awaitable<OneOrMany<RouteHandler<TRoute>>>;
20
+ export type RouteHandler<TRoute extends AnyRoute = AnyRoute> = (context: MultiRouteContext<TRoute>, next: NextFunction) => Awaitable<Response | null | void>;
21
+ export interface Route<Params extends ParamsObject, Meta, Path extends string> {
20
22
  path: Path;
21
23
  params: Params;
22
24
  meta: Meta;
23
25
  }
24
- export interface RouteWithHandler<Params extends ParamsObject = {}, Meta = unknown, Path extends string = string> extends Route<Params, Meta, Path> {
26
+ type DefineRoutes<T extends Record<string, {
27
+ meta?: unknown;
28
+ }>> = {
29
+ [K in keyof T]: K extends string ? T[K] extends {
30
+ meta: infer Meta;
31
+ } ? Route<PathParams<K>, Meta, K> : Route<PathParams<K>, unknown, K> : never;
32
+ };
33
+ type DefinePaths<T extends Record<string, {
34
+ verb: unknown;
35
+ }>, Verb extends "get" | "post"> = {
36
+ [K in keyof T]: K extends string ? T[K] extends {
37
+ verb: infer V;
38
+ } ? V extends Verb ? ConvertPath<K> : never : never : never;
39
+ }[keyof T];
40
+ export type DefineApp<T extends {
41
+ routes: Record<string, {
42
+ verb: "get" | "post";
43
+ meta?: unknown;
44
+ }>;
45
+ }> = {
46
+ routes: DefineRoutes<T["routes"]>;
47
+ getPaths: DefinePaths<T["routes"], "get">;
48
+ postPaths: DefinePaths<T["routes"], "post">;
49
+ };
50
+ export interface RouteWithHandler<Params extends ParamsObject = ParamsObject, Meta = unknown, Path extends string = string> extends Route<Params, Meta, Path> {
25
51
  handler: RouteHandler<this>;
26
52
  }
27
- export type Fetch<Platform = unknown> = (request: Request, platform: Platform) => Promise<Response | void>;
53
+ export type Fetch<TPlatform extends Platform = Platform> = (request: Request, platform: TPlatform) => Promise<Response | void>;
28
54
  export type Match = (method: string, pathname: string) => RouteWithHandler | null;
29
- export type Invoke = <Platform = unknown>(route: RouteWithHandler | null, request: Request, platform: Platform) => Promise<Response | void>;
55
+ export type Invoke<TPlatform extends Platform = Platform> = (route: RouteWithHandler | null, request: Request, platform: TPlatform) => Promise<Response | void>;
30
56
  export interface RuntimeModule {
31
- fetch: <Platform = unknown>(request: Request, platform: Platform) => Promise<Response | void>;
32
- match: (method: string, pathname: string) => RouteWithHandler | null;
33
- invoke: <Platform = unknown>(route: RouteWithHandler | null, request: Request, platform: Platform) => Promise<Response | void>;
57
+ fetch<TPlatform extends Platform = Platform>(...args: Parameters<Fetch<TPlatform>>): ReturnType<Fetch<TPlatform>>;
58
+ match: Match;
59
+ invoke<TPlatform extends Platform = Platform>(...args: Parameters<Invoke<TPlatform>>): ReturnType<Invoke<TPlatform>>;
34
60
  }
35
61
  type Member<T, U> = T extends T ? (U extends T ? T : never) : never;
62
+ type PathParamKeys<Path extends string> = Path extends `${infer _}:${infer Param}/${infer Rest}` ? [Param, ...PathParamKeys<Rest>] : Path extends `${infer _}:${infer Param}*` ? [Param] : Path extends `${infer _}:${infer Param}` ? [Param] : [];
63
+ type PathParams<Path extends string, Keys extends string[] = PathParamKeys<Path>> = 0 extends Keys["length"] ? NoParams : {
64
+ [K in Keys[number]]: string;
65
+ };
36
66
  type Segments<T extends string, Acc extends string[] = []> = T extends "" ? Acc : T extends `${infer Left}/${infer Rest}` ? Segments<Rest, [...Acc, Left]> : [...Acc, T];
37
67
  type GTE<A extends any[], B extends any[]> = A["length"] extends B["length"] ? 1 : A extends [infer _Ha, ...infer Ta] ? B extends [infer _Hb, ...infer Tb] ? GTE<Ta, Tb> : 1 : 0;
38
68
  type MatchSegments<A extends string, B extends string> = A extends `${infer P}/${string}*` ? 1 extends GTE<Segments<B>, Segments<P>> ? `${P}/${string}` : never : Segments<B>["length"] extends Segments<A>["length"] ? A : never;
39
69
  type PathPattern<T extends string> = T extends `${infer Left}/\${${string}}/${infer Rest}` ? PathPattern<`${Left}/${string}/${Rest}`> : T extends `${infer Left}/\${...${string}}` ? PathPattern<`${Left}/${string}*`> : T extends `${infer Left}/\${${string}}` ? PathPattern<`${Left}/${string}`> : T;
40
- export type PathTemplate<Path extends string> = Path extends `${infer Left}/\${${string}}/${infer Rest}` ? PathTemplate<`${Left}/${string}/${Rest}`> : Path extends `${infer Left}/\${${string}}` ? PathTemplate<`${Left}/${string}`> : Path;
41
- export type ValidatePath<Paths extends string, Path extends string> = Paths | (Path extends `/${string}` ? MatchSegments<Member<PathPattern<Paths>, Path>, Path> : Path);
42
- export type ValidateHref<Paths extends string, Href extends string> = Href extends `${infer P}#${infer H}?${infer Q}` ? `${ValidatePath<Paths, P>}#${H}?${Q}` : Href extends `${infer P}?${infer Q}` ? `${ValidatePath<Paths, P>}?${Q}` : Href extends `${infer P}#${infer H}` ? `${ValidatePath<Paths, P>}#${H}` : ValidatePath<Paths, Href>;
70
+ export type ConvertPath<Path extends string> = Path extends `${infer Left}/:${infer Param}/${infer Rest}` ? ConvertPath<`${Left}/\${${Param}}/${Rest}`> : Path extends `${infer Left}/:${infer Param}*` ? `${Left}/\${${Param}...}` : Path extends `${infer Left}/:${infer Param}` ? `${Left}/\${${Param}}` : Path;
71
+ type ValidatePath<Paths extends string, Path extends string> = Paths | (Path extends `/${string}` ? MatchSegments<Member<PathPattern<Paths>, Path>, Path> : Path);
72
+ type ValidateHref<Paths extends string, Href extends string> = Href extends `${infer P}#${infer H}?${infer Q}` ? `${ValidatePath<Paths, P>}#${H}?${Q}` : Href extends `${infer P}?${infer Q}` ? `${ValidatePath<Paths, P>}?${Q}` : Href extends `${infer P}#${infer H}` ? `${ValidatePath<Paths, P>}#${H}` : ValidatePath<Paths, Href>;
73
+ export interface AppData {
74
+ }
75
+ type HasAppData = AppData extends {
76
+ routes: any;
77
+ } ? 1 : 0;
78
+ type AnyParams = 0 extends HasAppData ? ParamsObject : never;
79
+ type AnyMeta = 0 extends HasAppData ? unknown : never;
80
+ export type Routes = AppData extends {
81
+ routes: infer T;
82
+ } ? T : Record<string, Route<ParamsObject, unknown, string>>;
83
+ export type AnyRoute = Routes[keyof Routes];
84
+ export type AnyContext = MultiRouteContext<AnyRoute>;
85
+ export type AnyHandler<Params extends AnyParams = AnyParams, Meta extends AnyMeta = AnyMeta> = 0 extends HasAppData ? HandlerLike<Route<Params, Meta, string>> : HandlerLike<AnyRoute>;
86
+ export type HandlerTypeFn<THandler extends HandlerLike = AnyHandler> = 0 extends HasAppData ? <Params extends ParamsObject = ParamsObject, Meta = unknown>(handler: HandlerLike<Route<Params, Meta, string>>) => HandlerLike<Route<Params, Meta, string>> : (handler: THandler) => THandler;
87
+ export type GetPaths = AppData extends {
88
+ getPaths: infer T;
89
+ } ? T : string;
90
+ export type PostPaths = AppData extends {
91
+ postPaths: infer T;
92
+ } ? T : string;
93
+ export type GetablePath<T extends string> = ValidatePath<GetPaths, T>;
94
+ export type GetableHref<T extends string> = ValidateHref<GetPaths, T>;
95
+ export type PostablePath<T extends string> = ValidatePath<PostPaths, T>;
96
+ export type PostableHref<T extends string> = ValidateHref<PostPaths, T>;
43
97
  export {};
@@ -232,7 +232,7 @@ async function buildRoutes(walk, basePath) {
232
232
  });
233
233
  }
234
234
  }
235
- pathStack.push(name.toLowerCase());
235
+ pathStack.push(name);
236
236
  }
237
237
  dirStack.push(name);
238
238
  isRoot = false;
@@ -680,9 +680,11 @@ function renderRouter(routes, options = {
680
680
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
681
681
  );
682
682
  }
683
- writer.writeLines(`
683
+ writer.writeLines(
684
+ `
684
685
  globalThis.__marko_run__ = { match, fetch, invoke };
685
- `).writeBlockStart(`export function match(method, pathname) {`).writeLines(
686
+ `
687
+ ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
686
688
  `if (!pathname) {
687
689
  pathname = '/';
688
690
  } else if (pathname.charAt(0) !== '/') {
@@ -942,22 +944,13 @@ function renderParamsInfo(params, pathIndex) {
942
944
  }
943
945
  return result ? result + " }" : "{}";
944
946
  }
945
- function renderParamsInfoType(params) {
946
- if (!params.length) {
947
- return "{}";
948
- }
949
- let result = "{";
950
- for (const { name } of params) {
951
- result += ` ${wrapPropertyName(name)}: string;`;
952
- }
953
- return result + " }";
954
- }
955
947
  function renderMatch(verb, route, pathIndex) {
956
948
  var _a;
957
949
  const handler = `${verb}${route.index}`;
958
950
  const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
959
951
  const meta = route.meta ? `meta${route.index}` : "{}";
960
- return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
952
+ const path3 = pathToURLPatternString(route.path);
953
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${path3}' }`;
961
954
  }
962
955
  function renderMiddleware(middleware) {
963
956
  const writer = createStringWriter();
@@ -994,76 +987,64 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
994
987
  Do NOT manually edit this file or your changes will be lost.
995
988
  */
996
989
  `,
997
- `import type { HandlerLike, Route as AnyRoute, Context as AnyContext, ParamsObject, ValidatePath, ValidateHref } from "@marko/run";`
990
+ `import "@marko/run/namespace";`,
991
+ `import type Run from "@marko/run";`
998
992
  );
999
- let platformType = "unknown";
993
+ const headWriter = writer.branch("head");
994
+ writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
1000
995
  if (adapter && adapter.typeInfo) {
1001
- platformType = await adapter.typeInfo((data) => writer.write(data));
1002
- writer.writeLines("");
1003
- }
1004
- writer.writeLines(`
1005
- interface NoParams extends ParamsObject {}
1006
- interface NoMeta {}
996
+ const platformType = await adapter.typeInfo(
997
+ (data) => headWriter.write(data)
998
+ );
999
+ if (platformType) {
1000
+ writer.writeLines(`interface Platform extends ${platformType} {}
1007
1001
  `);
1008
- const pathsWriter = writer.branch("paths");
1009
- const routesWriter = writer.branch("types");
1010
- const serverWriter = writer.branch("server");
1002
+ }
1003
+ }
1004
+ writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
1005
+ const routesWriter = writer.branch("routes");
1006
+ writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
1007
+ headWriter.join();
1008
+ const moduleWriter = writer.branch("module");
1011
1009
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
1012
1010
  const layoutRouteTypes = /* @__PURE__ */ new Map();
1013
- const getPaths = /* @__PURE__ */ new Set();
1014
- const postPaths = /* @__PURE__ */ new Set();
1015
- writeModuleDeclaration(serverWriter, void 0, void 0, platformType);
1016
1011
  for (const route of routes.list) {
1017
- const { meta, handler, params, middleware, page, layouts } = route;
1018
- const routeType = `Route${route.index}`;
1019
- const pathType = `\`${route.path.replace(
1020
- /\/\$(\$?)([^\/]*)/,
1021
- (_, catchAll, name) => {
1022
- name = decodeURIComponent(name);
1023
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1024
- }
1025
- )}\``;
1026
- const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
1027
- let metaType = "NoMeta";
1012
+ const { meta, handler, middleware, page, layouts } = route;
1013
+ const pathType = `${pathToURLPatternString(route.path)}`;
1014
+ const routeType = `"${pathType}"`;
1015
+ let verbType = "";
1028
1016
  if (page || handler) {
1029
- const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
1030
- const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
1031
- if (isGet || isPost) {
1032
- const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
1033
- name = decodeURIComponent(name);
1034
- return catchAll ? `\${...${name}}` : `\${${name}}`;
1035
- });
1036
- const splatIndex = path3.indexOf("/${...");
1037
- if (splatIndex >= 0) {
1038
- const path22 = path3.slice(0, splatIndex) || "/";
1039
- isGet && getPaths.add(path22);
1040
- isPost && postPaths.add(path22);
1041
- }
1042
- isGet && getPaths.add(path3);
1043
- isPost && postPaths.add(path3);
1017
+ const verbs = [];
1018
+ if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
1019
+ verbs.push(`"get"`);
1020
+ }
1021
+ if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
1022
+ verbs.push(`"post"`);
1044
1023
  }
1024
+ verbType = verbs.join(" | ");
1045
1025
  }
1046
1026
  if (meta) {
1047
1027
  const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1048
- metaType = `typeof import('${path3}')`;
1028
+ let metaType = `typeof import("${path3}")`;
1049
1029
  if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1050
- metaType += `['default']`;
1030
+ metaType += `["default"]`;
1051
1031
  }
1032
+ routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
1033
+ } else {
1034
+ routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1052
1035
  }
1053
1036
  if (handler) {
1054
1037
  writeModuleDeclaration(
1055
- serverWriter,
1038
+ moduleWriter,
1056
1039
  `${pathPrefix}/${handler.relativePath}`,
1057
- routeType,
1058
- platformType
1040
+ `Run.Routes[${routeType}]`
1059
1041
  );
1060
1042
  }
1061
1043
  if (page) {
1062
1044
  writeModuleDeclaration(
1063
1045
  writer,
1064
1046
  `${pathPrefix}/${page.relativePath}`,
1065
- routeType,
1066
- platformType,
1047
+ `Run.Routes[${routeType}]`,
1067
1048
  `
1068
1049
  export interface Input {
1069
1050
  renderBody: Marko.Body;
@@ -1097,45 +1078,20 @@ interface NoMeta {}
1097
1078
  }
1098
1079
  }
1099
1080
  }
1100
- routesWriter.writeLines(
1101
- `type ${routeType} = AnyRoute<${paramsType}, ${metaType}, ${pathType}>;`
1102
- );
1103
- }
1104
- pathsWriter.write(`type Get =`);
1105
- if (getPaths.size) {
1106
- for (const path3 of getPaths) {
1107
- pathsWriter.write(`
1108
- | '${path3}'`);
1109
- }
1110
- } else {
1111
- pathsWriter.write(" never");
1112
- }
1113
- pathsWriter.writeLines(";", "");
1114
- pathsWriter.write("type Post =");
1115
- if (postPaths.size) {
1116
- for (const path3 of postPaths) {
1117
- pathsWriter.write(`
1118
- | '${path3}'`);
1119
- }
1120
- } else {
1121
- pathsWriter.write(" never");
1122
1081
  }
1123
- pathsWriter.writeLines(";", "");
1124
- pathsWriter.join();
1082
+ routesWriter.join();
1125
1083
  for (const [file, { routeTypes }] of middlewareRouteTypes) {
1126
1084
  writeModuleDeclaration(
1127
- serverWriter,
1085
+ moduleWriter,
1128
1086
  `${pathPrefix}/${file.relativePath}`,
1129
- routeTypes.join(" | "),
1130
- platformType
1087
+ `Run.Routes[${routeTypes.join(" | ")}]`
1131
1088
  );
1132
1089
  }
1133
1090
  for (const [file, { routeTypes }] of layoutRouteTypes) {
1134
1091
  writeModuleDeclaration(
1135
1092
  writer,
1136
1093
  `${pathPrefix}/${file.relativePath}`,
1137
- routeTypes.join(" | "),
1138
- platformType,
1094
+ `Run.Routes[${routeTypes.join(" | ")}]`,
1139
1095
  `
1140
1096
  export interface Input {
1141
1097
  renderBody: Marko.Body;
@@ -1146,8 +1102,7 @@ interface NoMeta {}
1146
1102
  writeModuleDeclaration(
1147
1103
  writer,
1148
1104
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
1149
- void 0,
1150
- platformType,
1105
+ "Run.Route",
1151
1106
  `
1152
1107
  export interface Input {}`
1153
1108
  );
@@ -1156,51 +1111,41 @@ interface NoMeta {}
1156
1111
  writeModuleDeclaration(
1157
1112
  writer,
1158
1113
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
1159
- void 0,
1160
- platformType,
1114
+ "globalThis.MarkoRun.Route",
1161
1115
  `
1162
1116
  export interface Input {
1163
1117
  error: unknown;
1164
1118
  }`
1165
1119
  );
1166
1120
  }
1167
- serverWriter.join();
1121
+ moduleWriter.join();
1168
1122
  return writer.end();
1169
1123
  }
1170
- function writeModuleDeclaration(writer, path3 = "global", routeType = "AnyRoute", platformType = "unknown", moduleTypes) {
1171
- writer.writeLines("");
1172
- if (path3 === "global") {
1173
- writer.write("declare global {");
1174
- } else {
1175
- writer.write(`declare module '${stripTsExtension(path3)}' {`);
1176
- }
1124
+ function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
1125
+ writer.writeLines("").write(`declare module "${stripTsExtension(path3)}" {`);
1177
1126
  if (moduleTypes) {
1178
- writer.writeLines(moduleTypes);
1127
+ writer.write(moduleTypes);
1179
1128
  }
1180
- const isMarko = path3.endsWith(".marko");
1181
- writer.write(`
1182
- namespace MarkoRun {
1183
- type GetPaths = Get;
1184
- type PostPaths = Post;
1185
- type GetablePath<T extends string> = ValidatePath<Get, T>;
1186
- type GetableHref<T extends string> = ValidateHref<Get, T>;
1187
- type PostablePath<T extends string> = ValidatePath<Post, T>;
1188
- type PostableHref<T extends string> = ValidateHref<Post, T>;
1189
- type Platform = ${platformType};`);
1190
- if (path3 !== "global") {
1129
+ if (routeType) {
1130
+ const isMarko = path3.endsWith(".marko");
1191
1131
  writer.write(`
1192
- type Route = ${routeType};
1193
- type Context = AnyContext<Platform, Route>${isMarko ? " & Marko.Global" : ""};
1194
- type Handler<_Params = Route['params'], _Meta = Route['meta']> = HandlerLike<Route>;
1195
- function route(handler: Handler): typeof handler;
1196
- function route<_Params = Route['params'], _Meta = Route['meta']>(handler: Handler): typeof handler;
1197
- const NotHandled: unique symbol;
1198
- const NotMatched: unique symbol;`);
1132
+ namespace MarkoRun {
1133
+ export * from "@marko/run/namespace";
1134
+ export type Route = ${routeType};
1135
+ export type Context = Run.MultiRouteContext<Route>${isMarko ? " & Marko.Global" : ""};
1136
+ export type Handler = Run.HandlerLike<Route>;
1137
+ export const route: Run.HandlerTypeFn<Handler>;
1138
+ }`);
1199
1139
  }
1200
1140
  writer.writeLines(`
1201
- }
1202
1141
  }`);
1203
1142
  }
1143
+ function pathToURLPatternString(path3) {
1144
+ return path3.replace(/\/\$(\$?)([^\/]*)/g, (_, catchAll, name) => {
1145
+ name = decodeURIComponent(name);
1146
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1147
+ });
1148
+ }
1204
1149
 
1205
1150
  // src/vite/utils/ast.ts
1206
1151
  var t = __toESM(require("@babel/types"), 1);
@@ -195,7 +195,7 @@ async function buildRoutes(walk, basePath) {
195
195
  });
196
196
  }
197
197
  }
198
- pathStack.push(name.toLowerCase());
198
+ pathStack.push(name);
199
199
  }
200
200
  dirStack.push(name);
201
201
  isRoot = false;
@@ -643,9 +643,11 @@ function renderRouter(routes, options = {
643
643
  `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
644
644
  );
645
645
  }
646
- writer.writeLines(`
646
+ writer.writeLines(
647
+ `
647
648
  globalThis.__marko_run__ = { match, fetch, invoke };
648
- `).writeBlockStart(`export function match(method, pathname) {`).writeLines(
649
+ `
650
+ ).writeBlockStart(`export function match(method, pathname) {`).writeLines(
649
651
  `if (!pathname) {
650
652
  pathname = '/';
651
653
  } else if (pathname.charAt(0) !== '/') {
@@ -905,22 +907,13 @@ function renderParamsInfo(params, pathIndex) {
905
907
  }
906
908
  return result ? result + " }" : "{}";
907
909
  }
908
- function renderParamsInfoType(params) {
909
- if (!params.length) {
910
- return "{}";
911
- }
912
- let result = "{";
913
- for (const { name } of params) {
914
- result += ` ${wrapPropertyName(name)}: string;`;
915
- }
916
- return result + " }";
917
- }
918
910
  function renderMatch(verb, route, pathIndex) {
919
911
  var _a;
920
912
  const handler = `${verb}${route.index}`;
921
913
  const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
922
914
  const meta = route.meta ? `meta${route.index}` : "{}";
923
- return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
915
+ const path3 = pathToURLPatternString(route.path);
916
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${path3}' }`;
924
917
  }
925
918
  function renderMiddleware(middleware) {
926
919
  const writer = createStringWriter();
@@ -957,76 +950,64 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
957
950
  Do NOT manually edit this file or your changes will be lost.
958
951
  */
959
952
  `,
960
- `import type { HandlerLike, Route as AnyRoute, Context as AnyContext, ParamsObject, ValidatePath, ValidateHref } from "@marko/run";`
953
+ `import "@marko/run/namespace";`,
954
+ `import type Run from "@marko/run";`
961
955
  );
962
- let platformType = "unknown";
956
+ const headWriter = writer.branch("head");
957
+ writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
963
958
  if (adapter && adapter.typeInfo) {
964
- platformType = await adapter.typeInfo((data) => writer.write(data));
965
- writer.writeLines("");
966
- }
967
- writer.writeLines(`
968
- interface NoParams extends ParamsObject {}
969
- interface NoMeta {}
959
+ const platformType = await adapter.typeInfo(
960
+ (data) => headWriter.write(data)
961
+ );
962
+ if (platformType) {
963
+ writer.writeLines(`interface Platform extends ${platformType} {}
970
964
  `);
971
- const pathsWriter = writer.branch("paths");
972
- const routesWriter = writer.branch("types");
973
- const serverWriter = writer.branch("server");
965
+ }
966
+ }
967
+ writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
968
+ const routesWriter = writer.branch("routes");
969
+ writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
970
+ headWriter.join();
971
+ const moduleWriter = writer.branch("module");
974
972
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
975
973
  const layoutRouteTypes = /* @__PURE__ */ new Map();
976
- const getPaths = /* @__PURE__ */ new Set();
977
- const postPaths = /* @__PURE__ */ new Set();
978
- writeModuleDeclaration(serverWriter, void 0, void 0, platformType);
979
974
  for (const route of routes.list) {
980
- const { meta, handler, params, middleware, page, layouts } = route;
981
- const routeType = `Route${route.index}`;
982
- const pathType = `\`${route.path.replace(
983
- /\/\$(\$?)([^\/]*)/,
984
- (_, catchAll, name) => {
985
- name = decodeURIComponent(name);
986
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
987
- }
988
- )}\``;
989
- const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
990
- let metaType = "NoMeta";
975
+ const { meta, handler, middleware, page, layouts } = route;
976
+ const pathType = `${pathToURLPatternString(route.path)}`;
977
+ const routeType = `"${pathType}"`;
978
+ let verbType = "";
991
979
  if (page || handler) {
992
- const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
993
- const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
994
- if (isGet || isPost) {
995
- const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
996
- name = decodeURIComponent(name);
997
- return catchAll ? `\${...${name}}` : `\${${name}}`;
998
- });
999
- const splatIndex = path3.indexOf("/${...");
1000
- if (splatIndex >= 0) {
1001
- const path22 = path3.slice(0, splatIndex) || "/";
1002
- isGet && getPaths.add(path22);
1003
- isPost && postPaths.add(path22);
1004
- }
1005
- isGet && getPaths.add(path3);
1006
- isPost && postPaths.add(path3);
980
+ const verbs = [];
981
+ if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
982
+ verbs.push(`"get"`);
983
+ }
984
+ if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
985
+ verbs.push(`"post"`);
1007
986
  }
987
+ verbType = verbs.join(" | ");
1008
988
  }
1009
989
  if (meta) {
1010
990
  const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1011
- metaType = `typeof import('${path3}')`;
991
+ let metaType = `typeof import("${path3}")`;
1012
992
  if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1013
- metaType += `['default']`;
993
+ metaType += `["default"]`;
1014
994
  }
995
+ routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
996
+ } else {
997
+ routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1015
998
  }
1016
999
  if (handler) {
1017
1000
  writeModuleDeclaration(
1018
- serverWriter,
1001
+ moduleWriter,
1019
1002
  `${pathPrefix}/${handler.relativePath}`,
1020
- routeType,
1021
- platformType
1003
+ `Run.Routes[${routeType}]`
1022
1004
  );
1023
1005
  }
1024
1006
  if (page) {
1025
1007
  writeModuleDeclaration(
1026
1008
  writer,
1027
1009
  `${pathPrefix}/${page.relativePath}`,
1028
- routeType,
1029
- platformType,
1010
+ `Run.Routes[${routeType}]`,
1030
1011
  `
1031
1012
  export interface Input {
1032
1013
  renderBody: Marko.Body;
@@ -1060,45 +1041,20 @@ interface NoMeta {}
1060
1041
  }
1061
1042
  }
1062
1043
  }
1063
- routesWriter.writeLines(
1064
- `type ${routeType} = AnyRoute<${paramsType}, ${metaType}, ${pathType}>;`
1065
- );
1066
- }
1067
- pathsWriter.write(`type Get =`);
1068
- if (getPaths.size) {
1069
- for (const path3 of getPaths) {
1070
- pathsWriter.write(`
1071
- | '${path3}'`);
1072
- }
1073
- } else {
1074
- pathsWriter.write(" never");
1075
- }
1076
- pathsWriter.writeLines(";", "");
1077
- pathsWriter.write("type Post =");
1078
- if (postPaths.size) {
1079
- for (const path3 of postPaths) {
1080
- pathsWriter.write(`
1081
- | '${path3}'`);
1082
- }
1083
- } else {
1084
- pathsWriter.write(" never");
1085
1044
  }
1086
- pathsWriter.writeLines(";", "");
1087
- pathsWriter.join();
1045
+ routesWriter.join();
1088
1046
  for (const [file, { routeTypes }] of middlewareRouteTypes) {
1089
1047
  writeModuleDeclaration(
1090
- serverWriter,
1048
+ moduleWriter,
1091
1049
  `${pathPrefix}/${file.relativePath}`,
1092
- routeTypes.join(" | "),
1093
- platformType
1050
+ `Run.Routes[${routeTypes.join(" | ")}]`
1094
1051
  );
1095
1052
  }
1096
1053
  for (const [file, { routeTypes }] of layoutRouteTypes) {
1097
1054
  writeModuleDeclaration(
1098
1055
  writer,
1099
1056
  `${pathPrefix}/${file.relativePath}`,
1100
- routeTypes.join(" | "),
1101
- platformType,
1057
+ `Run.Routes[${routeTypes.join(" | ")}]`,
1102
1058
  `
1103
1059
  export interface Input {
1104
1060
  renderBody: Marko.Body;
@@ -1109,8 +1065,7 @@ interface NoMeta {}
1109
1065
  writeModuleDeclaration(
1110
1066
  writer,
1111
1067
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
1112
- void 0,
1113
- platformType,
1068
+ "Run.Route",
1114
1069
  `
1115
1070
  export interface Input {}`
1116
1071
  );
@@ -1119,51 +1074,41 @@ interface NoMeta {}
1119
1074
  writeModuleDeclaration(
1120
1075
  writer,
1121
1076
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
1122
- void 0,
1123
- platformType,
1077
+ "globalThis.MarkoRun.Route",
1124
1078
  `
1125
1079
  export interface Input {
1126
1080
  error: unknown;
1127
1081
  }`
1128
1082
  );
1129
1083
  }
1130
- serverWriter.join();
1084
+ moduleWriter.join();
1131
1085
  return writer.end();
1132
1086
  }
1133
- function writeModuleDeclaration(writer, path3 = "global", routeType = "AnyRoute", platformType = "unknown", moduleTypes) {
1134
- writer.writeLines("");
1135
- if (path3 === "global") {
1136
- writer.write("declare global {");
1137
- } else {
1138
- writer.write(`declare module '${stripTsExtension(path3)}' {`);
1139
- }
1087
+ function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
1088
+ writer.writeLines("").write(`declare module "${stripTsExtension(path3)}" {`);
1140
1089
  if (moduleTypes) {
1141
- writer.writeLines(moduleTypes);
1090
+ writer.write(moduleTypes);
1142
1091
  }
1143
- const isMarko = path3.endsWith(".marko");
1144
- writer.write(`
1145
- namespace MarkoRun {
1146
- type GetPaths = Get;
1147
- type PostPaths = Post;
1148
- type GetablePath<T extends string> = ValidatePath<Get, T>;
1149
- type GetableHref<T extends string> = ValidateHref<Get, T>;
1150
- type PostablePath<T extends string> = ValidatePath<Post, T>;
1151
- type PostableHref<T extends string> = ValidateHref<Post, T>;
1152
- type Platform = ${platformType};`);
1153
- if (path3 !== "global") {
1092
+ if (routeType) {
1093
+ const isMarko = path3.endsWith(".marko");
1154
1094
  writer.write(`
1155
- type Route = ${routeType};
1156
- type Context = AnyContext<Platform, Route>${isMarko ? " & Marko.Global" : ""};
1157
- type Handler<_Params = Route['params'], _Meta = Route['meta']> = HandlerLike<Route>;
1158
- function route(handler: Handler): typeof handler;
1159
- function route<_Params = Route['params'], _Meta = Route['meta']>(handler: Handler): typeof handler;
1160
- const NotHandled: unique symbol;
1161
- const NotMatched: unique symbol;`);
1095
+ namespace MarkoRun {
1096
+ export * from "@marko/run/namespace";
1097
+ export type Route = ${routeType};
1098
+ export type Context = Run.MultiRouteContext<Route>${isMarko ? " & Marko.Global" : ""};
1099
+ export type Handler = Run.HandlerLike<Route>;
1100
+ export const route: Run.HandlerTypeFn<Handler>;
1101
+ }`);
1162
1102
  }
1163
1103
  writer.writeLines(`
1164
- }
1165
1104
  }`);
1166
1105
  }
1106
+ function pathToURLPatternString(path3) {
1107
+ return path3.replace(/\/\$(\$?)([^\/]*)/g, (_, catchAll, name) => {
1108
+ name = decodeURIComponent(name);
1109
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1110
+ });
1111
+ }
1167
1112
 
1168
1113
  // src/vite/utils/ast.ts
1169
1114
  import * as t from "@babel/types";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marko/run",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "The Marko application framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/marko-js/run/tree/main/packages/run",
@@ -32,6 +32,9 @@
32
32
  "import": "./dist/runtime/index.js",
33
33
  "require": "./dist/runtime/index.cjs"
34
34
  },
35
+ "./namespace": {
36
+ "types": "./dist/runtime/namespace.d.ts"
37
+ },
35
38
  "./router": {
36
39
  "types": "./dist/runtime/router.d.ts",
37
40
  "import": "./dist/runtime/router.js",
@@ -58,6 +61,9 @@
58
61
  "*": [
59
62
  "./dist/runtime/index.d.ts"
60
63
  ],
64
+ "namespace": [
65
+ "./dist/runtime/namespace.d.ts"
66
+ ],
61
67
  "router": [
62
68
  "./dist/runtime/router.d.ts"
63
69
  ],
@@ -1,36 +0,0 @@
1
- import { createServer } from "vite";
2
-
3
- let activeDevServers;
4
-
5
- process
6
- .on("message", (message) => {
7
- switch (message.type) {
8
- case "start":
9
- return start(message.entry, message.config);
10
- case "shutdown":
11
- return shutdown();
12
- }
13
- })
14
- .send("ready");
15
-
16
- async function start(entry, config) {
17
- let changed = false;
18
- const loader = await createServer(config);
19
- ({ activeDevServers } = await loader.ssrLoadModule("@marko/run/adapter"));
20
- await loader.ssrLoadModule(entry);
21
-
22
- loader.watcher.on("change", (path) => {
23
- if (!changed && loader.moduleGraph.getModulesByFile(path)) {
24
- changed = true;
25
- process.send("restart");
26
- }
27
- });
28
- }
29
-
30
- function shutdown() {
31
- if (activeDevServers) {
32
- for (const devServer of activeDevServers) {
33
- devServer.ws.send({ type: "full-reload" });
34
- }
35
- }
36
- }
package/dist/index.html DELETED
@@ -1 +0,0 @@
1
- <!doctype html><html lang=en><head><meta charset=UTF-8><title>@marko/run Test Fixture</title><script async type="module" crossorigin src="/assets/__marko-run__route__index.marko-3cfb730f.js"></script></head><body><div id=app>Page rendered</div></body></html>