wrangler 0.0.0-e043479 → 0.0.0-e0a0509
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 +27 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +38 -25
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +136 -25
- package/pages/functions/filepath-routing.ts +14 -3
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +146 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +1294 -355
- package/src/__tests__/dev.test.tsx +592 -12
- package/src/__tests__/guess-worker-format.test.ts +37 -18
- package/src/__tests__/helpers/mock-account-id.ts +4 -0
- package/src/__tests__/helpers/mock-cfetch.ts +8 -4
- package/src/__tests__/helpers/mock-console.ts +20 -3
- package/src/__tests__/helpers/mock-dialogs.ts +26 -1
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +10 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +130 -0
- package/src/__tests__/index.test.ts +129 -753
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +13 -5
- package/src/__tests__/kv.test.ts +208 -174
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +327 -0
- package/src/__tests__/parse.test.ts +4 -0
- package/src/__tests__/publish.test.ts +3313 -505
- package/src/__tests__/r2.test.ts +38 -26
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +26 -7
- package/src/bundle.ts +43 -7
- package/src/cfetch/internal.ts +9 -5
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +69 -105
- package/src/config/environment.ts +93 -4
- package/src/config/index.ts +15 -4
- package/src/config/validation-helpers.ts +228 -23
- package/src/config/validation.ts +559 -154
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +41 -13
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +33 -10
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +418 -0
- package/src/dev/local.tsx +312 -0
- package/src/dev/remote.tsx +213 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +222 -12
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +123 -0
- package/src/index.tsx +878 -482
- package/src/inspect.ts +25 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +7 -27
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +41 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +94 -6
- package/src/open-in-browser.ts +18 -5
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +892 -62
- package/src/parse.ts +4 -2
- package/src/proxy.ts +128 -55
- package/src/publish.ts +305 -199
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +88 -33
- package/src/tail/index.ts +2 -2
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +244 -104
- package/src/whoami.tsx +2 -1
- package/src/{api/worker.ts → worker.ts} +15 -29
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +23568 -50489
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/__tests__/logout.test.ts +0 -50
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/dev.tsx +0 -960
- package/src/guess-worker-format.ts +0 -68
- package/src/reporting.ts +0 -115
- package/wrangler-dist/cli.js.map +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrangler",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-e0a0509",
|
|
4
4
|
"author": "wrangler@cloudflare.com",
|
|
5
5
|
"description": "Command-line interface for all things Cloudflare Workers",
|
|
6
6
|
"bin": {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"license": "MIT OR Apache-2.0",
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/cloudflare/
|
|
12
|
+
"url": "https://github.com/cloudflare/wrangler2/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/cloudflare/
|
|
14
|
+
"homepage": "https://github.com/cloudflare/wrangler2#readme",
|
|
15
15
|
"keywords": [
|
|
16
16
|
"wrangler",
|
|
17
17
|
"cloudflare",
|
|
@@ -36,9 +36,14 @@
|
|
|
36
36
|
"cli"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"esbuild": "0.
|
|
40
|
-
"
|
|
39
|
+
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
|
|
40
|
+
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
|
|
41
|
+
"blake3-wasm": "^2.1.5",
|
|
42
|
+
"esbuild": "0.14.34",
|
|
43
|
+
"miniflare": "2.4.0",
|
|
44
|
+
"nanoid": "^3.3.3",
|
|
41
45
|
"path-to-regexp": "^6.2.0",
|
|
46
|
+
"selfsigned": "^2.0.1",
|
|
42
47
|
"semiver": "^1.1.0",
|
|
43
48
|
"xxhash-wasm": "^1.0.1"
|
|
44
49
|
},
|
|
@@ -46,10 +51,7 @@
|
|
|
46
51
|
"fsevents": "~2.3.2"
|
|
47
52
|
},
|
|
48
53
|
"devDependencies": {
|
|
49
|
-
"@iarna/toml": "^
|
|
50
|
-
"@sentry/cli": "^1.71.0",
|
|
51
|
-
"@sentry/integrations": "^6.17.6",
|
|
52
|
-
"@sentry/node": "^6.17.6",
|
|
54
|
+
"@iarna/toml": "^3.0.0",
|
|
53
55
|
"@types/command-exists": "^1.2.0",
|
|
54
56
|
"@types/glob-to-regexp": "0.4.1",
|
|
55
57
|
"@types/mime": "^2.0.3",
|
|
@@ -57,55 +59,65 @@
|
|
|
57
59
|
"@types/react": "^17.0.37",
|
|
58
60
|
"@types/serve-static": "^1.13.10",
|
|
59
61
|
"@types/signal-exit": "^3.0.1",
|
|
60
|
-
"@types/
|
|
61
|
-
"@types/
|
|
62
|
-
"
|
|
62
|
+
"@types/supports-color": "^8.1.1",
|
|
63
|
+
"@types/ws": "^8.5.3",
|
|
64
|
+
"@types/yargs": "^17.0.10",
|
|
65
|
+
"@webcontainer/env": "^1.0.1",
|
|
66
|
+
"chokidar": "^3.5.3",
|
|
63
67
|
"clipboardy": "^3.0.0",
|
|
64
68
|
"cmd-shim": "^4.1.0",
|
|
65
69
|
"command-exists": "^1.2.9",
|
|
66
70
|
"devtools-protocol": "^0.0.955664",
|
|
67
|
-
"
|
|
71
|
+
"dotenv": "^16.0.0",
|
|
72
|
+
"execa": "^6.1.0",
|
|
68
73
|
"faye-websocket": "^0.11.4",
|
|
69
|
-
"finalhandler": "^1.
|
|
70
|
-
"find-up": "^6.
|
|
74
|
+
"finalhandler": "^1.2.0",
|
|
75
|
+
"find-up": "^6.3.0",
|
|
71
76
|
"get-port": "^6.1.2",
|
|
72
77
|
"glob-to-regexp": "0.4.1",
|
|
73
78
|
"ignore": "^5.2.0",
|
|
74
79
|
"ink": "^3.2.0",
|
|
75
80
|
"ink-select-input": "^4.2.1",
|
|
81
|
+
"ink-spinner": "^4.0.3",
|
|
76
82
|
"ink-table": "^3.0.0",
|
|
77
83
|
"ink-testing-library": "^2.1.0",
|
|
78
|
-
"ink-text-input": "^4.0.
|
|
84
|
+
"ink-text-input": "^4.0.3",
|
|
79
85
|
"jest-fetch-mock": "^3.0.3",
|
|
80
86
|
"jest-websocket-mock": "^2.3.0",
|
|
81
87
|
"mime": "^3.0.0",
|
|
82
88
|
"open": "^8.4.0",
|
|
89
|
+
"pretty-bytes": "^6.0.0",
|
|
83
90
|
"prompts": "^2.4.2",
|
|
84
91
|
"react": "^17.0.2",
|
|
85
92
|
"react-error-boundary": "^3.1.4",
|
|
86
|
-
"serve-static": "^1.
|
|
87
|
-
"signal-exit": "^3.0.
|
|
93
|
+
"serve-static": "^1.15.0",
|
|
94
|
+
"signal-exit": "^3.0.7",
|
|
95
|
+
"supports-color": "^9.2.2",
|
|
96
|
+
"timeago.js": "^4.0.2",
|
|
88
97
|
"tmp-promise": "^3.0.3",
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
98
|
+
"ts-dedent": "^2.2.0",
|
|
99
|
+
"undici": "^4.15.1",
|
|
100
|
+
"update-check": "^1.5.4",
|
|
101
|
+
"ws": "^8.5.0",
|
|
102
|
+
"yargs": "^17.4.1"
|
|
92
103
|
},
|
|
93
104
|
"files": [
|
|
94
105
|
"src",
|
|
95
106
|
"bin",
|
|
96
107
|
"pages",
|
|
97
108
|
"miniflare-config-stubs",
|
|
109
|
+
"miniflare-dist",
|
|
98
110
|
"wrangler-dist",
|
|
99
111
|
"templates",
|
|
100
112
|
"vendor",
|
|
101
113
|
"import_meta_url.js"
|
|
102
114
|
],
|
|
103
115
|
"scripts": {
|
|
104
|
-
"clean": "rm -rf wrangler-dist",
|
|
116
|
+
"clean": "rm -rf wrangler-dist miniflare-dist",
|
|
105
117
|
"check:type": "tsc",
|
|
106
118
|
"bundle": "node -r esbuild-register scripts/bundle.ts",
|
|
107
119
|
"build": "npm run clean && npm run bundle",
|
|
108
|
-
"prepublishOnly": "npm run build",
|
|
120
|
+
"prepublishOnly": "SOURCEMAPS=false npm run build",
|
|
109
121
|
"start": "npm run bundle && NODE_OPTIONS=--enable-source-maps ./bin/wrangler.js",
|
|
110
122
|
"test": "jest --silent=false --verbose=true",
|
|
111
123
|
"test-watch": "npm run test -- --runInBand --testTimeout=50000 --watch"
|
|
@@ -118,10 +130,11 @@
|
|
|
118
130
|
"testTimeout": 30000,
|
|
119
131
|
"testRegex": ".*.(test|spec)\\.[jt]sx?$",
|
|
120
132
|
"transformIgnorePatterns": [
|
|
121
|
-
"node_modules/(?!find-up|locate-path|p-locate|p-limit|yocto-queue|path-exists|execa|strip-final-newline|npm-run-path|path-key|onetime|mimic-fn|human-signals|is-stream|get-port)"
|
|
133
|
+
"node_modules/(?!find-up|locate-path|p-locate|p-limit|yocto-queue|path-exists|execa|strip-final-newline|npm-run-path|path-key|onetime|mimic-fn|human-signals|is-stream|get-port|supports-color|pretty-bytes)"
|
|
122
134
|
],
|
|
123
135
|
"moduleNameMapper": {
|
|
124
|
-
"clipboardy": "<rootDir>/src/__tests__/helpers/clipboardy-mock.js"
|
|
136
|
+
"clipboardy": "<rootDir>/src/__tests__/helpers/clipboardy-mock.js",
|
|
137
|
+
"miniflare/cli": "<rootDir>/../../node_modules/miniflare/dist/src/cli.js"
|
|
125
138
|
},
|
|
126
139
|
"transform": {
|
|
127
140
|
"^.+\\.c?(t|j)sx?$": [
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { access, lstat } from "node:fs/promises";
|
|
2
|
+
import { dirname, relative, resolve } from "node:path";
|
|
3
|
+
import { build } from "esbuild";
|
|
4
|
+
|
|
5
|
+
type Options = {
|
|
6
|
+
routesModule: string;
|
|
7
|
+
outfile: string;
|
|
8
|
+
minify?: boolean;
|
|
9
|
+
sourcemap?: boolean;
|
|
10
|
+
watch?: boolean;
|
|
11
|
+
onEnd?: () => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function buildPlugin({
|
|
15
|
+
routesModule,
|
|
16
|
+
outfile = "bundle.js",
|
|
17
|
+
minify = false,
|
|
18
|
+
sourcemap = false,
|
|
19
|
+
watch = false,
|
|
20
|
+
onEnd = () => {},
|
|
21
|
+
}: Options) {
|
|
22
|
+
return build({
|
|
23
|
+
entryPoints: [resolve(__dirname, "../pages/functions/template-plugin.ts")],
|
|
24
|
+
inject: [routesModule],
|
|
25
|
+
bundle: true,
|
|
26
|
+
format: "esm",
|
|
27
|
+
target: "esnext",
|
|
28
|
+
outfile,
|
|
29
|
+
minify,
|
|
30
|
+
sourcemap,
|
|
31
|
+
watch,
|
|
32
|
+
allowOverwrite: true,
|
|
33
|
+
plugins: [
|
|
34
|
+
{
|
|
35
|
+
name: "wrangler notifier and monitor",
|
|
36
|
+
setup(pluginBuild) {
|
|
37
|
+
pluginBuild.onEnd((result) => {
|
|
38
|
+
if (result.errors.length > 0) {
|
|
39
|
+
console.error(
|
|
40
|
+
`${result.errors.length} error(s) and ${result.warnings.length} warning(s) when compiling Worker.`
|
|
41
|
+
);
|
|
42
|
+
} else if (result.warnings.length > 0) {
|
|
43
|
+
console.warn(
|
|
44
|
+
`${result.warnings.length} warning(s) when compiling Worker.`
|
|
45
|
+
);
|
|
46
|
+
onEnd();
|
|
47
|
+
} else {
|
|
48
|
+
console.log("Compiled Worker successfully.");
|
|
49
|
+
onEnd();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "Assets",
|
|
56
|
+
setup(pluginBuild) {
|
|
57
|
+
if (pluginBuild.initialOptions.outfile) {
|
|
58
|
+
const outdir = dirname(pluginBuild.initialOptions.outfile);
|
|
59
|
+
|
|
60
|
+
pluginBuild.onResolve({ filter: /^assets:/ }, async (args) => {
|
|
61
|
+
const directory = resolve(
|
|
62
|
+
args.resolveDir,
|
|
63
|
+
args.path.slice("assets:".length)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const exists = await access(directory)
|
|
67
|
+
.then(() => true)
|
|
68
|
+
.catch(() => false);
|
|
69
|
+
|
|
70
|
+
const isDirectory =
|
|
71
|
+
exists && (await lstat(directory)).isDirectory();
|
|
72
|
+
|
|
73
|
+
if (!isDirectory) {
|
|
74
|
+
return {
|
|
75
|
+
errors: [
|
|
76
|
+
{
|
|
77
|
+
text: `'${directory}' does not exist or is not a directory.`,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const path = `assets:./${relative(outdir, directory)}`;
|
|
84
|
+
|
|
85
|
+
return { path, external: true, namespace: "assets" };
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { access, cp, lstat, rm } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
2
3
|
import { build } from "esbuild";
|
|
4
|
+
import { nanoid } from "nanoid";
|
|
3
5
|
|
|
4
6
|
type Options = {
|
|
5
7
|
routesModule: string;
|
|
@@ -9,6 +11,7 @@ type Options = {
|
|
|
9
11
|
fallbackService?: string;
|
|
10
12
|
watch?: boolean;
|
|
11
13
|
onEnd?: () => void;
|
|
14
|
+
buildOutputDirectory?: string;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
export function buildWorker({
|
|
@@ -19,11 +22,10 @@ export function buildWorker({
|
|
|
19
22
|
fallbackService = "ASSETS",
|
|
20
23
|
watch = false,
|
|
21
24
|
onEnd = () => {},
|
|
25
|
+
buildOutputDirectory,
|
|
22
26
|
}: Options) {
|
|
23
27
|
return build({
|
|
24
|
-
entryPoints: [
|
|
25
|
-
path.resolve(__dirname, "../pages/functions/template-worker.ts"),
|
|
26
|
-
],
|
|
28
|
+
entryPoints: [resolve(__dirname, "../pages/functions/template-worker.ts")],
|
|
27
29
|
inject: [routesModule],
|
|
28
30
|
bundle: true,
|
|
29
31
|
format: "esm",
|
|
@@ -57,6 +59,80 @@ export function buildWorker({
|
|
|
57
59
|
});
|
|
58
60
|
},
|
|
59
61
|
},
|
|
62
|
+
{
|
|
63
|
+
name: "Assets",
|
|
64
|
+
setup(pluginBuild) {
|
|
65
|
+
const identifiers = new Map<string, string>();
|
|
66
|
+
|
|
67
|
+
pluginBuild.onResolve({ filter: /^assets:/ }, async (args) => {
|
|
68
|
+
const directory = resolve(
|
|
69
|
+
args.resolveDir,
|
|
70
|
+
args.path.slice("assets:".length)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const exists = await access(directory)
|
|
74
|
+
.then(() => true)
|
|
75
|
+
.catch(() => false);
|
|
76
|
+
|
|
77
|
+
const isDirectory =
|
|
78
|
+
exists && (await lstat(directory)).isDirectory();
|
|
79
|
+
|
|
80
|
+
if (!isDirectory) {
|
|
81
|
+
return {
|
|
82
|
+
errors: [
|
|
83
|
+
{
|
|
84
|
+
text: `'${directory}' does not exist or is not a directory.`,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// TODO: Consider hashing the contents rather than using a unique identifier every time?
|
|
91
|
+
identifiers.set(directory, nanoid());
|
|
92
|
+
if (!buildOutputDirectory) {
|
|
93
|
+
console.warn(
|
|
94
|
+
"You're attempting to import static assets as part of your Pages Functions, but have not specified a directory in which to put them. You must use 'wrangler pages dev <directory>' rather than 'wrangler pages dev -- <command>' to import static assets in Functions."
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return { path: directory, namespace: "assets" };
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
pluginBuild.onLoad(
|
|
101
|
+
{ filter: /.*/, namespace: "assets" },
|
|
102
|
+
async (args) => {
|
|
103
|
+
const identifier = identifiers.get(args.path);
|
|
104
|
+
|
|
105
|
+
if (buildOutputDirectory) {
|
|
106
|
+
const staticAssetsOutputDirectory = join(
|
|
107
|
+
buildOutputDirectory,
|
|
108
|
+
"cdn-cgi",
|
|
109
|
+
"pages-plugins",
|
|
110
|
+
identifier as string
|
|
111
|
+
);
|
|
112
|
+
await rm(staticAssetsOutputDirectory, {
|
|
113
|
+
force: true,
|
|
114
|
+
recursive: true,
|
|
115
|
+
});
|
|
116
|
+
await cp(args.path, staticAssetsOutputDirectory, {
|
|
117
|
+
force: true,
|
|
118
|
+
recursive: true,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
// TODO: Watch args.path for changes and re-copy when updated
|
|
123
|
+
contents: `export const onRequest = ({ request, env, functionPath }) => {
|
|
124
|
+
const url = new URL(request.url)
|
|
125
|
+
const relativePathname = url.pathname.split(functionPath)[1] || "/";
|
|
126
|
+
url.pathname = '/cdn-cgi/pages-plugins/${identifier}' + relativePathname
|
|
127
|
+
request = new Request(url.toString(), request)
|
|
128
|
+
return env.ASSETS.fetch(request)
|
|
129
|
+
}`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
},
|
|
60
136
|
],
|
|
61
137
|
});
|
|
62
138
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeFileSync } from "fs";
|
|
1
|
+
import { writeFileSync, mkdirSync } from "fs";
|
|
2
2
|
import { runInTempDir } from "../../src/__tests__/helpers/run-in-tmp";
|
|
3
3
|
import { toUrlPath } from "../../src/paths";
|
|
4
4
|
import { compareRoutes, generateConfigFromFileTree } from "./filepath-routing";
|
|
@@ -83,34 +83,144 @@ describe("filepath-routing", () => {
|
|
|
83
83
|
`
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
+
mkdirSync("todos");
|
|
87
|
+
|
|
88
|
+
writeFileSync(
|
|
89
|
+
"todos/[id].ts",
|
|
90
|
+
`
|
|
91
|
+
export function onRequestPost() {}
|
|
92
|
+
export function onRequestDelete() {}
|
|
93
|
+
`
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
mkdirSync("authors");
|
|
97
|
+
mkdirSync("authors/[authorId]");
|
|
98
|
+
mkdirSync("authors/[authorId]/todos");
|
|
99
|
+
|
|
100
|
+
writeFileSync(
|
|
101
|
+
"authors/[authorId]/todos/[todoId].ts",
|
|
102
|
+
`
|
|
103
|
+
export function onRequestPost() {}
|
|
104
|
+
`
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
mkdirSync("books");
|
|
108
|
+
|
|
109
|
+
writeFileSync(
|
|
110
|
+
"books/[[title]].ts",
|
|
111
|
+
`
|
|
112
|
+
export function onRequestPost() {}
|
|
113
|
+
`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
mkdirSync("cats");
|
|
117
|
+
mkdirSync("cats/[[breed]]");
|
|
118
|
+
|
|
119
|
+
writeFileSync(
|
|
120
|
+
"cats/[[breed]]/blah.ts",
|
|
121
|
+
`
|
|
122
|
+
export function onRequestPost() {}
|
|
123
|
+
`
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// This won't actually work at runtime.
|
|
127
|
+
writeFileSync(
|
|
128
|
+
"cats/[[breed]]/[[name]].ts",
|
|
129
|
+
`
|
|
130
|
+
export function onRequestPost() {}
|
|
131
|
+
`
|
|
132
|
+
);
|
|
133
|
+
|
|
86
134
|
const entries = await generateConfigFromFileTree({
|
|
87
135
|
baseDir: ".",
|
|
88
136
|
baseURL: "/base" as UrlPath,
|
|
89
137
|
});
|
|
90
|
-
expect(entries).
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
expect(entries).toMatchInlineSnapshot(`
|
|
139
|
+
Object {
|
|
140
|
+
"routes": Array [
|
|
141
|
+
Object {
|
|
142
|
+
"method": "POST",
|
|
143
|
+
"module": Array [
|
|
144
|
+
"authors/[authorId]/todos/[todoId].ts:onRequestPost",
|
|
145
|
+
],
|
|
146
|
+
"mountPath": "/base/authors/:authorId/todos",
|
|
147
|
+
"routePath": "/base/authors/:authorId/todos/:todoId",
|
|
148
|
+
},
|
|
149
|
+
Object {
|
|
150
|
+
"method": "POST",
|
|
151
|
+
"module": Array [
|
|
152
|
+
"cats/[[breed]]/blah.ts:onRequestPost",
|
|
153
|
+
],
|
|
154
|
+
"mountPath": "/base/cats/:breed*",
|
|
155
|
+
"routePath": "/base/cats/:breed*/blah",
|
|
156
|
+
},
|
|
157
|
+
Object {
|
|
158
|
+
"method": "POST",
|
|
159
|
+
"module": Array [
|
|
160
|
+
"cats/[[breed]]/[[name]].ts:onRequestPost",
|
|
161
|
+
],
|
|
162
|
+
"mountPath": "/base/cats/:breed*",
|
|
163
|
+
"routePath": "/base/cats/:breed*/:name*",
|
|
164
|
+
},
|
|
165
|
+
Object {
|
|
166
|
+
"method": "DELETE",
|
|
167
|
+
"module": Array [
|
|
168
|
+
"todos/[id].ts:onRequestDelete",
|
|
169
|
+
],
|
|
170
|
+
"mountPath": "/base/todos",
|
|
171
|
+
"routePath": "/base/todos/:id",
|
|
172
|
+
},
|
|
173
|
+
Object {
|
|
174
|
+
"method": "POST",
|
|
175
|
+
"module": Array [
|
|
176
|
+
"todos/[id].ts:onRequestPost",
|
|
177
|
+
],
|
|
178
|
+
"mountPath": "/base/todos",
|
|
179
|
+
"routePath": "/base/todos/:id",
|
|
180
|
+
},
|
|
181
|
+
Object {
|
|
182
|
+
"method": "POST",
|
|
183
|
+
"module": Array [
|
|
184
|
+
"books/[[title]].ts:onRequestPost",
|
|
185
|
+
],
|
|
186
|
+
"mountPath": "/base/books",
|
|
187
|
+
"routePath": "/base/books/:title*",
|
|
188
|
+
},
|
|
189
|
+
Object {
|
|
190
|
+
"method": "DELETE",
|
|
191
|
+
"module": Array [
|
|
192
|
+
"bar.ts:onRequestDelete",
|
|
193
|
+
],
|
|
194
|
+
"mountPath": "/base/",
|
|
195
|
+
"routePath": "/base/bar",
|
|
196
|
+
},
|
|
197
|
+
Object {
|
|
198
|
+
"method": "PUT",
|
|
199
|
+
"module": Array [
|
|
200
|
+
"bar.ts:onRequestPut",
|
|
201
|
+
],
|
|
202
|
+
"mountPath": "/base/",
|
|
203
|
+
"routePath": "/base/bar",
|
|
204
|
+
},
|
|
205
|
+
Object {
|
|
206
|
+
"method": "GET",
|
|
207
|
+
"module": Array [
|
|
208
|
+
"foo.ts:onRequestGet",
|
|
209
|
+
],
|
|
210
|
+
"mountPath": "/base/",
|
|
211
|
+
"routePath": "/base/foo",
|
|
212
|
+
},
|
|
213
|
+
Object {
|
|
214
|
+
"method": "POST",
|
|
215
|
+
"module": Array [
|
|
216
|
+
"foo.ts:onRequestPost",
|
|
217
|
+
],
|
|
218
|
+
"mountPath": "/base/",
|
|
219
|
+
"routePath": "/base/foo",
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
}
|
|
223
|
+
`);
|
|
114
224
|
});
|
|
115
225
|
});
|
|
116
226
|
});
|
|
@@ -118,6 +228,7 @@ describe("filepath-routing", () => {
|
|
|
118
228
|
function routeConfig(routePath: string, method?: string): RouteConfig {
|
|
119
229
|
return {
|
|
120
230
|
routePath: toUrlPath(routePath),
|
|
231
|
+
mountPath: toUrlPath("/"),
|
|
121
232
|
method: method as HTTPMethod,
|
|
122
233
|
};
|
|
123
234
|
}
|
|
@@ -53,6 +53,7 @@ export async function generateConfigFromFileTree({
|
|
|
53
53
|
let routePath = path
|
|
54
54
|
.relative(baseDir, filepath)
|
|
55
55
|
.slice(0, -ext.length);
|
|
56
|
+
let mountPath = path.dirname(routePath);
|
|
56
57
|
|
|
57
58
|
if (isIndexFile || isMiddlewareFile) {
|
|
58
59
|
routePath = path.dirname(routePath);
|
|
@@ -61,17 +62,27 @@ export async function generateConfigFromFileTree({
|
|
|
61
62
|
if (routePath === ".") {
|
|
62
63
|
routePath = "";
|
|
63
64
|
}
|
|
65
|
+
if (mountPath === ".") {
|
|
66
|
+
mountPath = "";
|
|
67
|
+
}
|
|
64
68
|
|
|
65
69
|
routePath = `${baseURL}/${routePath}`;
|
|
70
|
+
mountPath = `${baseURL}/${mountPath}`;
|
|
71
|
+
|
|
72
|
+
routePath = routePath.replace(/\[\[([^\]]+)\]\]/g, ":$1*"); // transform [[id]] => :id*
|
|
73
|
+
routePath = routePath.replaceAll(/\[([^\]]+)\]/g, ":$1"); // transform [id] => :id
|
|
74
|
+
mountPath = mountPath.replace(/\[\[([^\]]+)\]\]/g, ":$1*"); // transform [[id]] => :id*
|
|
75
|
+
mountPath = mountPath.replaceAll(/\[([^\]]+)\]/g, ":$1"); // transform [id] => :id
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
// These are used as module specifiers so UrlPaths are okay to use even on Windows
|
|
78
|
+
const modulePath = toUrlPath(path.relative(baseDir, filepath));
|
|
69
79
|
|
|
70
80
|
const routeEntry: RouteConfig = {
|
|
71
81
|
routePath: toUrlPath(routePath),
|
|
82
|
+
mountPath: toUrlPath(mountPath),
|
|
72
83
|
method: method.toUpperCase() as HTTPMethod,
|
|
73
84
|
[isMiddlewareFile ? "middleware" : "module"]: [
|
|
74
|
-
`${
|
|
85
|
+
`${modulePath}:${exportName}`,
|
|
75
86
|
],
|
|
76
87
|
};
|
|
77
88
|
|
|
@@ -21,6 +21,7 @@ export function isHTTPMethod(
|
|
|
21
21
|
|
|
22
22
|
export type RoutesCollection = Array<{
|
|
23
23
|
routePath: UrlPath;
|
|
24
|
+
mountPath: UrlPath;
|
|
24
25
|
method?: HTTPMethod;
|
|
25
26
|
modules: string[];
|
|
26
27
|
middlewares: string[];
|
|
@@ -33,6 +34,7 @@ export type Config = {
|
|
|
33
34
|
|
|
34
35
|
export type RouteConfig = {
|
|
35
36
|
routePath: UrlPath;
|
|
37
|
+
mountPath: UrlPath;
|
|
36
38
|
method?: HTTPMethod;
|
|
37
39
|
middleware?: string | string[];
|
|
38
40
|
module?: string | string[];
|
|
@@ -113,9 +115,11 @@ export function parseConfig(config: Config, baseDir: string) {
|
|
|
113
115
|
});
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
for (const { routePath, method, ...props } of config.routes ??
|
|
118
|
+
for (const { routePath, mountPath, method, ...props } of config.routes ??
|
|
119
|
+
[]) {
|
|
117
120
|
routes.push({
|
|
118
121
|
routePath,
|
|
122
|
+
mountPath,
|
|
119
123
|
method,
|
|
120
124
|
middlewares: parseModuleIdentifiers(props.middleware),
|
|
121
125
|
modules: parseModuleIdentifiers(props.module),
|
|
@@ -141,6 +145,7 @@ export const routes = [
|
|
|
141
145
|
.map(
|
|
142
146
|
(route) => ` {
|
|
143
147
|
routePath: "${route.routePath}",
|
|
148
|
+
mountPath: "${route.mountPath}",
|
|
144
149
|
method: "${route.method}",
|
|
145
150
|
middlewares: [${route.middlewares.join(", ")}],
|
|
146
151
|
modules: [${route.modules.join(", ")}],
|