@marko/run 0.1.7 → 0.1.9

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
@@ -483,7 +483,23 @@ express()
483
483
 
484
484
  **`MarkoRun.Route`** - Type of the route's params and metadata
485
485
 
486
- **`MarkoRun.Context`** - 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
@@ -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 type { 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 Route = 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 Route> = 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 Route = AnyRoute> = Awaitable<OneOrMany<RouteHandler<TRoute>>>;
20
+ export type RouteHandler<TRoute extends Route = AnyRoute> = (context: MultiRouteContext<TRoute>, next: NextFunction) => Awaitable<Response | null | void>;
21
+ export interface Route<Params extends ParamsObject = ParamsObject, Meta = unknown, Path extends string = 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>;
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>> : HandlerLike<AnyRoute>;
86
+ export type HandlerTypeFn<TRoute extends Route = AnyRoute> = 0 extends HasAppData ? <Params extends ParamsObject = ParamsObject, Meta = unknown>(handler: HandlerLike<Route<Params, Meta>>) => HandlerLike<Route<Params, Meta>> : (handler: HandlerLike<TRoute>) => HandlerLike<TRoute>;
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 {};
@@ -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,16 +944,6 @@ 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}`;
@@ -995,70 +987,64 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
995
987
  Do NOT manually edit this file or your changes will be lost.
996
988
  */
997
989
  `,
998
- `import type { HandlerLike, Route as AnyRoute, Context as AnyContext, ParamsObject, ValidatePath, ValidateHref } from "@marko/run";`
990
+ `import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace";`,
991
+ `import type Run from "@marko/run";`
999
992
  );
1000
- let platformType = "unknown";
993
+ const headWriter = writer.branch("head");
994
+ writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
1001
995
  if (adapter && adapter.typeInfo) {
1002
- platformType = await adapter.typeInfo((data) => writer.write(data));
1003
- writer.writeLines("");
1004
- }
1005
- writer.writeLines(`
1006
- interface NoParams extends ParamsObject {}
1007
- interface NoMeta {}
996
+ const platformType = await adapter.typeInfo(
997
+ (data) => headWriter.write(data)
998
+ );
999
+ if (platformType) {
1000
+ writer.writeLines(`interface Platform extends ${platformType} {}
1008
1001
  `);
1009
- const pathsWriter = writer.branch("paths");
1010
- const routesWriter = writer.branch("types");
1011
- 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");
1012
1009
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
1013
1010
  const layoutRouteTypes = /* @__PURE__ */ new Map();
1014
- const getPaths = /* @__PURE__ */ new Set();
1015
- const postPaths = /* @__PURE__ */ new Set();
1016
- writeModuleDeclaration(serverWriter, void 0, void 0, platformType);
1017
1011
  for (const route of routes.list) {
1018
- const { meta, handler, params, middleware, page, layouts } = route;
1019
- const routeType = `Route${route.index}`;
1020
- const pathType = `\`${pathToURLPatternString(route.path)}\``;
1021
- const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
1022
- let metaType = "NoMeta";
1012
+ const { meta, handler, middleware, page, layouts } = route;
1013
+ const pathType = `${pathToURLPatternString(route.path)}`;
1014
+ const routeType = `"${pathType}"`;
1015
+ let verbType = "";
1023
1016
  if (page || handler) {
1024
- const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
1025
- const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
1026
- if (isGet || isPost) {
1027
- const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
1028
- name = decodeURIComponent(name);
1029
- return catchAll ? `\${...${name}}` : `\${${name}}`;
1030
- });
1031
- const splatIndex = path3.indexOf("/${...");
1032
- if (splatIndex >= 0) {
1033
- const path22 = path3.slice(0, splatIndex) || "/";
1034
- isGet && getPaths.add(path22);
1035
- isPost && postPaths.add(path22);
1036
- }
1037
- isGet && getPaths.add(path3);
1038
- 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"`);
1039
1020
  }
1021
+ if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
1022
+ verbs.push(`"post"`);
1023
+ }
1024
+ verbType = verbs.join(" | ");
1040
1025
  }
