@marko/run 0.0.1-beta4 → 0.0.1-beta6
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 +72 -18
- package/dist/adapter/index.cjs +27 -7
- package/dist/adapter/index.js +27 -7
- package/dist/adapter/middleware.cjs +28 -12
- package/dist/adapter/middleware.js +27 -7
- package/dist/adapter/polyfill.d.ts +1 -0
- package/dist/cli/index.mjs +1 -1
- package/dist/runtime/index.d.ts +9 -2
- package/dist/runtime/internal.cjs +2 -2
- package/dist/runtime/internal.js +2 -2
- package/dist/runtime/types.d.ts +8 -0
- package/dist/vite/index.cjs +122 -8
- package/dist/vite/index.js +122 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
</a>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
`@marko/
|
|
15
|
+
`@marko/run` is an application framework for [Marko](https://markojs.com), with these features:
|
|
16
16
|
|
|
17
|
-
-
|
|
17
|
+
- Vite plugin that encapsulates [`@marko/vite`](https://github.com/marko-js/vite)
|
|
18
|
+
- CLI to simplify build modes
|
|
18
19
|
- File-based routing with layouts and middleware
|
|
19
20
|
- Efficient routing using a compiled static trie
|
|
20
21
|
- [Designed with web standards](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/URLPattern) to run anywhere
|
|
22
|
+
- TypeScript support
|
|
21
23
|
|
|
22
24
|
## Installation
|
|
23
25
|
|
|
@@ -25,6 +27,39 @@
|
|
|
25
27
|
npm install @marko/run
|
|
26
28
|
```
|
|
27
29
|
|
|
30
|
+
## CLI
|
|
31
|
+
|
|
32
|
+
The package provides a command line tool `marko-run` which can be run using scripts in your package.json or with npx.
|
|
33
|
+
|
|
34
|
+
### Getting Started / Zero Config
|
|
35
|
+
|
|
36
|
+
`marko-run` makes it easy to get started without little to no config. The package ships with a default Vite config and node-based adapter that means a minimal project start can be:
|
|
37
|
+
1. Install `@marko/run`
|
|
38
|
+
2. Create file `src/routes/+page.marko`
|
|
39
|
+
3. Run `npx marko-run dev`
|
|
40
|
+
4. Open browser to `http://localhost:3000`
|
|
41
|
+
|
|
42
|
+
### Commands
|
|
43
|
+
|
|
44
|
+
**`dev`** - Start development server in watch mode
|
|
45
|
+
```bash
|
|
46
|
+
> npx marko-run dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**`build`** - Create a production build
|
|
50
|
+
```bash
|
|
51
|
+
> npx marko-run build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**`preview`** - Create a production build and serve
|
|
55
|
+
```bash
|
|
56
|
+
> npx marko-run preview
|
|
57
|
+
```
|
|
58
|
+
or (default command)
|
|
59
|
+
```bash
|
|
60
|
+
> npx marko-run
|
|
61
|
+
```
|
|
62
|
+
|
|
28
63
|
## Vite Plugin
|
|
29
64
|
|
|
30
65
|
This package’s Vite plugin discovers your route files, generates the routing code, and registers the `@marko/vite` plugin to compile your `.marko` files.
|
|
@@ -36,47 +71,66 @@ import marko from "@marko/run/vite"; // Import the Vite plugin
|
|
|
36
71
|
|
|
37
72
|
export default defineConfig({
|
|
38
73
|
plugins: [marko()], // Register the Vite plugin
|
|
39
|
-
build: {
|
|
40
|
-
sourcemap: true, // Generate sourcemaps for all builds
|
|
41
|
-
emptyOutDir: false, // Avoid server & client deleting files from each other. TODO: do we have to make the user set this themselves?
|
|
42
|
-
}
|
|
43
74
|
})
|
|
44
75
|
```
|
|
45
76
|
|
|
77
|
+
## Adapters
|
|
78
|
+
|
|
79
|
+
*🎗 TODO: provide a quick overview*
|
|
80
|
+
|
|
46
81
|
## Runtime
|
|
47
82
|
|
|
48
|
-
Generally, using
|
|
83
|
+
Generally, when using an adapter, this runtime will be abstracted away.
|
|
49
84
|
|
|
50
85
|
```ts
|
|
51
|
-
import { router,
|
|
86
|
+
import { router, matchRoute, invokeRoute } from '@marko/run/router`;
|
|
52
87
|
```
|
|
53
88
|
|
|
54
89
|
### `router`
|
|
55
90
|
|
|
56
91
|
```ts
|
|
57
|
-
|
|
92
|
+
interface RequestContext<T> {
|
|
93
|
+
url: URL;
|
|
94
|
+
method: string;
|
|
95
|
+
request: Request;
|
|
96
|
+
platform: T;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function router(context: RequestContext) => Promise<Response | void>;
|
|
58
100
|
```
|
|
59
101
|
|
|
60
|
-
This asynchronous function takes a
|
|
102
|
+
This asynchronous function takes a context object and returns the [WHATWG `Response` object](https://fetch.spec.whatwg.org/#response-class) from executing any matched route files or undefined if the request was explicitly not handled. If no route matches the requested path, a `404` status code response will be returned. If an error occurs a `500` status code response will be returned.
|
|
61
103
|
|
|
62
|
-
|
|
104
|
+
The context object contains the following properties
|
|
105
|
+
- `url`: The URL reprensting the requested resource
|
|
106
|
+
- `method`: The HTTP method used
|
|
107
|
+
- `request`: [WHATWG `Request` object](https://fetch.spec.whatwg.org/#request-class)
|
|
108
|
+
- `platform`: An object containing any platform-specific data (eg Node request/response) and will vary between adapters.
|
|
63
109
|
|
|
64
|
-
### `
|
|
110
|
+
### `matchRoute`
|
|
65
111
|
|
|
66
112
|
```ts
|
|
67
|
-
|
|
113
|
+
interface interface Route {
|
|
68
114
|
params: Record<string, string>;
|
|
69
115
|
meta: unknown;
|
|
70
|
-
|
|
71
|
-
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function matchRoute(method: string, pathname: string) => Route | null;
|
|
72
119
|
```
|
|
73
120
|
|
|
74
|
-
This synchronous function takes an HTTP method
|
|
121
|
+
This synchronous function takes an HTTP method and path name, then returns an object representing the best match — or `null` if no match is found.
|
|
75
122
|
|
|
76
123
|
- `params` - a `{ key: value }` collection of any path parameters for the route
|
|
77
124
|
- `meta` - metadata for the route
|
|
78
|
-
|
|
79
|
-
|
|
125
|
+
|
|
126
|
+
### `invokeRoute`
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
function invokeRoute(route: Route, context: RequestContext) => Promise<Response | void>;
|
|
130
|
+
```
|
|
131
|
+
This asynchronous function takes a route object returned by [matchRoute](#matchRoute) and a context object and returns a response in the same way the [router](#router) does.
|
|
132
|
+
|
|
133
|
+
|
|
80
134
|
|
|
81
135
|
## File-based Routing
|
|
82
136
|
|
package/dist/adapter/index.cjs
CHANGED
|
@@ -37,15 +37,35 @@ var import_url = require("url");
|
|
|
37
37
|
// src/adapter/dev-server.ts
|
|
38
38
|
var import_vite = require("vite");
|
|
39
39
|
|
|
40
|
-
// src/adapter/
|
|
41
|
-
var
|
|
42
|
-
var import_crypto =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
// src/adapter/polyfill.ts
|
|
41
|
+
var import_web = require("stream/web");
|
|
42
|
+
var import_crypto = require("crypto");
|
|
43
|
+
var import_undici = require("undici");
|
|
44
|
+
var globals = {
|
|
45
|
+
crypto: import_crypto.webcrypto,
|
|
46
|
+
fetch: import_undici.fetch,
|
|
47
|
+
Response: import_undici.Response,
|
|
48
|
+
Request: import_undici.Request,
|
|
49
|
+
Headers: import_undici.Headers,
|
|
50
|
+
ReadableStream: import_web.ReadableStream,
|
|
51
|
+
TransformStream: import_web.TransformStream,
|
|
52
|
+
WritableStream: import_web.WritableStream,
|
|
53
|
+
FormData: import_undici.FormData,
|
|
54
|
+
File: import_undici.File
|
|
55
|
+
};
|
|
56
|
+
function installPolyfills() {
|
|
57
|
+
for (const name in globals) {
|
|
58
|
+
Object.defineProperty(globalThis, name, {
|
|
59
|
+
enumerable: true,
|
|
60
|
+
configurable: true,
|
|
61
|
+
writable: true,
|
|
62
|
+
value: globals[name]
|
|
63
|
+
});
|
|
47
64
|
}
|
|
48
65
|
}
|
|
66
|
+
|
|
67
|
+
// src/adapter/middleware.ts
|
|
68
|
+
installPolyfills();
|
|
49
69
|
function getForwardedHeader(req, name) {
|
|
50
70
|
const value = req.headers["x-forwarded-" + name];
|
|
51
71
|
if (value) {
|
package/dist/adapter/index.js
CHANGED
|
@@ -5,15 +5,35 @@ import { fileURLToPath } from "url";
|
|
|
5
5
|
// src/adapter/dev-server.ts
|
|
6
6
|
import { createServer } from "vite";
|
|
7
7
|
|
|
8
|
-
// src/adapter/
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
// src/adapter/polyfill.ts
|
|
9
|
+
import { ReadableStream as ReadableStream2, TransformStream, WritableStream } from "stream/web";
|
|
10
|
+
import { webcrypto as crypto } from "crypto";
|
|
11
|
+
import { fetch, Response, Request as Request2, Headers, FormData, File } from "undici";
|
|
12
|
+
var globals = {
|
|
13
|
+
crypto,
|
|
14
|
+
fetch,
|
|
15
|
+
Response,
|
|
16
|
+
Request: Request2,
|
|
17
|
+
Headers,
|
|
18
|
+
ReadableStream: ReadableStream2,
|
|
19
|
+
TransformStream,
|
|
20
|
+
WritableStream,
|
|
21
|
+
FormData,
|
|
22
|
+
File
|
|
23
|
+
};
|
|
24
|
+
function installPolyfills() {
|
|
25
|
+
for (const name in globals) {
|
|
26
|
+
Object.defineProperty(globalThis, name, {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: globals[name]
|
|
31
|
+
});
|
|
15
32
|
}
|
|
16
33
|
}
|
|
34
|
+
|
|
35
|
+
// src/adapter/middleware.ts
|
|
36
|
+
installPolyfills();
|
|
17
37
|
function getForwardedHeader(req, name) {
|
|
18
38
|
const value = req.headers["x-forwarded-" + name];
|
|
19
39
|
if (value) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,10 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
19
|
|
|
26
20
|
// src/adapter/middleware.ts
|
|
@@ -30,14 +24,36 @@ __export(middleware_exports, {
|
|
|
30
24
|
getOrigin: () => getOrigin
|
|
31
25
|
});
|
|
32
26
|
module.exports = __toCommonJS(middleware_exports);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
|
|
28
|
+
// src/adapter/polyfill.ts
|
|
29
|
+
var import_web = require("stream/web");
|
|
30
|
+
var import_crypto = require("crypto");
|
|
31
|
+
var import_undici = require("undici");
|
|
32
|
+
var globals = {
|
|
33
|
+
crypto: import_crypto.webcrypto,
|
|
34
|
+
fetch: import_undici.fetch,
|
|
35
|
+
Response: import_undici.Response,
|
|
36
|
+
Request: import_undici.Request,
|
|
37
|
+
Headers: import_undici.Headers,
|
|
38
|
+
ReadableStream: import_web.ReadableStream,
|
|
39
|
+
TransformStream: import_web.TransformStream,
|
|
40
|
+
WritableStream: import_web.WritableStream,
|
|
41
|
+
FormData: import_undici.FormData,
|
|
42
|
+
File: import_undici.File
|
|
43
|
+
};
|
|
44
|
+
function installPolyfills() {
|
|
45
|
+
for (const name in globals) {
|
|
46
|
+
Object.defineProperty(globalThis, name, {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: globals[name]
|
|
51
|
+
});
|
|
39
52
|
}
|
|
40
53
|
}
|
|
54
|
+
|
|
55
|
+
// src/adapter/middleware.ts
|
|
56
|
+
installPolyfills();
|
|
41
57
|
function getForwardedHeader(req, name) {
|
|
42
58
|
const value = req.headers["x-forwarded-" + name];
|
|
43
59
|
if (value) {
|
|
@@ -1,12 +1,32 @@
|
|
|
1
|
-
// src/adapter/
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// src/adapter/polyfill.ts
|
|
2
|
+
import { ReadableStream as ReadableStream2, TransformStream, WritableStream } from "stream/web";
|
|
3
|
+
import { webcrypto as crypto } from "crypto";
|
|
4
|
+
import { fetch, Response, Request as Request2, Headers, FormData, File } from "undici";
|
|
5
|
+
var globals = {
|
|
6
|
+
crypto,
|
|
7
|
+
fetch,
|
|
8
|
+
Response,
|
|
9
|
+
Request: Request2,
|
|
10
|
+
Headers,
|
|
11
|
+
ReadableStream: ReadableStream2,
|
|
12
|
+
TransformStream,
|
|
13
|
+
WritableStream,
|
|
14
|
+
FormData,
|
|
15
|
+
File
|
|
16
|
+
};
|
|
17
|
+
function installPolyfills() {
|
|
18
|
+
for (const name in globals) {
|
|
19
|
+
Object.defineProperty(globalThis, name, {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: globals[name]
|
|
24
|
+
});
|
|
8
25
|
}
|
|
9
26
|
}
|
|
27
|
+
|
|
28
|
+
// src/adapter/middleware.ts
|
|
29
|
+
installPolyfills();
|
|
10
30
|
function getForwardedHeader(req, name) {
|
|
11
31
|
const value = req.headers["x-forwarded-" + name];
|
|
12
32
|
if (value) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installPolyfills(): void;
|
package/dist/cli/index.mjs
CHANGED
|
@@ -108,7 +108,7 @@ prog.command("dev [entry]").describe("Start development server in watch mode").o
|
|
|
108
108
|
const config2 = await getViteConfig(cwd, opts.config);
|
|
109
109
|
await dev(cmd, config2, opts.port, opts.env);
|
|
110
110
|
});
|
|
111
|
-
prog.command("build [entry]").describe("Build the application (without serving it)").option("-o, --output", "Directory to write built files (default: )").option("--skip-client", "Skip the client-side build").example("build --config vite.config.js").action(async (entry, opts) => {
|
|
111
|
+
prog.command("build [entry]").describe("Build the application (without serving it)").option("-o, --output", "Directory to write built files (default: 'build.outDir' in Vite config)").option("--skip-client", "Skip the client-side build").example("build --config vite.config.js").action(async (entry, opts) => {
|
|
112
112
|
const config2 = await getViteConfig(cwd, opts.config);
|
|
113
113
|
await build(entry, config2, opts.ouput, opts["skip-client"], opts.env);
|
|
114
114
|
});
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import type { HandlerLike, ParamsObject, Route } from "./types";
|
|
1
|
+
import type { HandlerLike, ParamsObject, Route, RouteContext } from "./types";
|
|
2
2
|
declare global {
|
|
3
3
|
namespace Marko {
|
|
4
|
+
interface Global {
|
|
5
|
+
context: RouteContext;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
namespace MarkoRun {
|
|
4
9
|
interface CurrentRoute extends Route {
|
|
5
10
|
}
|
|
11
|
+
interface CurrentContext extends RouteContext<CurrentRoute> {
|
|
12
|
+
}
|
|
6
13
|
type Handler<Params extends ParamsObject = {}, Meta = unknown> = HandlerLike<Route<Params, Meta, string>>;
|
|
7
14
|
function route<Params extends ParamsObject = {}, Meta = unknown>(handler: Handler<Params, Meta>): typeof handler;
|
|
8
15
|
}
|
|
9
16
|
}
|
|
10
|
-
export type { HandlerLike, InputObject, InvokeRoute, MatchRoute, NextFunction, RequestContext, Route, RouteContext, RouteContextExtensions, RouteHandler, RouteWithHandler, Router, } from "./types";
|
|
17
|
+
export type { HandlerLike, InputObject, InvokeRoute, MatchRoute, NextFunction, PathTemplate, RequestContext, Route, RouteContext, RouteContextExtensions, RouteHandler, RouteWithHandler, Router, ValidateHref, ValidatePath, } from "./types";
|
|
@@ -31,8 +31,8 @@ __export(internal_exports, {
|
|
|
31
31
|
notMatched: () => notMatched
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(internal_exports);
|
|
34
|
-
globalThis.
|
|
35
|
-
globalThis.
|
|
34
|
+
globalThis.MarkoRun ?? (globalThis.MarkoRun = {});
|
|
35
|
+
globalThis.MarkoRun.route = (handler) => handler;
|
|
36
36
|
var RequestNotHandled = Symbol();
|
|
37
37
|
var RequestNotMatched = Symbol();
|
|
38
38
|
function createInput(context) {
|
package/dist/runtime/internal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/runtime/internal.ts
|
|
2
|
-
globalThis.
|
|
3
|
-
globalThis.
|
|
2
|
+
globalThis.MarkoRun ?? (globalThis.MarkoRun = {});
|
|
3
|
+
globalThis.MarkoRun.route = (handler) => handler;
|
|
4
4
|
var RequestNotHandled = Symbol();
|
|
5
5
|
var RequestNotMatched = Symbol();
|
|
6
6
|
function createInput(context) {
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -32,4 +32,12 @@ export interface RouteWithHandler<Params extends ParamsObject = {}, Meta = unkno
|
|
|
32
32
|
export declare type MatchRoute = (method: string, pathname: string) => RouteWithHandler | null;
|
|
33
33
|
export declare type Router<T = unknown> = (context: RequestContext<T>) => Promise<Response | void>;
|
|
34
34
|
export declare type InvokeRoute<T = unknown> = (route: Route | null, context: RequestContext<T>) => Promise<Response | void>;
|
|
35
|
+
declare type Member<T, U> = T extends T ? (U extends T ? T : never) : never;
|
|
36
|
+
declare type Segments<T extends string, Acc extends string[] = []> = T extends "" ? Acc : T extends `${infer Left}/${infer Rest}` ? Segments<Rest, [...Acc, Left]> : [...Acc, T];
|
|
37
|
+
declare 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
|
+
declare 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
|
+
declare 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 declare 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 declare type ValidatePath<Paths extends string, Path extends string> = Paths | (Path extends `/${string}` ? MatchSegments<Member<PathPattern<Paths>, Path>, Path> : Path);
|
|
42
|
+
export declare 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>;
|
|
35
43
|
export {};
|
package/dist/vite/index.cjs
CHANGED
|
@@ -980,6 +980,7 @@ function stripTsExtension(path3) {
|
|
|
980
980
|
return path3;
|
|
981
981
|
}
|
|
982
982
|
function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
983
|
+
var _a, _b;
|
|
983
984
|
const writer = createStringWriter();
|
|
984
985
|
writer.writeLines(
|
|
985
986
|
`/*
|
|
@@ -987,13 +988,28 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
987
988
|
Do NOT manually edit this file or your changes will be lost.
|
|
988
989
|
*/
|
|
989
990
|
`,
|
|
990
|
-
`import type { HandlerLike, Route } from "@marko/run";
|
|
991
|
-
|
|
991
|
+
`import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";
|
|
992
|
+
|
|
993
|
+
declare global {
|
|
994
|
+
namespace MarkoRun {`
|
|
992
995
|
);
|
|
996
|
+
const pathsWriter = writer.branch("paths");
|
|
997
|
+
writer.write(`
|
|
998
|
+
type GetablePath<T extends string> = ValidatePath<GetPaths, T>;
|
|
999
|
+
type GetableHref<T extends string> = ValidateHref<GetPaths, T>;
|
|
1000
|
+
type PostablePath<T extends string> = ValidatePath<PostPaths, T>;
|
|
1001
|
+
type PostableHref<T extends string> = ValidateHref<PostPaths, T>;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
`);
|
|
993
1005
|
const routesWriter = writer.branch("types");
|
|
1006
|
+
const serverWriter = writer.branch("server");
|
|
994
1007
|
const middlewareRouteTypes = /* @__PURE__ */ new Map();
|
|
1008
|
+
const layoutRouteTypes = /* @__PURE__ */ new Map();
|
|
1009
|
+
const getPaths = /* @__PURE__ */ new Set();
|
|
1010
|
+
const postPaths = /* @__PURE__ */ new Set();
|
|
995
1011
|
for (const route of routes.list) {
|
|
996
|
-
const { meta, handler, params, middleware } = route;
|
|
1012
|
+
const { meta, handler, params, middleware, page, layouts } = route;
|
|
997
1013
|
const routeType = `Route${route.index}`;
|
|
998
1014
|
const pathType = `\`${route.path.replace(
|
|
999
1015
|
/\/\$(\$?)([^\/]*)/,
|
|
@@ -1001,6 +1017,24 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
1001
1017
|
)}\``;
|
|
1002
1018
|
const paramsType = params ? renderParamsInfoType(params) : "{}";
|
|
1003
1019
|
let metaType = "undefined";
|
|
1020
|
+
if (page || handler) {
|
|
1021
|
+
const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
|
|
1022
|
+
const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
|
|
1023
|
+
if (isGet || isPost) {
|
|
1024
|
+
const path3 = route.path.replace(
|
|
1025
|
+
/\$(\$?)([^/]+)/g,
|
|
1026
|
+
(_, s, name) => s ? `\${...${name}}` : `\${${name}}`
|
|
1027
|
+
);
|
|
1028
|
+
const splatIndex = path3.indexOf("/${...");
|
|
1029
|
+
if (splatIndex >= 0) {
|
|
1030
|
+
const path22 = path3.slice(0, splatIndex) || "/";
|
|
1031
|
+
isGet && getPaths.add(path22);
|
|
1032
|
+
isPost && postPaths.add(path22);
|
|
1033
|
+
}
|
|
1034
|
+
isGet && getPaths.add(path3);
|
|
1035
|
+
isPost && postPaths.add(path3);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1004
1038
|
if (meta) {
|
|
1005
1039
|
metaType = `typeof import('${pathPrefix}/${stripTsExtension(
|
|
1006
1040
|
meta.relativePath
|
|
@@ -1010,7 +1044,23 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
1010
1044
|
}
|
|
1011
1045
|
}
|
|
1012
1046
|
if (handler) {
|
|
1013
|
-
writeRouteTypeModule(
|
|
1047
|
+
writeRouteTypeModule(
|
|
1048
|
+
serverWriter,
|
|
1049
|
+
pathPrefix,
|
|
1050
|
+
handler.relativePath,
|
|
1051
|
+
routeType
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
if (page) {
|
|
1055
|
+
writer.writeLines(`
|
|
1056
|
+
declare module '${pathPrefix}/${page.relativePath}' {
|
|
1057
|
+
export interface Input {}
|
|
1058
|
+
|
|
1059
|
+
namespace MarkoRun {
|
|
1060
|
+
type CurrentRoute = ${routeType};
|
|
1061
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1062
|
+
}
|
|
1063
|
+
}`);
|
|
1014
1064
|
}
|
|
1015
1065
|
if (middleware) {
|
|
1016
1066
|
let i = 0;
|
|
@@ -1027,21 +1077,84 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
1027
1077
|
i++;
|
|
1028
1078
|
}
|
|
1029
1079
|
}
|
|
1080
|
+
if (layouts) {
|
|
1081
|
+
for (const layout of layouts) {
|
|
1082
|
+
const existing = layoutRouteTypes.get(layout);
|
|
1083
|
+
if (!existing) {
|
|
1084
|
+
layoutRouteTypes.set(layout, {
|
|
1085
|
+
routeTypes: [routeType]
|
|
1086
|
+
});
|
|
1087
|
+
} else {
|
|
1088
|
+
existing.routeTypes.push(routeType);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1030
1092
|
routesWriter.writeLines(
|
|
1031
1093
|
`interface ${routeType} extends Route<${paramsType}, ${metaType}, ${pathType}> {}`
|
|
1032
1094
|
);
|
|
1033
1095
|
}
|
|
1096
|
+
pathsWriter.write(" type GetPaths =");
|
|
1097
|
+
for (const path3 of getPaths) {
|
|
1098
|
+
pathsWriter.write(`
|
|
1099
|
+
| '${path3}'`);
|
|
1100
|
+
}
|
|
1101
|
+
pathsWriter.writeLines(";", "");
|
|
1102
|
+
pathsWriter.write(" type PostPaths =");
|
|
1103
|
+
for (const path3 of postPaths) {
|
|
1104
|
+
pathsWriter.write(`
|
|
1105
|
+
| '${path3}'`);
|
|
1106
|
+
}
|
|
1107
|
+
pathsWriter.writeLines(";");
|
|
1108
|
+
pathsWriter.join();
|
|
1034
1109
|
for (const [file, { routeTypes }] of middlewareRouteTypes) {
|
|
1035
|
-
|
|
1036
|
-
|
|
1110
|
+
writeRouteTypeModule(
|
|
1111
|
+
serverWriter,
|
|
1112
|
+
pathPrefix,
|
|
1113
|
+
file.relativePath,
|
|
1114
|
+
routeTypes.join(" | ")
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
for (const [file, { routeTypes }] of layoutRouteTypes) {
|
|
1118
|
+
writer.writeLines(`
|
|
1119
|
+
declare module '${pathPrefix}/${file.relativePath}' {
|
|
1120
|
+
export interface Input {
|
|
1121
|
+
renderBody: Marko.Body;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
namespace MarkoRun {
|
|
1125
|
+
type CurrentRoute = ${routeTypes.join(" | ")};
|
|
1126
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1127
|
+
}
|
|
1128
|
+
}`);
|
|
1129
|
+
}
|
|
1130
|
+
for (const route of [routes.special["404"], routes.special["500"]]) {
|
|
1131
|
+
if (route && route.page) {
|
|
1132
|
+
writer.write(`
|
|
1133
|
+
declare module '${pathPrefix}/${route.page.relativePath}' {
|
|
1134
|
+
export interface Input {`);
|
|
1135
|
+
if (route.page.type === RoutableFileTypes.Error) {
|
|
1136
|
+
writer.write(`
|
|
1137
|
+
error: unknown;
|
|
1138
|
+
`);
|
|
1139
|
+
}
|
|
1140
|
+
writer.writeLines(`}
|
|
1141
|
+
|
|
1142
|
+
namespace MarkoRun {
|
|
1143
|
+
type CurrentRoute = Route;
|
|
1144
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1145
|
+
}
|
|
1146
|
+
}`);
|
|
1147
|
+
}
|
|
1037
1148
|
}
|
|
1149
|
+
serverWriter.join();
|
|
1038
1150
|
return writer.end();
|
|
1039
1151
|
}
|
|
1040
1152
|
function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
|
|
1041
1153
|
writer.writeLines(`
|
|
1042
1154
|
declare module '${pathPrefix}/${stripTsExtension(path3)}' {
|
|
1043
|
-
namespace
|
|
1155
|
+
namespace MarkoRun {
|
|
1044
1156
|
type CurrentRoute = ${routeType};
|
|
1157
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1045
1158
|
type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
|
|
1046
1159
|
function route(handler: Handler): typeof handler;
|
|
1047
1160
|
function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
|
|
@@ -1321,13 +1434,14 @@ function markoServe(opts = {}) {
|
|
|
1321
1434
|
const startTime = performance.now();
|
|
1322
1435
|
routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
|
|
1323
1436
|
times.routesBuild = performance.now() - startTime;
|
|
1324
|
-
await
|
|
1437
|
+
await setVirtualFiles(false);
|
|
1325
1438
|
isStale = false;
|
|
1326
1439
|
isRendered = false;
|
|
1327
1440
|
});
|
|
1328
1441
|
const renderVirtualFiles = single(async () => {
|
|
1329
1442
|
const startTime = performance.now();
|
|
1330
1443
|
await setVirtualFiles(true);
|
|
1444
|
+
await writeTypesFile();
|
|
1331
1445
|
times.routesRender = performance.now() - startTime;
|
|
1332
1446
|
isRendered = true;
|
|
1333
1447
|
});
|
package/dist/vite/index.js
CHANGED
|
@@ -943,6 +943,7 @@ function stripTsExtension(path3) {
|
|
|
943
943
|
return path3;
|
|
944
944
|
}
|
|
945
945
|
function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
946
|
+
var _a, _b;
|
|
946
947
|
const writer = createStringWriter();
|
|
947
948
|
writer.writeLines(
|
|
948
949
|
`/*
|
|
@@ -950,13 +951,28 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
950
951
|
Do NOT manually edit this file or your changes will be lost.
|
|
951
952
|
*/
|
|
952
953
|
`,
|
|
953
|
-
`import type { HandlerLike, Route } from "@marko/run";
|
|
954
|
-
|
|
954
|
+
`import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";
|
|
955
|
+
|
|
956
|
+
declare global {
|
|
957
|
+
namespace MarkoRun {`
|
|
955
958
|
);
|
|
959
|
+
const pathsWriter = writer.branch("paths");
|
|
960
|
+
writer.write(`
|
|
961
|
+
type GetablePath<T extends string> = ValidatePath<GetPaths, T>;
|
|
962
|
+
type GetableHref<T extends string> = ValidateHref<GetPaths, T>;
|
|
963
|
+
type PostablePath<T extends string> = ValidatePath<PostPaths, T>;
|
|
964
|
+
type PostableHref<T extends string> = ValidateHref<PostPaths, T>;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
`);
|
|
956
968
|
const routesWriter = writer.branch("types");
|
|
969
|
+
const serverWriter = writer.branch("server");
|
|
957
970
|
const middlewareRouteTypes = /* @__PURE__ */ new Map();
|
|
971
|
+
const layoutRouteTypes = /* @__PURE__ */ new Map();
|
|
972
|
+
const getPaths = /* @__PURE__ */ new Set();
|
|
973
|
+
const postPaths = /* @__PURE__ */ new Set();
|
|
958
974
|
for (const route of routes.list) {
|
|
959
|
-
const { meta, handler, params, middleware } = route;
|
|
975
|
+
const { meta, handler, params, middleware, page, layouts } = route;
|
|
960
976
|
const routeType = `Route${route.index}`;
|
|
961
977
|
const pathType = `\`${route.path.replace(
|
|
962
978
|
/\/\$(\$?)([^\/]*)/,
|
|
@@ -964,6 +980,24 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
964
980
|
)}\``;
|
|
965
981
|
const paramsType = params ? renderParamsInfoType(params) : "{}";
|
|
966
982
|
let metaType = "undefined";
|
|
983
|
+
if (page || handler) {
|
|
984
|
+
const isGet = page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"));
|
|
985
|
+
const isPost = (_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post");
|
|
986
|
+
if (isGet || isPost) {
|
|
987
|
+
const path3 = route.path.replace(
|
|
988
|
+
/\$(\$?)([^/]+)/g,
|
|
989
|
+
(_, s, name) => s ? `\${...${name}}` : `\${${name}}`
|
|
990
|
+
);
|
|
991
|
+
const splatIndex = path3.indexOf("/${...");
|
|
992
|
+
if (splatIndex >= 0) {
|
|
993
|
+
const path22 = path3.slice(0, splatIndex) || "/";
|
|
994
|
+
isGet && getPaths.add(path22);
|
|
995
|
+
isPost && postPaths.add(path22);
|
|
996
|
+
}
|
|
997
|
+
isGet && getPaths.add(path3);
|
|
998
|
+
isPost && postPaths.add(path3);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
967
1001
|
if (meta) {
|
|
968
1002
|
metaType = `typeof import('${pathPrefix}/${stripTsExtension(
|
|
969
1003
|
meta.relativePath
|
|
@@ -973,7 +1007,23 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
973
1007
|
}
|
|
974
1008
|
}
|
|
975
1009
|
if (handler) {
|
|
976
|
-
writeRouteTypeModule(
|
|
1010
|
+
writeRouteTypeModule(
|
|
1011
|
+
serverWriter,
|
|
1012
|
+
pathPrefix,
|
|
1013
|
+
handler.relativePath,
|
|
1014
|
+
routeType
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
if (page) {
|
|
1018
|
+
writer.writeLines(`
|
|
1019
|
+
declare module '${pathPrefix}/${page.relativePath}' {
|
|
1020
|
+
export interface Input {}
|
|
1021
|
+
|
|
1022
|
+
namespace MarkoRun {
|
|
1023
|
+
type CurrentRoute = ${routeType};
|
|
1024
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1025
|
+
}
|
|
1026
|
+
}`);
|
|
977
1027
|
}
|
|
978
1028
|
if (middleware) {
|
|
979
1029
|
let i = 0;
|
|
@@ -990,21 +1040,84 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
|
|
|
990
1040
|
i++;
|
|
991
1041
|
}
|
|
992
1042
|
}
|
|
1043
|
+
if (layouts) {
|
|
1044
|
+
for (const layout of layouts) {
|
|
1045
|
+
const existing = layoutRouteTypes.get(layout);
|
|
1046
|
+
if (!existing) {
|
|
1047
|
+
layoutRouteTypes.set(layout, {
|
|
1048
|
+
routeTypes: [routeType]
|
|
1049
|
+
});
|
|
1050
|
+
} else {
|
|
1051
|
+
existing.routeTypes.push(routeType);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
993
1055
|
routesWriter.writeLines(
|
|
994
1056
|
`interface ${routeType} extends Route<${paramsType}, ${metaType}, ${pathType}> {}`
|
|
995
1057
|
);
|
|
996
1058
|
}
|
|
1059
|
+
pathsWriter.write(" type GetPaths =");
|
|
1060
|
+
for (const path3 of getPaths) {
|
|
1061
|
+
pathsWriter.write(`
|
|
1062
|
+
| '${path3}'`);
|
|
1063
|
+
}
|
|
1064
|
+
pathsWriter.writeLines(";", "");
|
|
1065
|
+
pathsWriter.write(" type PostPaths =");
|
|
1066
|
+
for (const path3 of postPaths) {
|
|
1067
|
+
pathsWriter.write(`
|
|
1068
|
+
| '${path3}'`);
|
|
1069
|
+
}
|
|
1070
|
+
pathsWriter.writeLines(";");
|
|
1071
|
+
pathsWriter.join();
|
|
997
1072
|
for (const [file, { routeTypes }] of middlewareRouteTypes) {
|
|
998
|
-
|
|
999
|
-
|
|
1073
|
+
writeRouteTypeModule(
|
|
1074
|
+
serverWriter,
|
|
1075
|
+
pathPrefix,
|
|
1076
|
+
file.relativePath,
|
|
1077
|
+
routeTypes.join(" | ")
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
for (const [file, { routeTypes }] of layoutRouteTypes) {
|
|
1081
|
+
writer.writeLines(`
|
|
1082
|
+
declare module '${pathPrefix}/${file.relativePath}' {
|
|
1083
|
+
export interface Input {
|
|
1084
|
+
renderBody: Marko.Body;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
namespace MarkoRun {
|
|
1088
|
+
type CurrentRoute = ${routeTypes.join(" | ")};
|
|
1089
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1090
|
+
}
|
|
1091
|
+
}`);
|
|
1092
|
+
}
|
|
1093
|
+
for (const route of [routes.special["404"], routes.special["500"]]) {
|
|
1094
|
+
if (route && route.page) {
|
|
1095
|
+
writer.write(`
|
|
1096
|
+
declare module '${pathPrefix}/${route.page.relativePath}' {
|
|
1097
|
+
export interface Input {`);
|
|
1098
|
+
if (route.page.type === RoutableFileTypes.Error) {
|
|
1099
|
+
writer.write(`
|
|
1100
|
+
error: unknown;
|
|
1101
|
+
`);
|
|
1102
|
+
}
|
|
1103
|
+
writer.writeLines(`}
|
|
1104
|
+
|
|
1105
|
+
namespace MarkoRun {
|
|
1106
|
+
type CurrentRoute = Route;
|
|
1107
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1108
|
+
}
|
|
1109
|
+
}`);
|
|
1110
|
+
}
|
|
1000
1111
|
}
|
|
1112
|
+
serverWriter.join();
|
|
1001
1113
|
return writer.end();
|
|
1002
1114
|
}
|
|
1003
1115
|
function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
|
|
1004
1116
|
writer.writeLines(`
|
|
1005
1117
|
declare module '${pathPrefix}/${stripTsExtension(path3)}' {
|
|
1006
|
-
namespace
|
|
1118
|
+
namespace MarkoRun {
|
|
1007
1119
|
type CurrentRoute = ${routeType};
|
|
1120
|
+
type CurrentContext = RouteContext<CurrentRoute>;
|
|
1008
1121
|
type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
|
|
1009
1122
|
function route(handler: Handler): typeof handler;
|
|
1010
1123
|
function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
|
|
@@ -1283,13 +1396,14 @@ function markoServe(opts = {}) {
|
|
|
1283
1396
|
const startTime = performance.now();
|
|
1284
1397
|
routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
|
|
1285
1398
|
times.routesBuild = performance.now() - startTime;
|
|
1286
|
-
await
|
|
1399
|
+
await setVirtualFiles(false);
|
|
1287
1400
|
isStale = false;
|
|
1288
1401
|
isRendered = false;
|
|
1289
1402
|
});
|
|
1290
1403
|
const renderVirtualFiles = single(async () => {
|
|
1291
1404
|
const startTime = performance.now();
|
|
1292
1405
|
await setVirtualFiles(true);
|
|
1406
|
+
await writeTypesFile();
|
|
1293
1407
|
times.routesRender = performance.now() - startTime;
|
|
1294
1408
|
isRendered = true;
|
|
1295
1409
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marko/run",
|
|
3
|
-
"version": "0.0.1-
|
|
3
|
+
"version": "0.0.1-beta6",
|
|
4
4
|
"description": "File-based routing for Marko based on Vite",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Ryan Turnquist <rturnq@gmail.com>",
|
|
@@ -89,7 +89,6 @@
|
|
|
89
89
|
"typescript": "^4.7.4"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@hattip/polyfills": "^0.0.27",
|
|
93
92
|
"@marko/vite": "^2.3.9",
|
|
94
93
|
"cli-table3": "^0.6.3",
|
|
95
94
|
"compression": "^1.7.4",
|
|
@@ -100,6 +99,7 @@
|
|
|
100
99
|
"kleur": "^4.1.5",
|
|
101
100
|
"sade": "^1.8.1",
|
|
102
101
|
"serve-static": "^1.15.0",
|
|
102
|
+
"undici": "^5.20.0",
|
|
103
103
|
"vite": "^3.0.8"
|
|
104
104
|
}
|
|
105
105
|
}
|