wrangler 0.0.0-e95e5a0 → 0.0.0-e98613f8

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