wrangler 0.0.0-e88a54e → 0.0.0-e8e684c7
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/Cloudflare_CA.pem +18 -0
- package/README.md +51 -14
- package/bin/wrangler.js +161 -29
- package/kv-asset-handler.js +1 -0
- package/miniflare-dist/index.mjs +5484 -21
- package/package.json +173 -143
- package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
- package/src/__tests__/config-cache.test.ts +42 -0
- package/src/__tests__/configuration.test.ts +4016 -2786
- package/src/__tests__/dev.test.tsx +1305 -483
- package/src/__tests__/generate.test.ts +91 -0
- package/src/__tests__/guess-worker-format.test.ts +75 -48
- package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
- package/src/__tests__/helpers/mock-account-id.ts +24 -24
- package/src/__tests__/helpers/mock-bin.ts +20 -20
- package/src/__tests__/helpers/mock-cfetch.ts +182 -93
- package/src/__tests__/helpers/mock-console.ts +59 -32
- package/src/__tests__/helpers/mock-dialogs.ts +121 -33
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +74 -0
- package/src/__tests__/helpers/mock-known-routes.ts +7 -0
- package/src/__tests__/helpers/mock-kv.ts +26 -26
- package/src/__tests__/helpers/mock-oauth-flow.ts +250 -0
- package/src/__tests__/helpers/mock-process.ts +39 -0
- package/src/__tests__/helpers/mock-stdin.ts +82 -77
- package/src/__tests__/helpers/mock-web-socket.ts +21 -21
- package/src/__tests__/helpers/run-in-tmp.ts +28 -22
- package/src/__tests__/helpers/run-wrangler.ts +8 -8
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
- package/src/__tests__/https-options.test.ts +144 -108
- package/src/__tests__/index.test.ts +229 -975
- package/src/__tests__/init.test.ts +2170 -0
- package/src/__tests__/jest.setup.ts +122 -34
- package/src/__tests__/kv.test.ts +1376 -1087
- package/src/__tests__/logger.test.ts +141 -0
- package/src/__tests__/metrics.test.ts +450 -0
- package/src/__tests__/package-manager.test.ts +312 -165
- package/src/__tests__/pages.test.ts +1270 -39
- package/src/__tests__/parse.test.ts +253 -245
- package/src/__tests__/publish.test.ts +6878 -2627
- package/src/__tests__/pubsub.test.ts +367 -0
- package/src/__tests__/r2.test.ts +328 -190
- package/src/__tests__/route.test.ts +22 -22
- package/src/__tests__/secret.test.ts +474 -407
- package/src/__tests__/tail.test.ts +679 -441
- package/src/__tests__/test-old-node-version.js +31 -0
- package/src/__tests__/user.test.ts +155 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/version.test.ts +35 -0
- package/src/__tests__/whoami.test.tsx +276 -87
- package/src/__tests__/worker-namespace.test.ts +329 -0
- package/src/abort.d.ts +3 -0
- package/src/api/dev.ts +93 -0
- package/src/api/index.ts +1 -0
- package/src/bundle-reporter.tsx +29 -0
- package/src/bundle.ts +441 -110
- package/src/cfetch/index.ts +83 -66
- package/src/cfetch/internal.ts +251 -92
- package/src/cli.ts +22 -14
- package/src/config/README.md +1 -1
- package/src/config/config.ts +224 -179
- package/src/config/diagnostics.ts +61 -61
- package/src/config/environment.ts +430 -311
- package/src/config/index.ts +227 -38
- package/src/config/validation-helpers.ts +414 -303
- package/src/config/validation.ts +1745 -973
- package/src/config-cache.ts +85 -0
- package/src/create-worker-preview.ts +209 -118
- package/src/create-worker-upload-form.ts +275 -201
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +488 -307
- package/src/dev/local.tsx +427 -210
- package/src/dev/remote.tsx +407 -188
- package/src/dev/use-esbuild.ts +156 -78
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +160 -0
- package/src/dev.tsx +696 -0
- package/src/dialogs.tsx +115 -57
- package/src/dispatch-namespace.ts +206 -0
- package/src/durable.ts +102 -0
- package/src/entry.ts +267 -147
- package/src/environment-variables.ts +25 -23
- package/src/errors.ts +11 -0
- package/src/faye-websocket.d.ts +6 -0
- package/src/generate.ts +131 -0
- package/src/git-client.ts +42 -0
- package/src/global-wrangler-config-path.ts +26 -0
- package/src/https-options.ts +85 -80
- package/src/index.tsx +2191 -2304
- package/src/init.ts +622 -0
- package/src/inspect.ts +687 -557
- package/src/intl-polyfill.d.ts +139 -0
- package/src/is-ci.ts +14 -0
- package/src/is-interactive.ts +12 -0
- package/src/kv.ts +353 -242
- package/src/logger.ts +73 -0
- package/src/metrics/index.ts +5 -0
- package/src/metrics/metrics-config.ts +239 -0
- package/src/metrics/metrics-dispatcher.ts +96 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +92 -0
- package/src/miniflare-cli/assets.ts +554 -0
- package/src/miniflare-cli/enum-keys.ts +8 -8
- package/src/miniflare-cli/index.ts +199 -29
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +213 -213
- package/src/open-in-browser.ts +8 -16
- package/src/package-manager.ts +183 -90
- package/src/pages/build.tsx +238 -0
- package/src/pages/constants.ts +12 -0
- package/src/pages/deployments.tsx +106 -0
- package/src/pages/dev.tsx +528 -0
- package/src/pages/errors.ts +22 -0
- package/src/pages/functions/buildPlugin.ts +109 -0
- package/src/pages/functions/buildWorker.ts +155 -0
- package/src/pages/functions/filepath-routing.test.ts +234 -0
- package/src/pages/functions/filepath-routing.ts +189 -0
- package/src/pages/functions/identifiers.ts +78 -0
- package/src/pages/functions/routes-consolidation.test.ts +250 -0
- package/src/pages/functions/routes-consolidation.ts +73 -0
- package/src/pages/functions/routes-transformation.test.ts +271 -0
- package/src/pages/functions/routes-transformation.ts +122 -0
- package/src/pages/functions/routes.ts +151 -0
- package/src/pages/functions.tsx +96 -0
- package/src/pages/index.tsx +94 -0
- package/src/pages/projects.tsx +169 -0
- package/src/pages/publish.tsx +391 -0
- package/src/pages/types.ts +49 -0
- package/src/pages/upload.tsx +413 -0
- package/src/pages/utils.ts +12 -0
- package/src/parse.ts +224 -121
- package/src/paths.ts +6 -6
- package/src/preview.ts +31 -0
- package/src/proxy.ts +416 -370
- package/src/publish.ts +796 -321
- package/src/pubsub/index.ts +286 -0
- package/src/pubsub/pubsub-commands.tsx +623 -0
- package/src/r2.ts +100 -19
- package/src/selfsigned.d.ts +23 -23
- package/src/sites.tsx +281 -189
- package/src/tail/filters.ts +111 -109
- package/src/tail/index.ts +230 -217
- package/src/tail/printing.ts +92 -47
- package/src/update-check.ts +19 -0
- package/src/user/choose-account.tsx +69 -0
- package/src/user/env-vars.ts +46 -0
- package/src/user/generate-auth-url.ts +33 -0
- package/src/user/generate-random-state.ts +16 -0
- package/src/user/index.ts +3 -0
- package/src/user/user.tsx +1191 -0
- package/src/whoami.tsx +142 -42
- package/src/worker.ts +135 -94
- package/src/zones.ts +167 -0
- package/templates/checked-fetch.js +17 -0
- package/templates/first-party-worker-module-facade.ts +18 -0
- package/templates/format-dev-errors.ts +32 -0
- package/templates/gitignore +171 -0
- package/templates/new-worker-scheduled.js +17 -0
- package/templates/new-worker-scheduled.ts +32 -0
- package/templates/new-worker.js +3 -3
- package/templates/new-worker.ts +18 -3
- package/templates/no-op-worker.js +10 -0
- package/templates/pages-shim.ts +9 -0
- package/templates/pages-template-plugin.ts +167 -0
- package/templates/pages-template-worker.ts +172 -0
- package/templates/serve-static-assets.ts +63 -0
- package/templates/service-bindings-module-facade.js +54 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/templates/tsconfig.json +95 -95
- package/wrangler-dist/cli.d.ts +338 -0
- package/wrangler-dist/cli.js +124611 -112403
- package/miniflare-dist/index.mjs.map +0 -7
- package/pages/functions/buildWorker.ts +0 -62
- package/pages/functions/filepath-routing.test.ts +0 -223
- package/pages/functions/filepath-routing.ts +0 -181
- package/pages/functions/identifiers.ts +0 -78
- package/pages/functions/routes.ts +0 -151
- package/pages/functions/template-worker.ts +0 -130
- package/src/__tests__/dev2.test.tsx +0 -154
- package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
- package/src/__tests__/logout.test.ts +0 -52
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/pages.tsx +0 -1047
- package/src/reporting.ts +0 -131
- package/src/user.tsx +0 -1118
- package/templates/static-asset-facade.js +0 -47
- package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
- package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
- package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
- package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
- package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
- package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
- package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
- package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
- package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
- package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
- package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
- package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
- package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
- package/vendor/wrangler-mime/CHANGELOG.md +0 -289
- package/vendor/wrangler-mime/LICENSE +0 -21
- package/vendor/wrangler-mime/Mime.js +0 -97
- package/vendor/wrangler-mime/README.md +0 -187
- package/vendor/wrangler-mime/cli.js +0 -46
- package/vendor/wrangler-mime/index.js +0 -4
- package/vendor/wrangler-mime/lite.js +0 -4
- package/vendor/wrangler-mime/package.json +0 -52
- package/vendor/wrangler-mime/types/other.js +0 -1
- package/vendor/wrangler-mime/types/standard.js +0 -1
- package/wrangler-dist/cli.js.map +0 -7
|
@@ -9,22 +9,24 @@ import type { Environment, RawEnvironment } from "./environment";
|
|
|
9
9
|
* The `fieldPath` is a dot separated property path, e.g. `"build.upload.format"`.
|
|
10
10
|
*/
|
|
11
11
|
export function deprecated<T extends object>(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
diagnostics: Diagnostics,
|
|
13
|
+
config: T,
|
|
14
|
+
fieldPath: DeepKeyOf<T>,
|
|
15
|
+
message: string,
|
|
16
|
+
remove: boolean,
|
|
17
|
+
title = "Deprecation",
|
|
18
|
+
type: "warning" | "error" = "warning"
|
|
18
19
|
): void {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const BOLD = "\x1b[1m";
|
|
21
|
+
const NORMAL = "\x1b[0m";
|
|
22
|
+
const diagnosticMessage = `${BOLD}${title}${NORMAL}: "${fieldPath}":\n${message}`;
|
|
23
|
+
const result = unwindPropertyPath(config, fieldPath);
|
|
24
|
+
if (result !== undefined && result.field in result.container) {
|
|
25
|
+
diagnostics[`${type}s`].push(diagnosticMessage);
|
|
26
|
+
if (remove) {
|
|
27
|
+
delete (result.container as Record<string, unknown>)[result.field];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -34,16 +36,16 @@ export function deprecated<T extends object>(
|
|
|
34
36
|
* The `fieldPath` is a dot separated property path, e.g. `"build.upload.format"`.
|
|
35
37
|
*/
|
|
36
38
|
export function experimental<T extends object>(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
diagnostics: Diagnostics,
|
|
40
|
+
config: T,
|
|
41
|
+
fieldPath: DeepKeyOf<T>
|
|
40
42
|
): void {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const result = unwindPropertyPath(config, fieldPath);
|
|
44
|
+
if (result !== undefined && result.field in result.container) {
|
|
45
|
+
diagnostics.warnings.push(
|
|
46
|
+
`"${fieldPath}" fields are experimental and may change or break at any time.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
/**
|
|
@@ -53,65 +55,83 @@ export function experimental<T extends object>(
|
|
|
53
55
|
* and then the `defaultValue`.
|
|
54
56
|
*/
|
|
55
57
|
export function inheritable<K extends keyof Environment>(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
diagnostics: Diagnostics,
|
|
59
|
+
topLevelEnv: Environment | undefined,
|
|
60
|
+
rawEnv: RawEnvironment,
|
|
61
|
+
field: K,
|
|
62
|
+
validate: ValidatorFn,
|
|
63
|
+
defaultValue: Environment[K],
|
|
64
|
+
transformFn: TransformFn<Environment[K]> = (v) => v
|
|
62
65
|
): Environment[K] {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
validate(diagnostics, field, rawEnv[field], topLevelEnv);
|
|
67
|
+
return (
|
|
68
|
+
(rawEnv[field] as Environment[K]) ??
|
|
69
|
+
transformFn(topLevelEnv?.[field]) ??
|
|
70
|
+
defaultValue
|
|
71
|
+
);
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
/**
|
|
70
75
|
* Get an inheritable environment field, but only if we are in legacy environments
|
|
71
76
|
*/
|
|
72
77
|
export function inheritableInLegacyEnvironments<K extends keyof Environment>(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
diagnostics: Diagnostics,
|
|
79
|
+
isLegacyEnv: boolean | undefined,
|
|
80
|
+
topLevelEnv: Environment | undefined,
|
|
81
|
+
rawEnv: RawEnvironment,
|
|
82
|
+
field: K,
|
|
83
|
+
validate: ValidatorFn,
|
|
84
|
+
transformFn: TransformFn<Environment[K]> = (v) => v,
|
|
85
|
+
defaultValue: Environment[K]
|
|
80
86
|
): Environment[K] {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
return topLevelEnv === undefined || isLegacyEnv === true
|
|
88
|
+
? inheritable(
|
|
89
|
+
diagnostics,
|
|
90
|
+
topLevelEnv,
|
|
91
|
+
rawEnv,
|
|
92
|
+
field,
|
|
93
|
+
validate,
|
|
94
|
+
defaultValue,
|
|
95
|
+
transformFn
|
|
96
|
+
)
|
|
97
|
+
: notAllowedInNamedServiceEnvironment(
|
|
98
|
+
diagnostics,
|
|
99
|
+
topLevelEnv,
|
|
100
|
+
rawEnv,
|
|
101
|
+
field
|
|
102
|
+
);
|
|
96
103
|
}
|
|
97
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Type of function that is used to transform an inheritable environment field.
|
|
107
|
+
*/
|
|
108
|
+
type TransformFn<T> = (fieldValue: T | undefined) => T | undefined;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Transform an environment field by appending current environment name to it.
|
|
112
|
+
*/
|
|
113
|
+
export const appendEnvName =
|
|
114
|
+
(envName: string): TransformFn<string | undefined> =>
|
|
115
|
+
(fieldValue) =>
|
|
116
|
+
fieldValue ? `${fieldValue}-${envName}` : undefined;
|
|
117
|
+
|
|
98
118
|
/**
|
|
99
119
|
* Log an error if this named environment is trying to override the value in the top-level
|
|
100
120
|
* environment, which is not allow for this field.
|
|
101
121
|
*/
|
|
102
122
|
function notAllowedInNamedServiceEnvironment<K extends keyof Environment>(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
diagnostics: Diagnostics,
|
|
124
|
+
topLevelEnv: Environment,
|
|
125
|
+
rawEnv: RawEnvironment,
|
|
126
|
+
field: K
|
|
107
127
|
): Environment[K] {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
128
|
+
if (field in rawEnv) {
|
|
129
|
+
diagnostics.errors.push(
|
|
130
|
+
`The "${field}" field is not allowed in named service environments.\n` +
|
|
131
|
+
`Please remove the field from this environment.`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return topLevelEnv[field];
|
|
115
135
|
}
|
|
116
136
|
|
|
117
137
|
/**
|
|
@@ -121,39 +141,39 @@ function notAllowedInNamedServiceEnvironment<K extends keyof Environment>(
|
|
|
121
141
|
* then log a warning and return the `defaultValue`.
|
|
122
142
|
*/
|
|
123
143
|
export function notInheritable<K extends keyof Environment>(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
144
|
+
diagnostics: Diagnostics,
|
|
145
|
+
topLevelEnv: Environment | undefined,
|
|
146
|
+
rawConfig: RawConfig | undefined,
|
|
147
|
+
rawEnv: RawEnvironment,
|
|
148
|
+
envName: string,
|
|
149
|
+
field: K,
|
|
150
|
+
validate: ValidatorFn,
|
|
151
|
+
defaultValue: Environment[K]
|
|
132
152
|
): Environment[K] {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
if (rawEnv[field] !== undefined) {
|
|
154
|
+
validate(diagnostics, field, rawEnv[field], topLevelEnv);
|
|
155
|
+
} else {
|
|
156
|
+
if (rawConfig?.[field] !== undefined) {
|
|
157
|
+
diagnostics.warnings.push(
|
|
158
|
+
`"${field}" exists at the top level, but not on "env.${envName}".\n` +
|
|
159
|
+
`This is not what you probably want, since "${field}" is not inherited by environments.\n` +
|
|
160
|
+
`Please add "${field}" to "env.${envName}".`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return (rawEnv[field] as Environment[K]) ?? defaultValue;
|
|
145
165
|
}
|
|
146
166
|
|
|
147
167
|
// Idea taken from https://stackoverflow.com/a/66661477
|
|
148
168
|
type DeepKeyOf<T> = (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
169
|
+
T extends object
|
|
170
|
+
? {
|
|
171
|
+
[K in Exclude<keyof T, symbol>]: `${K}${DotPrefix<DeepKeyOf<T[K]>>}`;
|
|
172
|
+
}[Exclude<keyof T, symbol>]
|
|
173
|
+
: ""
|
|
154
174
|
) extends infer D
|
|
155
|
-
|
|
156
|
-
|
|
175
|
+
? Extract<D, string>
|
|
176
|
+
: never;
|
|
157
177
|
|
|
158
178
|
type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;
|
|
159
179
|
|
|
@@ -168,117 +188,145 @@ type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;
|
|
|
168
188
|
* ```
|
|
169
189
|
*/
|
|
170
190
|
function unwindPropertyPath<T extends object>(
|
|
171
|
-
|
|
172
|
-
|
|
191
|
+
root: T,
|
|
192
|
+
path: DeepKeyOf<T>
|
|
173
193
|
): { container: object; field: string } | undefined {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
let container: object = root;
|
|
195
|
+
const parts = (path as string).split(".");
|
|
196
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
197
|
+
if (!hasProperty(container, parts[i])) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
container = container[parts[i]];
|
|
201
|
+
}
|
|
202
|
+
return { container, field: parts[parts.length - 1] };
|
|
183
203
|
}
|
|
184
204
|
|
|
185
205
|
/**
|
|
186
206
|
* The type of a function that can be used to validate a configuration field.
|
|
187
207
|
*/
|
|
188
208
|
export type ValidatorFn = (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
209
|
+
diagnostics: Diagnostics,
|
|
210
|
+
field: string,
|
|
211
|
+
value: unknown,
|
|
212
|
+
topLevelEnv: Environment | undefined
|
|
193
213
|
) => boolean;
|
|
194
214
|
|
|
195
215
|
/**
|
|
196
216
|
* Validate that the field is a string.
|
|
197
217
|
*/
|
|
198
218
|
export const isString: ValidatorFn = (diagnostics, field, value) => {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
219
|
+
if (value !== undefined && typeof value !== "string") {
|
|
220
|
+
diagnostics.errors.push(
|
|
221
|
+
`Expected "${field}" to be of type string but got ${JSON.stringify(
|
|
222
|
+
value
|
|
223
|
+
)}.`
|
|
224
|
+
);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Validate that the `name` field is compliant with EWC constraints.
|
|
232
|
+
*/
|
|
233
|
+
export const isValidName: ValidatorFn = (diagnostics, field, value) => {
|
|
234
|
+
if (
|
|
235
|
+
(typeof value === "string" && /^$|^[a-z0-9_ ][a-z0-9-_ ]*$/.test(value)) ||
|
|
236
|
+
value === undefined
|
|
237
|
+
) {
|
|
238
|
+
return true;
|
|
239
|
+
} else {
|
|
240
|
+
diagnostics.errors.push(
|
|
241
|
+
`Expected "${field}" to be of type string, alphanumeric and lowercase with dashes only but got ${JSON.stringify(
|
|
242
|
+
value
|
|
243
|
+
)}.`
|
|
244
|
+
);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
208
247
|
};
|
|
209
248
|
|
|
210
249
|
/**
|
|
211
250
|
* Validate that the field is an array of strings.
|
|
212
251
|
*/
|
|
213
252
|
export const isStringArray: ValidatorFn = (diagnostics, field, value) => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
253
|
+
if (
|
|
254
|
+
value !== undefined &&
|
|
255
|
+
(!Array.isArray(value) || value.some((item) => typeof item !== "string"))
|
|
256
|
+
) {
|
|
257
|
+
diagnostics.errors.push(
|
|
258
|
+
`Expected "${field}" to be of type string array but got ${JSON.stringify(
|
|
259
|
+
value
|
|
260
|
+
)}.`
|
|
261
|
+
);
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
226
265
|
};
|
|
227
266
|
|
|
228
267
|
/**
|
|
229
268
|
* Validate that the field is an object containing the given properties.
|
|
230
269
|
*/
|
|
231
270
|
export const isObjectWith =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
271
|
+
(...properties: string[]): ValidatorFn =>
|
|
272
|
+
(diagnostics, field, value) => {
|
|
273
|
+
if (
|
|
274
|
+
value !== undefined &&
|
|
275
|
+
(typeof value !== "object" ||
|
|
276
|
+
value === null ||
|
|
277
|
+
!properties.every((prop) => prop in value))
|
|
278
|
+
) {
|
|
279
|
+
diagnostics.errors.push(
|
|
280
|
+
`Expected "${field}" to be of type object, containing only properties ${properties}, but got ${JSON.stringify(
|
|
281
|
+
value
|
|
282
|
+
)}.`
|
|
283
|
+
);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
// it's an object with the field as desired,
|
|
287
|
+
// but let's also check for unexpected fields
|
|
288
|
+
if (value !== undefined) {
|
|
289
|
+
const restFields = Object.keys(value).filter(
|
|
290
|
+
(key) => !properties.includes(key)
|
|
291
|
+
);
|
|
292
|
+
validateAdditionalProperties(diagnostics, field, restFields, []);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return true;
|
|
296
|
+
};
|
|
249
297
|
|
|
250
298
|
/**
|
|
251
299
|
* Validate that the field value is one of the given choices.
|
|
252
300
|
*/
|
|
253
301
|
export const isOneOf =
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
302
|
+
(...choices: unknown[]): ValidatorFn =>
|
|
303
|
+
(diagnostics, field, value) => {
|
|
304
|
+
if (value !== undefined && !choices.some((choice) => value === choice)) {
|
|
305
|
+
diagnostics.errors.push(
|
|
306
|
+
`Expected "${field}" field to be one of ${JSON.stringify(
|
|
307
|
+
choices
|
|
308
|
+
)} but got ${JSON.stringify(value)}.`
|
|
309
|
+
);
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
return true;
|
|
313
|
+
};
|
|
266
314
|
|
|
267
315
|
/**
|
|
268
316
|
* Aggregate multiple validator functions
|
|
269
317
|
*/
|
|
270
318
|
export const all = (...validations: ValidatorFn[]): ValidatorFn => {
|
|
271
|
-
|
|
272
|
-
|
|
319
|
+
return (diagnostics, field, value, config) => {
|
|
320
|
+
let passedValidations = true;
|
|
273
321
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
322
|
+
for (const validate of validations) {
|
|
323
|
+
if (!validate(diagnostics, field, value, config)) {
|
|
324
|
+
passedValidations = false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
279
327
|
|
|
280
|
-
|
|
281
|
-
|
|
328
|
+
return passedValidations;
|
|
329
|
+
};
|
|
282
330
|
};
|
|
283
331
|
|
|
284
332
|
/**
|
|
@@ -288,199 +336,262 @@ export const all = (...validations: ValidatorFn[]): ValidatorFn => {
|
|
|
288
336
|
* @param fields the names of the fields to check against.
|
|
289
337
|
*/
|
|
290
338
|
export const isMutuallyExclusiveWith = <T extends RawEnvironment | RawConfig>(
|
|
291
|
-
|
|
292
|
-
|
|
339
|
+
container: T,
|
|
340
|
+
...fields: (keyof T)[]
|
|
293
341
|
): ValidatorFn => {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
342
|
+
return (diagnostics, field, value) => {
|
|
343
|
+
if (value === undefined) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
for (const exclusiveWith of fields) {
|
|
348
|
+
if (container[exclusiveWith] !== undefined) {
|
|
349
|
+
diagnostics.errors.push(
|
|
350
|
+
`Expected exactly one of the following fields ${JSON.stringify([
|
|
351
|
+
field,
|
|
352
|
+
...fields,
|
|
353
|
+
])}.`
|
|
354
|
+
);
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return true;
|
|
360
|
+
};
|
|
313
361
|
};
|
|
314
362
|
|
|
315
363
|
/**
|
|
316
364
|
* Validate that the field is a boolean.
|
|
317
365
|
*/
|
|
318
366
|
export const isBoolean: ValidatorFn = (diagnostics, field, value) => {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
367
|
+
if (value !== undefined && typeof value !== "boolean") {
|
|
368
|
+
diagnostics.errors.push(
|
|
369
|
+
`Expected "${field}" to be of type boolean but got ${JSON.stringify(
|
|
370
|
+
value
|
|
371
|
+
)}.`
|
|
372
|
+
);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return true;
|
|
328
376
|
};
|
|
329
377
|
|
|
330
378
|
/**
|
|
331
379
|
* Validate that the required field exists and has the expected type.
|
|
332
380
|
*/
|
|
333
381
|
export const validateRequiredProperty = (
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
382
|
+
diagnostics: Diagnostics,
|
|
383
|
+
container: string,
|
|
384
|
+
key: string,
|
|
385
|
+
value: unknown,
|
|
386
|
+
type: TypeofType,
|
|
387
|
+
choices?: unknown[]
|
|
340
388
|
): boolean => {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
389
|
+
if (container) {
|
|
390
|
+
container += ".";
|
|
391
|
+
}
|
|
392
|
+
if (value === undefined) {
|
|
393
|
+
diagnostics.errors.push(`"${container}${key}" is a required field.`);
|
|
394
|
+
return false;
|
|
395
|
+
} else if (typeof value !== type) {
|
|
396
|
+
diagnostics.errors.push(
|
|
397
|
+
`Expected "${container}${key}" to be of type ${type} but got ${JSON.stringify(
|
|
398
|
+
value
|
|
399
|
+
)}.`
|
|
400
|
+
);
|
|
401
|
+
return false;
|
|
402
|
+
} else if (choices) {
|
|
403
|
+
if (
|
|
404
|
+
!isOneOf(...choices)(diagnostics, `${container}${key}`, value, undefined)
|
|
405
|
+
) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return true;
|
|
362
410
|
};
|
|
363
411
|
|
|
364
412
|
/**
|
|
365
413
|
* Validate that, if the optional field exists, then it has the expected type.
|
|
366
414
|
*/
|
|
367
415
|
export const validateOptionalProperty = (
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
416
|
+
diagnostics: Diagnostics,
|
|
417
|
+
container: string,
|
|
418
|
+
key: string,
|
|
419
|
+
value: unknown,
|
|
420
|
+
type: TypeofType,
|
|
421
|
+
choices?: unknown[]
|
|
374
422
|
): boolean => {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
423
|
+
if (value !== undefined) {
|
|
424
|
+
return validateRequiredProperty(
|
|
425
|
+
diagnostics,
|
|
426
|
+
container,
|
|
427
|
+
key,
|
|
428
|
+
value,
|
|
429
|
+
type,
|
|
430
|
+
choices
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return true;
|
|
386
434
|
};
|
|
387
435
|
|
|
388
436
|
/**
|
|
389
437
|
* Validate that the field is an array of elements of the given type.
|
|
390
438
|
*/
|
|
391
439
|
export const validateTypedArray = (
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
440
|
+
diagnostics: Diagnostics,
|
|
441
|
+
container: string,
|
|
442
|
+
value: unknown,
|
|
443
|
+
type: TypeofType
|
|
396
444
|
): boolean => {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
445
|
+
let isValid = true;
|
|
446
|
+
if (!Array.isArray(value)) {
|
|
447
|
+
diagnostics.errors.push(
|
|
448
|
+
`Expected "${container}" to be an array of ${type}s but got ${JSON.stringify(
|
|
449
|
+
value
|
|
450
|
+
)}`
|
|
451
|
+
);
|
|
452
|
+
isValid = false;
|
|
453
|
+
} else {
|
|
454
|
+
for (let i = 0; i < value.length; i++) {
|
|
455
|
+
isValid =
|
|
456
|
+
validateRequiredProperty(
|
|
457
|
+
diagnostics,
|
|
458
|
+
container,
|
|
459
|
+
`[${i}]`,
|
|
460
|
+
value[i],
|
|
461
|
+
type
|
|
462
|
+
) && isValid;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return isValid;
|
|
418
466
|
};
|
|
419
467
|
|
|
420
468
|
/**
|
|
421
469
|
* Validate that, if the optional field exists, it is an array of elements of the given type.
|
|
422
470
|
*/
|
|
423
471
|
export const validateOptionalTypedArray = (
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
472
|
+
diagnostics: Diagnostics,
|
|
473
|
+
container: string,
|
|
474
|
+
value: unknown,
|
|
475
|
+
type: TypeofType
|
|
428
476
|
) => {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
477
|
+
if (value !== undefined) {
|
|
478
|
+
return validateTypedArray(diagnostics, container, value, type);
|
|
479
|
+
}
|
|
480
|
+
return true;
|
|
433
481
|
};
|
|
434
482
|
|
|
435
483
|
/**
|
|
436
484
|
* Test to see if `obj` has the required property `prop` of type `type`.
|
|
437
485
|
*/
|
|
438
486
|
export const isRequiredProperty = <T extends object>(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
487
|
+
obj: object,
|
|
488
|
+
prop: keyof T,
|
|
489
|
+
type: TypeofType,
|
|
490
|
+
choices?: unknown[]
|
|
443
491
|
): obj is T =>
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
492
|
+
hasProperty<T>(obj, prop) &&
|
|
493
|
+
typeof obj[prop] === type &&
|
|
494
|
+
(choices === undefined || choices.includes(obj[prop]));
|
|
447
495
|
|
|
448
496
|
/**
|
|
449
497
|
* Test to see if `obj` has the optional property `prop` of type `type`.
|
|
450
498
|
*/
|
|
451
499
|
export const isOptionalProperty = <T extends object>(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
500
|
+
obj: object,
|
|
501
|
+
prop: keyof T,
|
|
502
|
+
type: TypeofType
|
|
455
503
|
): obj is T => !hasProperty<T>(obj, prop) || typeof obj[prop] === type;
|
|
456
504
|
|
|
457
505
|
/**
|
|
458
506
|
* Test to see if `obj` has the property `prop`.
|
|
459
507
|
*/
|
|
460
508
|
export const hasProperty = <T extends object>(
|
|
461
|
-
|
|
462
|
-
|
|
509
|
+
obj: object,
|
|
510
|
+
property: keyof T
|
|
463
511
|
): obj is T => property in obj;
|
|
464
512
|
|
|
465
513
|
/**
|
|
466
514
|
* Add warning messages about any properties in the given field that are not expected to be there.
|
|
467
515
|
*/
|
|
468
516
|
export const validateAdditionalProperties = (
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
517
|
+
diagnostics: Diagnostics,
|
|
518
|
+
fieldPath: string,
|
|
519
|
+
restProps: Iterable<string>,
|
|
520
|
+
knownProps: Iterable<string>
|
|
473
521
|
): boolean => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
522
|
+
const restPropSet = new Set(restProps);
|
|
523
|
+
for (const knownProp of knownProps) {
|
|
524
|
+
restPropSet.delete(knownProp);
|
|
525
|
+
}
|
|
526
|
+
if (restPropSet.size > 0) {
|
|
527
|
+
const fields = Array.from(restPropSet.keys()).map((field) => `"${field}"`);
|
|
528
|
+
diagnostics.warnings.push(
|
|
529
|
+
`Unexpected fields found in ${fieldPath} field: ${fields}`
|
|
530
|
+
);
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
return true;
|
|
486
534
|
};
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Get the names of the bindings collection in `value`.
|
|
538
|
+
*
|
|
539
|
+
* Will return an empty array if it doesn't understand the value
|
|
540
|
+
* passed in, so another form of validation should be
|
|
541
|
+
* performed externally.
|
|
542
|
+
*/
|
|
543
|
+
export const getBindingNames = (value: unknown): string[] => {
|
|
544
|
+
if (typeof value !== "object" || value === null) {
|
|
545
|
+
return [];
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (isBindingList(value)) {
|
|
549
|
+
return value.bindings.map(({ name }) => name);
|
|
550
|
+
} else if (isNamespaceList(value)) {
|
|
551
|
+
return value.map(({ binding }) => binding);
|
|
552
|
+
} else if (isRecord(value)) {
|
|
553
|
+
return Object.keys(value);
|
|
554
|
+
} else {
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const isBindingList = (
|
|
560
|
+
value: unknown
|
|
561
|
+
): value is {
|
|
562
|
+
bindings: {
|
|
563
|
+
name: string;
|
|
564
|
+
}[];
|
|
565
|
+
} =>
|
|
566
|
+
isRecord(value) &&
|
|
567
|
+
"bindings" in value &&
|
|
568
|
+
Array.isArray(value.bindings) &&
|
|
569
|
+
value.bindings.every(
|
|
570
|
+
(binding) =>
|
|
571
|
+
isRecord(binding) && "name" in binding && typeof binding.name === "string"
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
const isNamespaceList = (value: unknown): value is { binding: string }[] =>
|
|
575
|
+
Array.isArray(value) &&
|
|
576
|
+
value.every(
|
|
577
|
+
(entry) =>
|
|
578
|
+
isRecord(entry) && "binding" in entry && typeof entry.binding === "string"
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
const isRecord = (
|
|
582
|
+
value: unknown
|
|
583
|
+
): value is Record<string | number | symbol, unknown> =>
|
|
584
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* JavaScript `typeof` operator return values.
|
|
588
|
+
*/
|
|
589
|
+
type TypeofType =
|
|
590
|
+
| "string"
|
|
591
|
+
| "number"
|
|
592
|
+
| "bigint"
|
|
593
|
+
| "boolean"
|
|
594
|
+
| "symbol"
|
|
595
|
+
| "undefined"
|
|
596
|
+
| "object"
|
|
597
|
+
| "function";
|