1041
1026
  if (meta) {
1042
1027
  const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1043
- metaType = `typeof import('${path3}')`;
1028
+ let metaType = `typeof import("${path3}")`;
1044
1029
  if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1045
- metaType += `['default']`;
1030
+ metaType += `["default"]`;
1046
1031
  }
1032
+ routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
1033
+ } else {
1034
+ routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1047
1035
  }
1048
1036
  if (handler) {
1049
1037
  writeModuleDeclaration(
1050
- serverWriter,
1038
+ moduleWriter,
1051
1039
  `${pathPrefix}/${handler.relativePath}`,
1052
- routeType,
1053
- platformType
1040
+ `Run.Routes[${routeType}]`
1054
1041
  );
1055
1042
  }
1056
1043
  if (page) {
1057
1044
  writeModuleDeclaration(
1058
1045
  writer,
1059
1046
  `${pathPrefix}/${page.relativePath}`,
1060
- routeType,
1061
- platformType,
1047
+ `Run.Routes[${routeType}]`,
1062
1048
  `
1063
1049
  export interface Input {
1064
1050
  renderBody: Marko.Body;
@@ -1092,45 +1078,20 @@ interface NoMeta {}
1092
1078
  }
1093
1079
  }
1094
1080
  }
1095
- routesWriter.writeLines(
1096
- `type ${routeType} = AnyRoute<${paramsType}, ${metaType}, ${pathType}>;`
1097
- );
1098
- }
1099
- pathsWriter.write(`type Get =`);
1100
- if (getPaths.size) {
1101
- for (const path3 of getPaths) {
1102
- pathsWriter.write(`
1103
- | '${path3}'`);
1104
- }
1105
- } else {
1106
- pathsWriter.write(" never");
1107
- }
1108
- pathsWriter.writeLines(";", "");
1109
- pathsWriter.write("type Post =");
1110
- if (postPaths.size) {
1111
- for (const path3 of postPaths) {
1112
- pathsWriter.write(`
1113
- | '${path3}'`);
1114
- }
1115
- } else {
1116
- pathsWriter.write(" never");
1117
1081
  }
1118
- pathsWriter.writeLines(";", "");
1119
- pathsWriter.join();
1082
+ routesWriter.join();
1120
1083
  for (const [file, { routeTypes }] of middlewareRouteTypes) {
1121
1084
  writeModuleDeclaration(
1122
- serverWriter,
1085
+ moduleWriter,
1123
1086
  `${pathPrefix}/${file.relativePath}`,
1124
- routeTypes.join(" | "),
1125
- platformType
1087
+ `Run.Routes[${routeTypes.join(" | ")}]`
1126
1088
  );
1127
1089
  }
1128
1090
  for (const [file, { routeTypes }] of layoutRouteTypes) {
1129
1091
  writeModuleDeclaration(
1130
1092
  writer,
1131
1093
  `${pathPrefix}/${file.relativePath}`,
1132
- routeTypes.join(" | "),
1133
- platformType,
1094
+ `Run.Routes[${routeTypes.join(" | ")}]`,
1134
1095
  `
1135
1096
  export interface Input {
1136
1097
  renderBody: Marko.Body;
@@ -1141,8 +1102,7 @@ interface NoMeta {}
1141
1102
  writeModuleDeclaration(
1142
1103
  writer,
1143
1104
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
1144
- void 0,
1145
- platformType,
1105
+ "Run.Route",
1146
1106
  `
1147
1107
  export interface Input {}`
1148
1108
  );
@@ -1151,59 +1111,40 @@ interface NoMeta {}
1151
1111
  writeModuleDeclaration(
1152
1112
  writer,
1153
1113
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
1154
- void 0,
1155
- platformType,
1114
+ "globalThis.MarkoRun.Route",
1156
1115
  `
1157
1116
  export interface Input {
1158
1117
  error: unknown;
1159
1118
  }`
1160
1119
  );
1161
1120
  }
1162
- serverWriter.join();
1121
+ moduleWriter.join();
1163
1122
  return writer.end();
1164
1123
  }
1165
- function writeModuleDeclaration(writer, path3 = "global", routeType = "AnyRoute", platformType = "unknown", moduleTypes) {
1166
- writer.writeLines("");
1167
- if (path3 === "global") {
1168
- writer.write("declare global {");
1169
- } else {
1170
- writer.write(`declare module '${stripTsExtension(path3)}' {`);
1171
- }
1124
+ function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
1125
+ writer.writeLines("").write(`declare module "${stripTsExtension(path3)}" {`);
1172
1126
  if (moduleTypes) {
1173
- writer.writeLines(moduleTypes);
1127
+ writer.write(moduleTypes);
1174
1128
  }
1175
- const isMarko = path3.endsWith(".marko");
1176
- writer.write(`
1177
- namespace MarkoRun {
1178
- type GetPaths = Get;
1179
- type PostPaths = Post;
1180
- type GetablePath<T extends string> = ValidatePath<Get, T>;
1181
- type GetableHref<T extends string> = ValidateHref<Get, T>;
1182
- type PostablePath<T extends string> = ValidatePath<Post, T>;
1183
- type PostableHref<T extends string> = ValidateHref<Post, T>;
1184
- type Platform = ${platformType};`);
1185
- if (path3 !== "global") {
1129
+ if (routeType) {
1130
+ const isMarko = path3.endsWith(".marko");
1186
1131
  writer.write(`
1187
- type Route = ${routeType};
1188
- type Context = AnyContext<Platform, Route>${isMarko ? " & Marko.Global" : ""};
1189
- type Handler<_Params = Route['params'], _Meta = Route['meta']> = HandlerLike<Route>;
1190
- function route(handler: Handler): typeof handler;
1191
- function route<_Params = Route['params'], _Meta = Route['meta']>(handler: Handler): typeof handler;
1192
- const NotHandled: unique symbol;
1193
- const NotMatched: unique symbol;`);
1132
+ namespace MarkoRun {
1133
+ export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
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<Route>;
1138
+ }`);
1194
1139
  }
1195
1140
  writer.writeLines(`
1196
- }
1197
1141
  }`);
1198
1142
  }
1199
1143
  function pathToURLPatternString(path3) {
1200
- return path3.replace(
1201
- /\/\$(\$?)([^\/]*)/g,
1202
- (_, catchAll, name) => {
1203
- name = decodeURIComponent(name);
1204
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1205
- }
1206
- );
1144
+ return path3.replace(/\/\$(\$?)([^\/]*)/g, (_, catchAll, name) => {
1145
+ name = decodeURIComponent(name);
1146
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1147
+ });
1207
1148
  }
1208
1149
 
1209
1150
  // src/vite/utils/ast.ts
@@ -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,16 +907,6 @@ 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}`;
@@ -958,70 +950,64 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
958
950
  Do NOT manually edit this file or your changes will be lost.
959
951
  */
960
952
  `,
961
- `import type { HandlerLike, Route as AnyRoute, Context as AnyContext, ParamsObject, ValidatePath, ValidateHref } from "@marko/run";`
953
+ `import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace";`,
954
+ `import type Run from "@marko/run";`
962
955
  );
963
- let platformType = "unknown";
956
+ const headWriter = writer.branch("head");
957
+ writer.writeLines("\n").writeBlockStart(`declare module "@marko/run" {`);
964
958
  if (adapter && adapter.typeInfo) {
965
- platformType = await adapter.typeInfo((data) => writer.write(data));
966
- writer.writeLines("");
967
- }
968
- writer.writeLines(`
969
- interface NoParams extends ParamsObject {}
970
- interface NoMeta {}
959
+ const platformType = await adapter.typeInfo(
960
+ (data) => headWriter.write(data)
961
+ );
962
+ if (platformType) {
963
+ writer.writeLines(`interface Platform extends ${platformType} {}
971
964
  `);
972
- const pathsWriter = writer.branch("paths");
973
- const routesWriter = writer.branch("types");
974
- 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");
975
972
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
976
973
  const layoutRouteTypes = /* @__PURE__ */ new Map();
977
- const getPaths = /* @__PURE__ */ new Set();
978
- const postPaths = /* @__PURE__ */ new Set();
979
- writeModuleDeclaration(serverWriter, void 0, void 0, platformType);
980
974
  for (const route of routes.list) {
981
- const { meta, handler, params, middleware, page, layouts } = route;
982
- const routeType = `Route${route.index}`;
983
- const pathType = `\`${pathToURLPatternString(route.path)}\``;
984
- const paramsType = (params == null ? void 0 : params.length) ? renderParamsInfoType(params) : "NoParams";
985
- let metaType = "NoMeta";
975
+ const { meta, handler, middleware, page, layouts } = route;
976
+ const pathType = `${pathToURLPatternString(route.path)}`;
977
+ const routeType = `"${pathType}"`;
978
+ let verbType = "";
986
979
  if (page || handler) {
987
- const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
988
- const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
989
- if (isGet || isPost) {
990
- const path3 = route.path.replace(/\$(\$?)([^/]+)/g, (_, catchAll, name) => {
991
- name = decodeURIComponent(name);
992
- return catchAll ? `\${...${name}}` : `\${${name}}`;
993
- });
994
- const splatIndex = path3.indexOf("/${...");
995
- if (splatIndex >= 0) {
996
- const path22 = path3.slice(0, splatIndex) || "/";
997
- isGet && getPaths.add(path22);
998
- isPost && postPaths.add(path22);
999
- }
1000
- isGet && getPaths.add(path3);
1001
- 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"`);
1002
983
  }
984
+ if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
985
+ verbs.push(`"post"`);
986
+ }
987
+ verbType = verbs.join(" | ");
1003
988
  }
1004
989
  if (meta) {
1005
990
  const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1006
- metaType = `typeof import('${path3}')`;
991
+ let metaType = `typeof import("${path3}")`;
1007
992
  if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1008
- metaType += `['default']`;
993
+ metaType += `["default"]`;
1009
994
  }
995
+ routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
996
+ } else {
997
+ routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1010
998
  }
