wrangler 0.0.0-e043479 → 0.0.0-e0621809
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 +47 -14
- package/bin/wrangler.js +181 -29
- package/kv-asset-handler.js +1 -0
- package/miniflare-dist/index.mjs +6368 -0
- package/package.json +198 -136
- package/src/__tests__/access.test.ts +25 -0
- package/src/__tests__/api-dev.test.ts +238 -0
- package/src/__tests__/api-devregistry.test.js +64 -0
- package/src/__tests__/api.test.ts +80 -0
- 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 +4456 -2178
- package/src/__tests__/d1/d1.test.ts +82 -0
- package/src/__tests__/d1/execute.test.ts +66 -0
- package/src/__tests__/d1/migrate.test.ts +157 -0
- package/src/__tests__/d1/splitter.test.ts +255 -0
- package/src/__tests__/delete.test.ts +272 -0
- package/src/__tests__/deployments.test.ts +369 -0
- package/src/__tests__/dev.test.tsx +1605 -235
- package/src/__tests__/generate.test.ts +238 -0
- package/src/__tests__/get-host-from-url.test.ts +16 -0
- package/src/__tests__/guess-worker-format.test.ts +111 -57
- package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
- package/src/__tests__/helpers/end-event-loop.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +26 -22
- package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
- package/src/__tests__/helpers/mock-bin.ts +20 -20
- package/src/__tests__/helpers/mock-console.ts +74 -32
- package/src/__tests__/helpers/mock-dialogs.ts +107 -33
- package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +11 -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 +12 -0
- package/src/__tests__/helpers/mock-kv.ts +42 -36
- package/src/__tests__/helpers/mock-oauth-flow.ts +263 -0
- package/src/__tests__/helpers/mock-process.ts +34 -0
- package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
- package/src/__tests__/helpers/mock-stdin.ts +82 -77
- package/src/__tests__/helpers/mock-web-socket.ts +21 -21
- package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
- package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +160 -0
- package/src/__tests__/helpers/msw/handlers/namespaces.ts +81 -0
- package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
- package/src/__tests__/helpers/msw/handlers/r2.ts +60 -0
- package/src/__tests__/helpers/msw/handlers/script.ts +56 -0
- package/src/__tests__/helpers/msw/handlers/user.ts +52 -0
- package/src/__tests__/helpers/msw/handlers/zones.ts +20 -0
- package/src/__tests__/helpers/msw/index.ts +52 -0
- package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
- package/src/__tests__/helpers/run-in-tmp.ts +29 -20
- package/src/__tests__/helpers/run-wrangler.ts +8 -8
- package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
- package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/parent-worker.js +11 -0
- package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
- 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 +163 -0
- package/src/__tests__/index.test.ts +264 -850
- package/src/__tests__/init.test.ts +3196 -0
- package/src/__tests__/jest.setup.ts +158 -48
- package/src/__tests__/kv.test.ts +1789 -1398
- package/src/__tests__/logger.test.ts +141 -0
- package/src/__tests__/logout.test.ts +41 -44
- package/src/__tests__/metrics.test.ts +493 -0
- package/src/__tests__/middleware.scheduled.test.ts +145 -0
- package/src/__tests__/middleware.test.ts +816 -0
- package/src/__tests__/mtls-certificates.test.ts +588 -0
- package/src/__tests__/package-manager.test.ts +312 -165
- package/src/__tests__/pages/deployment-list.test.ts +80 -0
- package/src/__tests__/pages/functions-build.test.ts +452 -0
- package/src/__tests__/pages/pages.test.ts +81 -0
- package/src/__tests__/pages/project-create.test.ts +63 -0
- package/src/__tests__/pages/project-list.test.ts +110 -0
- package/src/__tests__/pages/project-upload.test.ts +500 -0
- package/src/__tests__/pages/publish.test.ts +2820 -0
- package/src/__tests__/pages-deployment-tail.test.ts +955 -0
- package/src/__tests__/parse.test.ts +359 -245
- package/src/__tests__/paths.test.ts +39 -0
- package/src/__tests__/publish.test.ts +8373 -2089
- package/src/__tests__/pubsub.test.ts +496 -0
- package/src/__tests__/queues.test.ts +532 -0
- package/src/__tests__/r2.test.ts +369 -193
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +683 -415
- package/src/__tests__/tail.test.ts +838 -444
- package/src/__tests__/test-old-node-version.js +31 -0
- package/src/__tests__/tsconfig-sanity.ts +12 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/tsconfig.tsbuildinfo +1 -0
- package/src/__tests__/type-generation.test.ts +234 -0
- package/src/__tests__/user.test.ts +118 -0
- package/src/__tests__/utils-collectKeyValues.test.ts +47 -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 +167 -81
- package/src/__tests__/worker-namespace.test.ts +340 -0
- package/src/abort.d.ts +3 -0
- package/src/api/dev.ts +327 -0
- package/src/api/index.ts +11 -0
- package/src/api/mtls-certificate.ts +148 -0
- package/src/api/pages/create-worker-bundle-contents.ts +75 -0
- package/src/api/pages/index.ts +5 -0
- package/src/api/pages/publish.tsx +355 -0
- package/src/bundle-reporter.ts +68 -0
- package/src/bundle.ts +874 -103
- package/src/cfetch/index.ts +123 -69
- package/src/cfetch/internal.ts +217 -92
- package/src/cli.ts +23 -14
- package/src/config/README.md +7 -7
- package/src/config/config.ts +236 -224
- package/src/config/diagnostics.ts +61 -61
- package/src/config/environment.ts +545 -256
- package/src/config/index.ts +367 -34
- package/src/config/validation-helpers.ts +449 -222
- package/src/config/validation.ts +2142 -907
- package/src/config-cache.ts +85 -0
- package/src/create-worker-preview.ts +293 -0
- package/src/create-worker-upload-form.ts +342 -0
- package/src/d1/backups.tsx +219 -0
- package/src/d1/constants.ts +2 -0
- package/src/d1/create.tsx +68 -0
- package/src/d1/delete.ts +53 -0
- package/src/d1/execute.tsx +357 -0
- package/src/d1/formatTimeAgo.ts +14 -0
- package/src/d1/index.ts +100 -0
- package/src/d1/list.tsx +60 -0
- package/src/d1/migrations/apply.tsx +212 -0
- package/src/d1/migrations/create.tsx +79 -0
- package/src/d1/migrations/helpers.ts +172 -0
- package/src/d1/migrations/index.ts +3 -0
- package/src/d1/migrations/list.tsx +95 -0
- package/src/d1/migrations/options.ts +23 -0
- package/src/d1/options.ts +22 -0
- package/src/d1/splitter.ts +161 -0
- package/src/d1/types.ts +25 -0
- package/src/d1/utils.ts +49 -0
- package/src/delete.ts +100 -0
- package/src/deployments.ts +368 -0
- package/src/deprecated/index.ts +144 -0
- package/src/dev/dev-vars.ts +39 -0
- package/src/dev/dev.tsx +600 -0
- package/src/dev/get-local-persistence-path.ts +31 -0
- package/src/dev/local.tsx +920 -0
- package/src/dev/remote.tsx +632 -0
- package/src/dev/start-server.ts +540 -0
- package/src/dev/use-esbuild.ts +209 -0
- package/src/dev/validate-dev-props.ts +40 -0
- package/src/dev-registry.ts +201 -0
- package/src/dev.tsx +907 -939
- package/src/dialogs.ts +136 -0
- package/src/dispatch-namespace.ts +211 -0
- package/src/docs/index.ts +97 -0
- package/src/durable.ts +102 -0
- package/src/entry.ts +307 -37
- package/src/environment-variables/factory.ts +88 -0
- package/src/environment-variables/misc-variables.ts +30 -0
- package/src/errors.ts +11 -0
- package/src/generate/index.ts +298 -0
- package/src/git-client.ts +135 -0
- package/src/global-wrangler-config-path.ts +26 -0
- package/src/https-options.ts +127 -0
- package/src/index.ts +758 -0
- package/src/init.ts +1032 -0
- package/src/inspect.ts +723 -550
- package/src/intl-polyfill.d.ts +139 -0
- package/src/is-ci.ts +14 -0
- package/src/is-interactive.ts +16 -0
- package/src/jest.d.ts +4 -0
- package/src/kv/helpers.ts +430 -0
- package/src/kv/index.ts +594 -0
- package/src/logger.ts +104 -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 +99 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/assets.ts +251 -0
- package/src/miniflare-cli/index.ts +210 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/miniflare-cli/tsconfig.json +9 -0
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
- package/src/miniflare-cli/types.ts +11 -0
- package/src/module-collection.ts +243 -146
- package/src/mtls-certificate/cli.ts +155 -0
- package/src/open-in-browser.ts +10 -6
- package/src/package-manager.ts +183 -90
- package/src/pages/build.ts +410 -0
- package/src/pages/buildFunctions.ts +140 -0
- package/src/pages/constants.ts +18 -0
- package/src/pages/deployment-tails.ts +281 -0
- package/src/pages/deployments.tsx +84 -0
- package/src/pages/dev.ts +716 -0
- package/src/pages/errors.ts +67 -0
- package/src/pages/functions/buildPlugin.ts +112 -0
- package/src/pages/functions/buildWorker.ts +297 -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 +282 -0
- package/src/pages/functions/routes-transformation.ts +115 -0
- package/src/pages/functions/routes-validation.test.ts +403 -0
- package/src/pages/functions/routes-validation.ts +202 -0
- package/src/pages/functions/routes.ts +151 -0
- package/src/pages/functions/tsconfig.json +8 -0
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
- package/src/pages/functions.ts +86 -0
- package/src/pages/hash.ts +13 -0
- package/src/pages/index.ts +102 -0
- package/src/pages/projects.tsx +159 -0
- package/src/pages/prompt-select-project.tsx +31 -0
- package/src/pages/publish.tsx +267 -0
- package/src/pages/types.ts +46 -0
- package/src/pages/upload.tsx +469 -0
- package/src/pages/utils.ts +23 -0
- package/src/parse.ts +247 -122
- package/src/paths.ts +53 -8
- package/src/proxy.ts +636 -318
- package/src/publish/index.ts +274 -0
- package/src/publish/publish.ts +1065 -0
- package/src/pubsub/index.ts +286 -0
- package/src/pubsub/pubsub-commands.ts +623 -0
- package/src/queues/cli/commands/consumer/add.ts +71 -0
- package/src/queues/cli/commands/consumer/index.ts +19 -0
- package/src/queues/cli/commands/consumer/remove.ts +31 -0
- package/src/queues/cli/commands/create.ts +25 -0
- package/src/queues/cli/commands/delete.ts +26 -0
- package/src/queues/cli/commands/index.ts +35 -0
- package/src/queues/cli/commands/list.ts +25 -0
- package/src/queues/client.ts +136 -0
- package/src/queues/utils.ts +18 -0
- package/src/r2/constants.ts +4 -0
- package/src/r2/helpers.ts +132 -0
- package/src/r2/index.ts +289 -0
- package/src/routes.ts +140 -0
- package/src/secret/index.ts +375 -0
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.ts +372 -0
- package/src/tail/createTail.ts +406 -0
- package/src/tail/filters.ts +109 -111
- package/src/tail/index.ts +208 -296
- package/src/tail/printing.ts +107 -47
- package/src/tsconfig-sanity.ts +16 -0
- package/src/type-generation.ts +181 -0
- package/src/update-check.ts +19 -0
- package/src/user/access.ts +68 -0
- package/src/user/auth-variables.ts +113 -0
- package/src/user/choose-account.tsx +39 -0
- package/src/user/generate-auth-url.ts +33 -0
- package/src/user/generate-random-state.ts +16 -0
- package/src/user/index.ts +2 -0
- package/src/user/user.ts +1233 -0
- package/src/utils/collectKeyValues.ts +14 -0
- package/src/utils/render.ts +93 -0
- package/src/whoami.ts +135 -0
- package/src/worker.ts +264 -0
- package/src/yargs-types.ts +37 -0
- package/src/zones.ts +191 -0
- package/templates/__tests__/pages-dev-util.test.ts +128 -0
- package/templates/__tests__/tsconfig-sanity.ts +12 -0
- package/templates/__tests__/tsconfig.json +8 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
- package/templates/checked-fetch.js +23 -0
- package/templates/d1-beta-facade.js +244 -0
- package/templates/facade.d.ts +14 -0
- package/templates/first-party-worker-module-facade.ts +19 -0
- package/templates/format-dev-errors.ts +34 -0
- package/templates/gitignore +172 -0
- package/templates/init-tests/test-jest-new-worker.js +23 -0
- package/templates/init-tests/test-vitest-new-worker.js +24 -0
- package/templates/init-tests/test-vitest-new-worker.ts +25 -0
- package/templates/middleware/common.ts +62 -0
- package/templates/middleware/loader-modules.ts +84 -0
- package/templates/middleware/loader-sw.ts +233 -0
- package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
- package/templates/middleware/middleware-pretty-error.ts +40 -0
- package/templates/middleware/middleware-scheduled.ts +15 -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 +21 -3
- package/templates/no-op-worker.js +10 -0
- package/templates/pages-dev-pipeline.ts +31 -0
- package/templates/pages-dev-util.ts +52 -0
- package/templates/pages-shim.ts +12 -0
- package/templates/pages-template-plugin.ts +180 -0
- package/templates/pages-template-worker.ts +189 -0
- package/templates/serve-static-assets.ts +66 -0
- package/templates/service-bindings-module-facade.js +55 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/templates/tsconfig-sanity.ts +11 -0
- package/templates/tsconfig.init.json +105 -0
- package/templates/tsconfig.json +6 -103
- package/templates/tsconfig.tsbuildinfo +1 -0
- package/wrangler-dist/cli.d.ts +1619 -0
- package/wrangler-dist/cli.js +141446 -128789
- package/wrangler-dist/wasm-sync.wasm +0 -0
- package/pages/functions/buildWorker.ts +0 -62
- package/pages/functions/filepath-routing.test.ts +0 -123
- package/pages/functions/filepath-routing.ts +0 -178
- 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__/helpers/faye-websocket.d.ts +0 -6
- package/src/__tests__/helpers/mock-cfetch.ts +0 -207
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/api/form_data.ts +0 -217
- package/src/api/preview.ts +0 -147
- package/src/api/worker.ts +0 -186
- package/src/dialogs.tsx +0 -77
- package/src/environment-variables.ts +0 -33
- package/src/guess-worker-format.ts +0 -68
- package/src/index.tsx +0 -2302
- package/src/kv.tsx +0 -339
- package/src/pages.tsx +0 -1045
- package/src/publish.ts +0 -363
- package/src/r2.ts +0 -50
- package/src/reporting.ts +0 -115
- package/src/sites.tsx +0 -238
- package/src/user.tsx +0 -1063
- package/src/whoami.tsx +0 -69
- 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
|
@@ -1,27 +1,32 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RawConfig } from "./config";
|
|
2
2
|
import type { Diagnostics } from "./diagnostics";
|
|
3
3
|
import type { Environment, RawEnvironment } from "./environment";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Mark a field as deprecated.
|
|
7
7
|
*
|
|
8
|
-
* This function will add a diagnostics warning if the deprecated field is found in the `rawEnv
|
|
8
|
+
* This function will add a diagnostics warning if the deprecated field is found in the `rawEnv` (or an error if it's also a breaking deprecation)
|
|
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
|
-
|
|
12
|
+
diagnostics: Diagnostics,
|
|
13
|
+
config: T,
|
|
14
|
+
fieldPath: DeepKeyOf<T>,
|
|
15
|
+
message: string,
|
|
16
|
+
remove: boolean,
|
|
17
|
+
title = "Deprecation",
|
|
18
|
+
type: "warning" | "error" = "warning"
|
|
17
19
|
): void {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
}
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
/**
|
|
@@ -31,16 +36,16 @@ export function deprecated<T extends object>(
|
|
|
31
36
|
* The `fieldPath` is a dot separated property path, e.g. `"build.upload.format"`.
|
|
32
37
|
*/
|
|
33
38
|
export function experimental<T extends object>(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
diagnostics: Diagnostics,
|
|
40
|
+
config: T,
|
|
41
|
+
fieldPath: DeepKeyOf<T>
|
|
37
42
|
): void {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
}
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
/**
|
|
@@ -50,15 +55,83 @@ export function experimental<T extends object>(
|
|
|
50
55
|
* and then the `defaultValue`.
|
|
51
56
|
*/
|
|
52
57
|
export function inheritable<K extends keyof Environment>(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
59
65
|
): Environment[K] {
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
validate(diagnostics, field, rawEnv[field], topLevelEnv);
|
|
67
|
+
return (
|
|
68
|
+
(rawEnv[field] as Environment[K]) ??
|
|
69
|
+
transformFn(topLevelEnv?.[field]) ??
|
|
70
|
+
defaultValue
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get an inheritable environment field, but only if we are in legacy environments
|
|
76
|
+
*/
|
|
77
|
+
export function inheritableInLegacyEnvironments<K extends keyof Environment>(
|
|
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]
|
|
86
|
+
): Environment[K] {
|
|
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
|
+
);
|
|
103
|
+
}
|
|
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
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Log an error if this named environment is trying to override the value in the top-level
|
|
120
|
+
* environment, which is not allow for this field.
|
|
121
|
+
*/
|
|
122
|
+
function notAllowedInNamedServiceEnvironment<K extends keyof Environment>(
|
|
123
|
+
diagnostics: Diagnostics,
|
|
124
|
+
topLevelEnv: Environment,
|
|
125
|
+
rawEnv: RawEnvironment,
|
|
126
|
+
field: K
|
|
127
|
+
): Environment[K] {
|
|
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];
|
|
62
135
|
}
|
|
63
136
|
|
|
64
137
|
/**
|
|
@@ -68,39 +141,39 @@ export function inheritable<K extends keyof Environment>(
|
|
|
68
141
|
* then log a warning and return the `defaultValue`.
|
|
69
142
|
*/
|
|
70
143
|
export function notInheritable<K extends keyof Environment>(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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]
|
|
79
152
|
): Environment[K] {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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;
|
|
92
165
|
}
|
|
93
166
|
|
|
94
167
|
// Idea taken from https://stackoverflow.com/a/66661477
|
|
95
168
|
type DeepKeyOf<T> = (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
169
|
+
T extends object
|
|
170
|
+
? {
|
|
171
|
+
[K in Exclude<keyof T, symbol>]: `${K}${DotPrefix<DeepKeyOf<T[K]>>}`;
|
|
172
|
+
}[Exclude<keyof T, symbol>]
|
|
173
|
+
: ""
|
|
101
174
|
) extends infer D
|
|
102
|
-
|
|
103
|
-
|
|
175
|
+
? Extract<D, string>
|
|
176
|
+
: never;
|
|
104
177
|
|
|
105
178
|
type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;
|
|
106
179
|
|
|
@@ -115,256 +188,410 @@ type DotPrefix<T extends string> = T extends "" ? "" : `.${T}`;
|
|
|
115
188
|
* ```
|
|
116
189
|
*/
|
|
117
190
|
function unwindPropertyPath<T extends object>(
|
|
118
|
-
|
|
119
|
-
|
|
191
|
+
root: T,
|
|
192
|
+
path: DeepKeyOf<T>
|
|
120
193
|
): { container: object; field: string } | undefined {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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] };
|
|
130
203
|
}
|
|
131
204
|
|
|
132
205
|
/**
|
|
133
206
|
* The type of a function that can be used to validate a configuration field.
|
|
134
207
|
*/
|
|
135
208
|
export type ValidatorFn = (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
209
|
+
diagnostics: Diagnostics,
|
|
210
|
+
field: string,
|
|
211
|
+
value: unknown,
|
|
212
|
+
topLevelEnv: Environment | undefined
|
|
140
213
|
) => boolean;
|
|
141
214
|
|
|
142
215
|
/**
|
|
143
216
|
* Validate that the field is a string.
|
|
144
217
|
*/
|
|
145
218
|
export const isString: ValidatorFn = (diagnostics, field, value) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
}
|
|
155
247
|
};
|
|
156
248
|
|
|
157
249
|
/**
|
|
158
250
|
* Validate that the field is an array of strings.
|
|
159
251
|
*/
|
|
160
252
|
export const isStringArray: ValidatorFn = (diagnostics, field, value) => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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;
|
|
173
265
|
};
|
|
174
266
|
|
|
175
267
|
/**
|
|
176
268
|
* Validate that the field is an object containing the given properties.
|
|
177
269
|
*/
|
|
178
270
|
export const isObjectWith =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
+
};
|
|
196
297
|
|
|
197
298
|
/**
|
|
198
299
|
* Validate that the field value is one of the given choices.
|
|
199
300
|
*/
|
|
200
301
|
export const isOneOf =
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Aggregate multiple validator functions
|
|
317
|
+
*/
|
|
318
|
+
export const all = (...validations: ValidatorFn[]): ValidatorFn => {
|
|
319
|
+
return (diagnostics, field, value, config) => {
|
|
320
|
+
let passedValidations = true;
|
|
321
|
+
|
|
322
|
+
for (const validate of validations) {
|
|
323
|
+
if (!validate(diagnostics, field, value, config)) {
|
|
324
|
+
passedValidations = false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return passedValidations;
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Check that the field is mutually exclusive with a list of other fields.
|
|
334
|
+
*
|
|
335
|
+
* @param container the container of the fields to check against.
|
|
336
|
+
* @param fields the names of the fields to check against.
|
|
337
|
+
*/
|
|
338
|
+
export const isMutuallyExclusiveWith = <T extends RawEnvironment | RawConfig>(
|
|
339
|
+
container: T,
|
|
340
|
+
...fields: (keyof T)[]
|
|
341
|
+
): ValidatorFn => {
|
|
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
|
+
};
|
|
361
|
+
};
|
|
213
362
|
|
|
214
363
|
/**
|
|
215
364
|
* Validate that the field is a boolean.
|
|
216
365
|
*/
|
|
217
366
|
export const isBoolean: ValidatorFn = (diagnostics, field, value) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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;
|
|
227
376
|
};
|
|
228
377
|
|
|
229
378
|
/**
|
|
230
379
|
* Validate that the required field exists and has the expected type.
|
|
231
380
|
*/
|
|
232
381
|
export const validateRequiredProperty = (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
382
|
+
diagnostics: Diagnostics,
|
|
383
|
+
container: string,
|
|
384
|
+
key: string,
|
|
385
|
+
value: unknown,
|
|
386
|
+
type: TypeofType,
|
|
387
|
+
choices?: unknown[]
|
|
238
388
|
): boolean => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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;
|
|
254
410
|
};
|
|
255
411
|
|
|
256
412
|
/**
|
|
257
413
|
* Validate that, if the optional field exists, then it has the expected type.
|
|
258
414
|
*/
|
|
259
415
|
export const validateOptionalProperty = (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
416
|
+
diagnostics: Diagnostics,
|
|
417
|
+
container: string,
|
|
418
|
+
key: string,
|
|
419
|
+
value: unknown,
|
|
420
|
+
type: TypeofType,
|
|
421
|
+
choices?: unknown[]
|
|
265
422
|
): boolean => {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
423
|
+
if (value !== undefined) {
|
|
424
|
+
return validateRequiredProperty(
|
|
425
|
+
diagnostics,
|
|
426
|
+
container,
|
|
427
|
+
key,
|
|
428
|
+
value,
|
|
429
|
+
type,
|
|
430
|
+
choices
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return true;
|
|
270
434
|
};
|
|
271
435
|
|
|
272
436
|
/**
|
|
273
437
|
* Validate that the field is an array of elements of the given type.
|
|
274
438
|
*/
|
|
275
439
|
export const validateTypedArray = (
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
440
|
+
diagnostics: Diagnostics,
|
|
441
|
+
container: string,
|
|
442
|
+
value: unknown,
|
|
443
|
+
type: TypeofType
|
|
280
444
|
): boolean => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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;
|
|
302
466
|
};
|
|
303
467
|
|
|
304
468
|
/**
|
|
305
469
|
* Validate that, if the optional field exists, it is an array of elements of the given type.
|
|
306
470
|
*/
|
|
307
471
|
export const validateOptionalTypedArray = (
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
472
|
+
diagnostics: Diagnostics,
|
|
473
|
+
container: string,
|
|
474
|
+
value: unknown,
|
|
475
|
+
type: TypeofType
|
|
312
476
|
) => {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
477
|
+
if (value !== undefined) {
|
|
478
|
+
return validateTypedArray(diagnostics, container, value, type);
|
|
479
|
+
}
|
|
480
|
+
return true;
|
|
317
481
|
};
|
|
318
482
|
|
|
319
483
|
/**
|
|
320
484
|
* Test to see if `obj` has the required property `prop` of type `type`.
|
|
321
485
|
*/
|
|
322
486
|
export const isRequiredProperty = <T extends object>(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
487
|
+
obj: object,
|
|
488
|
+
prop: keyof T,
|
|
489
|
+
type: TypeofType,
|
|
490
|
+
choices?: unknown[]
|
|
327
491
|
): obj is T =>
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
492
|
+
hasProperty<T>(obj, prop) &&
|
|
493
|
+
typeof obj[prop] === type &&
|
|
494
|
+
(choices === undefined || choices.includes(obj[prop]));
|
|
331
495
|
|
|
332
496
|
/**
|
|
333
497
|
* Test to see if `obj` has the optional property `prop` of type `type`.
|
|
334
498
|
*/
|
|
335
499
|
export const isOptionalProperty = <T extends object>(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
500
|
+
obj: object,
|
|
501
|
+
prop: keyof T,
|
|
502
|
+
type: TypeofType
|
|
339
503
|
): obj is T => !hasProperty<T>(obj, prop) || typeof obj[prop] === type;
|
|
340
504
|
|
|
341
505
|
/**
|
|
342
506
|
* Test to see if `obj` has the property `prop`.
|
|
343
507
|
*/
|
|
344
508
|
export const hasProperty = <T extends object>(
|
|
345
|
-
|
|
346
|
-
|
|
509
|
+
obj: object,
|
|
510
|
+
property: keyof T
|
|
347
511
|
): obj is T => property in obj;
|
|
348
512
|
|
|
349
513
|
/**
|
|
350
514
|
* Add warning messages about any properties in the given field that are not expected to be there.
|
|
351
515
|
*/
|
|
352
516
|
export const validateAdditionalProperties = (
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
517
|
+
diagnostics: Diagnostics,
|
|
518
|
+
fieldPath: string,
|
|
519
|
+
restProps: Iterable<string>,
|
|
520
|
+
knownProps: Iterable<string>
|
|
357
521
|
): boolean => {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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;
|
|
370
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).filter((k) => value[k] !== undefined);
|
|
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";
|