1011
999
  if (handler) {
1012
1000
  writeModuleDeclaration(
1013
- serverWriter,
1001
+ moduleWriter,
1014
1002
  `${pathPrefix}/${handler.relativePath}`,
1015
- routeType,
1016
- platformType
1003
+ `Run.Routes[${routeType}]`
1017
1004
  );
1018
1005
  }
1019
1006
  if (page) {
1020
1007
  writeModuleDeclaration(
1021
1008
  writer,
1022
1009
  `${pathPrefix}/${page.relativePath}`,
1023
- routeType,
1024
- platformType,
1010
+ `Run.Routes[${routeType}]`,
1025
1011
  `
1026
1012
  export interface Input {
1027
1013
  renderBody: Marko.Body;
@@ -1055,45 +1041,20 @@ interface NoMeta {}
1055
1041
  }
1056
1042
  }
1057
1043
  }
1058
- routesWriter.writeLines(
1059
- `type ${routeType} = AnyRoute<${paramsType}, ${metaType}, ${pathType}>;`
1060
- );
1061
- }
1062
- pathsWriter.write(`type Get =`);
1063
- if (getPaths.size) {
1064
- for (const path3 of getPaths) {
1065
- pathsWriter.write(`
1066
- | '${path3}'`);
1067
- }
1068
- } else {
1069
- pathsWriter.write(" never");
1070
- }
1071
- pathsWriter.writeLines(";", "");
1072
- pathsWriter.write("type Post =");
1073
- if (postPaths.size) {
1074
- for (const path3 of postPaths) {
1075
- pathsWriter.write(`
1076
- | '${path3}'`);
1077
- }
1078
- } else {
1079
- pathsWriter.write(" never");
1080
1044
  }
1081
- pathsWriter.writeLines(";", "");
1082
- pathsWriter.join();
1045
+ routesWriter.join();
1083
1046
  for (const [file, { routeTypes }] of middlewareRouteTypes) {
1084
1047
  writeModuleDeclaration(
1085
- serverWriter,
1048
+ moduleWriter,
1086
1049
  `${pathPrefix}/${file.relativePath}`,
1087
- routeTypes.join(" | "),
1088
- platformType
1050
+ `Run.Routes[${routeTypes.join(" | ")}]`
1089
1051
  );
1090
1052
  }
1091
1053
  for (const [file, { routeTypes }] of layoutRouteTypes) {
1092
1054
  writeModuleDeclaration(
1093
1055
  writer,
1094
1056
  `${pathPrefix}/${file.relativePath}`,
1095
- routeTypes.join(" | "),
1096
- platformType,
1057
+ `Run.Routes[${routeTypes.join(" | ")}]`,
1097
1058
  `
1098
1059
  export interface Input {
1099
1060
  renderBody: Marko.Body;
@@ -1104,8 +1065,7 @@ interface NoMeta {}
1104
1065
  writeModuleDeclaration(
1105
1066
  writer,
1106
1067
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
1107
- void 0,
1108
- platformType,
1068
+ "Run.Route",
1109
1069
  `
1110
1070
  export interface Input {}`
1111
1071
  );
@@ -1114,59 +1074,40 @@ interface NoMeta {}
1114
1074
  writeModuleDeclaration(
1115
1075
  writer,
1116
1076
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
1117
- void 0,
1118
- platformType,
1077
+ "globalThis.MarkoRun.Route",
1119
1078
  `
1120
1079
  export interface Input {
1121
1080
  error: unknown;
1122
1081
  }`
1123
1082
  );
1124
1083
  }
1125
- serverWriter.join();
1084
+ moduleWriter.join();
1126
1085
  return writer.end();
1127
1086
  }
1128
- function writeModuleDeclaration(writer, path3 = "global", routeType = "AnyRoute", platformType = "unknown", moduleTypes) {
1129
- writer.writeLines("");
1130
- if (path3 === "global") {
1131
- writer.write("declare global {");
1132
- } else {
1133
- writer.write(`declare module '${stripTsExtension(path3)}' {`);
1134
- }
1087
+ function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
1088
+ writer.writeLines("").write(`declare module "${stripTsExtension(path3)}" {`);
1135
1089
  if (moduleTypes) {
1136
- writer.writeLines(moduleTypes);
1090
+ writer.write(moduleTypes);
1137
1091
  }
1138
- const isMarko = path3.endsWith(".marko");
1139
- writer.write(`
1140
- namespace MarkoRun {
1141
- type GetPaths = Get;
1142
- type PostPaths = Post;
1143
- type GetablePath<T extends string> = ValidatePath<Get, T>;
1144
- type GetableHref<T extends string> = ValidateHref<Get, T>;
1145
- type PostablePath<T extends string> = ValidatePath<Post, T>;
1146
- type PostableHref<T extends string> = ValidateHref<Post, T>;
1147
- type Platform = ${platformType};`);
1148
- if (path3 !== "global") {
1092
+ if (routeType) {
1093
+ const isMarko = path3.endsWith(".marko");
1149
1094
  writer.write(`
1150
- type Route = ${routeType};
1151
- type Context = AnyContext<Platform, Route>${isMarko ? " & Marko.Global" : ""};
1152
- type Handler<_Params = Route['params'], _Meta = Route['meta']> = HandlerLike<Route>;
1153
- function route(handler: Handler): typeof handler;
1154
- function route<_Params = Route['params'], _Meta = Route['meta']>(handler: Handler): typeof handler;
1155
- const NotHandled: unique symbol;
1156
- const NotMatched: unique symbol;`);
1095
+ namespace MarkoRun {
1096
+ export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform };
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<Route>;
1101
+ }`);
1157
1102
  }
1158
1103
  writer.writeLines(`
1159
- }
1160
1104
  }`);
1161
1105
  }
1162
1106
  function pathToURLPatternString(path3) {
1163
- return path3.replace(
1164
- /\/\$(\$?)([^\/]*)/g,
1165
- (_, catchAll, name) => {
1166
- name = decodeURIComponent(name);
1167
- return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1168
- }
1169
- );
1107
+ return path3.replace(/\/\$(\$?)([^\/]*)/g, (_, catchAll, name) => {
1108
+ name = decodeURIComponent(name);
1109
+ return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1110
+ });
1170
1111
  }
1171
1112
 
1172
1113
  // src/vite/utils/ast.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marko/run",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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>