wrangler 0.0.0-e3cab74 → 0.0.0-e3ce82b

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 (139) hide show
  1. package/Cloudflare_CA.pem +18 -0
  2. package/README.md +27 -14
  3. package/bin/wrangler.js +49 -5
  4. package/miniflare-dist/index.mjs +4886 -0
  5. package/package.json +43 -28
  6. package/pages/functions/buildPlugin.ts +105 -0
  7. package/pages/functions/buildWorker.ts +93 -4
  8. package/pages/functions/filepath-routing.test.ts +136 -25
  9. package/pages/functions/filepath-routing.ts +14 -3
  10. package/pages/functions/routes.ts +6 -1
  11. package/pages/functions/template-plugin.ts +147 -0
  12. package/pages/functions/template-worker.ts +21 -8
  13. package/src/__tests__/config-cache.test.ts +36 -0
  14. package/src/__tests__/configuration.test.ts +1713 -411
  15. package/src/__tests__/dev.test.tsx +954 -84
  16. package/src/__tests__/guess-worker-format.test.ts +37 -18
  17. package/src/__tests__/helpers/mock-account-id.ts +22 -4
  18. package/src/__tests__/helpers/mock-cfetch.ts +8 -4
  19. package/src/__tests__/helpers/mock-console.ts +35 -10
  20. package/src/__tests__/helpers/mock-dialogs.ts +67 -2
  21. package/src/__tests__/helpers/mock-http-server.ts +46 -0
  22. package/src/__tests__/helpers/mock-istty.ts +27 -0
  23. package/src/__tests__/helpers/mock-kv.ts +9 -16
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
  25. package/src/__tests__/helpers/mock-stdin.ts +103 -0
  26. package/src/__tests__/helpers/run-in-tmp.ts +10 -0
  27. package/src/__tests__/helpers/write-worker-source.ts +31 -0
  28. package/src/__tests__/https-options.test.ts +130 -0
  29. package/src/__tests__/index.test.ts +138 -747
  30. package/src/__tests__/init.test.ts +1637 -0
  31. package/src/__tests__/jest.setup.ts +28 -8
  32. package/src/__tests__/kv.test.ts +598 -258
  33. package/src/__tests__/logger.test.ts +115 -0
  34. package/src/__tests__/package-manager.test.ts +154 -7
  35. package/src/__tests__/pages.test.ts +754 -0
  36. package/src/__tests__/parse.test.ts +8 -0
  37. package/src/__tests__/publish.test.ts +4374 -1025
  38. package/src/__tests__/r2.test.ts +69 -34
  39. package/src/__tests__/route.test.ts +45 -0
  40. package/src/__tests__/secret.test.ts +228 -73
  41. package/src/__tests__/tail.test.ts +146 -20
  42. package/src/__tests__/user.test.ts +131 -0
  43. package/src/__tests__/whoami.test.tsx +60 -7
  44. package/src/abort.d.ts +3 -0
  45. package/src/bundle.ts +75 -11
  46. package/src/cfetch/index.ts +21 -4
  47. package/src/cfetch/internal.ts +29 -20
  48. package/src/cli.ts +5 -11
  49. package/src/config/README.md +7 -7
  50. package/src/config/config.ts +69 -100
  51. package/src/config/environment.ts +119 -4
  52. package/src/config/index.ts +177 -4
  53. package/src/config/validation-helpers.ts +237 -23
  54. package/src/config/validation.ts +722 -191
  55. package/src/config-cache.ts +45 -0
  56. package/src/{api/preview.ts → create-worker-preview.ts} +65 -27
  57. package/src/{api/form_data.ts → create-worker-upload-form.ts} +55 -18
  58. package/src/dev/dev-vars.ts +36 -0
  59. package/src/dev/dev.tsx +401 -0
  60. package/src/dev/local.tsx +322 -0
  61. package/src/dev/remote.tsx +237 -0
  62. package/src/dev/use-esbuild.ts +118 -0
  63. package/src/dialogs.tsx +64 -6
  64. package/src/durable.ts +102 -0
  65. package/src/entry.ts +279 -14
  66. package/src/environment-variables.ts +3 -1
  67. package/src/errors.ts +11 -0
  68. package/src/https-options.ts +123 -0
  69. package/src/index.tsx +1386 -867
  70. package/src/inspect.ts +64 -11
  71. package/src/intl-polyfill.d.ts +139 -0
  72. package/src/{kv.tsx → kv.ts} +195 -62
  73. package/src/logger.ts +66 -0
  74. package/src/miniflare-cli/README.md +30 -0
  75. package/src/miniflare-cli/enum-keys.ts +17 -0
  76. package/src/miniflare-cli/index.ts +41 -0
  77. package/src/miniflare-cli/request-context.ts +40 -0
  78. package/src/module-collection.ts +94 -6
  79. package/src/open-in-browser.ts +9 -3
  80. package/src/package-manager.ts +59 -11
  81. package/src/pages.tsx +1123 -75
  82. package/src/parse.ts +26 -6
  83. package/src/proxy.ts +159 -57
  84. package/src/publish.ts +581 -228
  85. package/src/selfsigned.d.ts +29 -0
  86. package/src/sites.tsx +130 -45
  87. package/src/tail/index.ts +2 -2
  88. package/src/tail/printing.ts +13 -8
  89. package/src/update-check.ts +19 -0
  90. package/src/user.tsx +275 -110
  91. package/src/whoami.tsx +5 -3
  92. package/src/{api/worker.ts → worker.ts} +24 -29
  93. package/src/zones.ts +73 -0
  94. package/templates/gitignore +171 -0
  95. package/templates/new-worker-scheduled.js +17 -0
  96. package/templates/new-worker-scheduled.ts +32 -0
  97. package/templates/new-worker.ts +16 -1
  98. package/templates/static-asset-facade.js +1 -5
  99. package/wrangler-dist/cli.js +104803 -118375
  100. package/src/__tests__/helpers/mock-user.ts +0 -27
  101. package/src/__tests__/logout.test.ts +0 -50
  102. package/src/__tests__/sentry.test.ts +0 -146
  103. package/src/dev.tsx +0 -961
  104. package/src/guess-worker-format.ts +0 -68
  105. package/src/reporting.ts +0 -115
  106. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  107. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  108. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  109. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  110. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  111. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  112. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  113. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  114. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  115. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  116. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  117. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  118. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  119. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  120. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  121. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  122. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  123. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  124. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  125. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  126. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  127. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  128. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  129. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  130. package/vendor/wrangler-mime/LICENSE +0 -21
  131. package/vendor/wrangler-mime/Mime.js +0 -97
  132. package/vendor/wrangler-mime/README.md +0 -187
  133. package/vendor/wrangler-mime/cli.js +0 -46
  134. package/vendor/wrangler-mime/index.js +0 -4
  135. package/vendor/wrangler-mime/lite.js +0 -4
  136. package/vendor/wrangler-mime/package.json +0 -52
  137. package/vendor/wrangler-mime/types/other.js +0 -1
  138. package/vendor/wrangler-mime/types/standard.js +0 -1
  139. package/wrangler-dist/cli.js.map +0 -7
@@ -1,39 +1,49 @@
1
1
  import path from "node:path";
2
2
  import { normalizeAndValidateConfig } from "../config/validation";
3
- import type { RawConfig, RawEnvironment } from "../config";
3
+ import { normalizeSlashes } from "./helpers/mock-console";
4
+ import type {
5
+ ConfigFields,
6
+ RawDevConfig,
7
+ RawConfig,
8
+ RawEnvironment,
9
+ } from "../config";
4
10
 
5
11
  describe("normalizeAndValidateConfig()", () => {
6
12
  it("should use defaults for empty configuration", () => {
7
- const { config, diagnostics } = normalizeAndValidateConfig({}, undefined);
13
+ const { config, diagnostics } = normalizeAndValidateConfig({}, undefined, {
14
+ env: undefined,
15
+ });
8
16
 
9
17
  expect(config).toEqual({
10
18
  account_id: undefined,
11
19
  build: {
12
20
  command: undefined,
13
21
  cwd: undefined,
14
- watch_dir: undefined,
22
+ watch_dir: "./src",
15
23
  },
16
24
  compatibility_date: undefined,
17
25
  compatibility_flags: [],
18
26
  configPath: undefined,
19
27
  dev: {
20
- ip: "127.0.0.1",
28
+ ip: "localhost",
21
29
  local_protocol: "http",
22
- port: 8787,
30
+ port: undefined, // the default of 8787 is set at runtime
23
31
  upstream_protocol: "https",
32
+ host: undefined,
24
33
  },
25
34
  durable_objects: {
26
35
  bindings: [],
27
36
  },
28
- env: {},
29
37
  jsx_factory: "React.createElement",
30
38
  jsx_fragment: "React.Fragment",
39
+ tsconfig: undefined,
31
40
  kv_namespaces: [],
32
41
  legacy_env: true,
33
42
  main: undefined,
34
43
  migrations: [],
35
44
  name: undefined,
36
45
  r2_buckets: [],
46
+ services: [],
37
47
  route: undefined,
38
48
  routes: undefined,
39
49
  rules: [],
@@ -48,8 +58,11 @@ describe("normalizeAndValidateConfig()", () => {
48
58
  usage_model: undefined,
49
59
  vars: {},
50
60
  wasm_modules: undefined,
51
- workers_dev: true,
61
+ data_blobs: undefined,
62
+ workers_dev: undefined,
52
63
  zone_id: undefined,
64
+ minify: undefined,
65
+ node_compat: undefined,
53
66
  });
54
67
  expect(diagnostics.hasErrors()).toBe(false);
55
68
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -57,56 +70,42 @@ describe("normalizeAndValidateConfig()", () => {
57
70
 
58
71
  describe("top-level non-environment configuration", () => {
59
72
  it("should override config defaults with provided values", () => {
60
- const main = "src/index.ts";
61
- const expectedConfig: RawConfig = {
62
- main,
73
+ const expectedConfig: Partial<ConfigFields<RawDevConfig>> = {
63
74
  legacy_env: true,
64
75
  dev: {
65
76
  ip: "255.255.255.255",
66
77
  port: 9999,
67
- local_protocol: "HTTPS",
68
- upstream_protocol: "HTTP",
69
- },
70
- build: {
71
- command: "COMMAND",
72
- cwd: "CWD",
73
- watch_dir: "WATCH_DIR",
78
+ local_protocol: "https",
79
+ upstream_protocol: "http",
74
80
  },
75
81
  };
76
82
 
77
83
  const { config, diagnostics } = normalizeAndValidateConfig(
78
84
  expectedConfig,
79
- undefined
85
+ undefined,
86
+ { env: undefined }
80
87
  );
81
88
 
82
- const resolvedMain = path.resolve(process.cwd(), main);
83
- expect(config).toEqual(
84
- expect.objectContaining({ ...expectedConfig, main: resolvedMain })
85
- );
89
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
86
90
  expect(diagnostics.hasErrors()).toBe(false);
87
91
  expect(diagnostics.hasWarnings()).toBe(false);
88
92
  });
89
93
 
90
94
  it("should error on invalid top level fields", () => {
91
95
  const expectedConfig = {
92
- main: 111,
93
96
  legacy_env: "FOO",
94
97
  dev: {
95
98
  ip: 222,
96
99
  port: "FOO",
97
- local_protocol: 333,
98
- upstream_protocol: 444,
99
- },
100
- build: {
101
- command: 555,
102
- cwd: 666,
103
- watch_dir: 777,
100
+ local_protocol: "wss",
101
+ upstream_protocol: "ws",
104
102
  },
105
103
  };
106
104
 
107
105
  const { config, diagnostics } = normalizeAndValidateConfig(
108
106
  expectedConfig as unknown as RawConfig,
109
- undefined
107
+ undefined,
108
+ { env: undefined }
110
109
  );
111
110
 
112
111
  expect(config).toEqual(
@@ -114,233 +113,411 @@ describe("normalizeAndValidateConfig()", () => {
114
113
  );
115
114
  expect(diagnostics.hasWarnings()).toBe(false);
116
115
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
117
- "Processing wrangler configuration:
118
- - ERROR: \\"build.command\\" should be of type string but got 555.
119
- - ERROR: \\"build.cwd\\" should be of type string but got 666.
120
- - ERROR: \\"build.watch_dir\\" should be of type string but got 777.
121
- - ERROR: \\"legacy_env\\" should be of type boolean but got \\"FOO\\".
122
- - ERROR: \\"main\\" should be a string but got 111
123
- - ERROR: \\"dev.ip\\" should be of type string but got 222.
124
- - ERROR: \\"dev.port\\" should be of type number but got \\"FOO\\".
125
- - ERROR: \\"dev.local_protocol\\" should be of type string but got 333.
126
- - ERROR: \\"dev.upstream_protocol\\" should be of type string but got 444."
127
- `);
116
+ "Processing wrangler configuration:
117
+ - Expected \\"legacy_env\\" to be of type boolean but got \\"FOO\\".
118
+ - Expected \\"dev.ip\\" to be of type string but got 222.
119
+ - Expected \\"dev.port\\" to be of type number but got \\"FOO\\".
120
+ - Expected \\"dev.local_protocol\\" field to be one of [\\"http\\",\\"https\\"] but got \\"wss\\".
121
+ - Expected \\"dev.upstream_protocol\\" field to be one of [\\"http\\",\\"https\\"] but got \\"ws\\"."
122
+ `);
128
123
  });
129
124
 
130
125
  it("should warn on and remove unexpected top level fields", () => {
131
126
  const expectedConfig = {
132
- miniflare: {
133
- host: "127.0.0.1",
127
+ unexpected: {
128
+ subkey: "some-value",
134
129
  },
135
130
  };
136
131
 
137
132
  const { config, diagnostics } = normalizeAndValidateConfig(
138
133
  expectedConfig as unknown as RawConfig,
139
- undefined
134
+ undefined,
135
+ { env: undefined }
140
136
  );
141
137
 
142
- expect("miniflare" in config).toBe(false);
138
+ expect("unexpected" in config).toBe(false);
143
139
  expect(diagnostics.hasErrors()).toBe(false);
144
140
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
145
141
  "Processing wrangler configuration:
146
- - Unexpected fields found in top-level field: \\"miniflare\\""
142
+ - Unexpected fields found in top-level field: \\"unexpected\\""
147
143
  `);
148
144
  });
149
145
 
150
- it("should override build.upload config defaults with provided values and warn about deprecations", () => {
151
- const expectedConfig: RawConfig = {
152
- build: {
153
- upload: {
154
- dir: "src",
155
- format: "modules",
156
- main: "index.ts",
157
- rules: [{ type: "Text", globs: ["GLOB"], fallthrough: true }],
158
- },
146
+ it("should report a deprecation warning if `miniflare` appears at the top level", () => {
147
+ const expectedConfig = {
148
+ miniflare: {
149
+ host: "localhost",
159
150
  },
160
151
  };
161
152
 
162
153
  const { config, diagnostics } = normalizeAndValidateConfig(
163
- expectedConfig,
164
- path.resolve("project/wrangler.toml")
154
+ expectedConfig as unknown as RawConfig,
155
+ undefined,
156
+ { env: undefined }
165
157
  );
166
158
 
167
- expect(config.main).toEqual(path.resolve("project/src/index.ts"));
168
- expect(config.build.upload).toBeUndefined();
159
+ expect("miniflare" in config).toBe(false);
169
160
  expect(diagnostics.hasErrors()).toBe(false);
170
- expect(diagnostics.hasWarnings()).toBe(true);
171
- expect(normalizePath(diagnostics.renderWarnings()))
172
- .toMatchInlineSnapshot(`
173
- "Processing project/wrangler.toml configuration:
174
- - DEPRECATION: \\"build.upload.format\\":
175
- The format is inferred automatically from the code.
176
- - DEPRECATION: \\"build.upload.main\\":
177
- Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
178
- Then add the top level \`main\` field to your configuration file:
179
- \`\`\`
180
- main = \\"src/index.ts\\"
181
- \`\`\`
182
- - DEPRECATION: \\"build.upload.dir\\":
183
- Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the Worker.
184
- - DEPRECATION: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:
185
- \`\`\`
186
- [[rules]]
187
- type = \\"Text\\"
188
- globs = [ \\"GLOB\\" ]
189
- fallthrough = true
190
- \`\`\`"
161
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
162
+ "Processing wrangler configuration:
163
+ - 😶 Ignored: \\"miniflare\\":
164
+ Wrangler does not use configuration in the \`miniflare\` section. Unless you are using Miniflare directly you can remove this section."
191
165
  `);
192
166
  });
193
167
 
194
- it("should override `migrations` config defaults with provided values", () => {
195
- const expectedConfig: RawConfig = {
196
- migrations: [
197
- {
198
- tag: "TAG",
199
- new_classes: ["CLASS_1", "CLASS_2"],
200
- renamed_classes: [
201
- {
202
- from: "FROM_CLASS",
203
- to: "TO_CLASS",
204
- },
205
- ],
206
- deleted_classes: ["CLASS_3", "CLASS_4"],
207
- },
208
- ],
209
- };
168
+ describe("migrations", () => {
169
+ it("should override `migrations` config defaults with provided values", () => {
170
+ const expectedConfig: RawConfig = {
171
+ migrations: [
172
+ {
173
+ tag: "TAG",
174
+ new_classes: ["CLASS_1", "CLASS_2"],
175
+ renamed_classes: [
176
+ {
177
+ from: "FROM_CLASS",
178
+ to: "TO_CLASS",
179
+ },
180
+ ],
181
+ deleted_classes: ["CLASS_3", "CLASS_4"],
182
+ },
183
+ ],
184
+ };
210
185
 
211
- const { config, diagnostics } = normalizeAndValidateConfig(
212
- expectedConfig,
213
- undefined
214
- );
186
+ const { config, diagnostics } = normalizeAndValidateConfig(
187
+ expectedConfig,
188
+ undefined,
189
+ { env: undefined }
190
+ );
215
191
 
216
- expect(config).toEqual(expect.objectContaining(expectedConfig));
217
- expect(diagnostics.hasErrors()).toBe(false);
218
- expect(diagnostics.hasWarnings()).toBe(false);
192
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
193
+ expect(diagnostics.hasErrors()).toBe(false);
194
+ expect(diagnostics.hasWarnings()).toBe(false);
195
+ });
196
+
197
+ it("should error on invalid `migrations` values", () => {
198
+ const expectedConfig = {
199
+ migrations: [
200
+ {
201
+ tag: 111,
202
+ new_classes: [222, 333],
203
+ renamed_classes: [
204
+ {
205
+ from: 444,
206
+ to: 555,
207
+ },
208
+ ],
209
+ deleted_classes: [666, 777],
210
+ },
211
+ ],
212
+ };
213
+
214
+ const { config, diagnostics } = normalizeAndValidateConfig(
215
+ expectedConfig as unknown as RawConfig,
216
+ undefined,
217
+ { env: undefined }
218
+ );
219
+
220
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
221
+ expect(diagnostics.hasWarnings()).toBe(false);
222
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
223
+ "Processing wrangler configuration:
224
+ - Expected \\"migrations[0].tag\\" to be of type string but got 111.
225
+ - Expected \\"migrations[0].new_classes.[0]\\" to be of type string but got 222.
226
+ - Expected \\"migrations[0].new_classes.[1]\\" to be of type string but got 333.
227
+ - Expected \\"migrations[0].renamed_classes\\" to be an array of \\"{from: string, to: string}\\" objects but got [{\\"from\\":444,\\"to\\":555}].
228
+ - Expected \\"migrations[0].deleted_classes.[0]\\" to be of type string but got 666.
229
+ - Expected \\"migrations[0].deleted_classes.[1]\\" to be of type string but got 777."
230
+ `);
231
+ });
232
+
233
+ it("should warn/error on unexpected fields on `migrations`", async () => {
234
+ const expectedConfig = {
235
+ migrations: [
236
+ {
237
+ tag: "TAG",
238
+ new_classes: ["CLASS_1", "CLASS_2"],
239
+ renamed_classes: [
240
+ {
241
+ from: "FROM_CLASS",
242
+ to: "TO_CLASS",
243
+ },
244
+ {
245
+ a: "something",
246
+ b: "someone",
247
+ },
248
+ ],
249
+ deleted_classes: ["CLASS_3", "CLASS_4"],
250
+ unrecognized_field: "FOO",
251
+ },
252
+ ],
253
+ };
254
+
255
+ const { config, diagnostics } = normalizeAndValidateConfig(
256
+ expectedConfig as unknown as RawConfig,
257
+ undefined,
258
+ { env: undefined }
259
+ );
260
+
261
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
262
+ expect(diagnostics.hasErrors()).toBe(true);
263
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
264
+ "Processing wrangler configuration:
265
+ - Unexpected fields found in migrations field: \\"unrecognized_field\\""
266
+ `);
267
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
268
+ "Processing wrangler configuration:
269
+ - Expected \\"migrations[0].renamed_classes\\" to be an array of \\"{from: string, to: string}\\" objects but got [{\\"from\\":\\"FROM_CLASS\\",\\"to\\":\\"TO_CLASS\\"},{\\"a\\":\\"something\\",\\"b\\":\\"someone\\"}]."
270
+ `);
271
+ });
219
272
  });
220
273
 
221
- it("should error on invalid `migrations` values", () => {
222
- const expectedConfig = {
223
- migrations: [
224
- {
225
- tag: 111,
226
- new_classes: [222, 333],
227
- renamed_classes: [
228
- {
229
- from: 444,
230
- to: 555,
231
- },
232
- ],
233
- deleted_classes: [666, 777],
274
+ describe("site", () => {
275
+ it("should override `site` config defaults with provided values", () => {
276
+ const expectedConfig: RawConfig = {
277
+ site: {
278
+ bucket: "BUCKET",
279
+ "entry-point": "my-site",
280
+ exclude: ["EXCLUDE_1", "EXCLUDE_2"],
281
+ include: ["INCLUDE_1", "INCLUDE_2"],
234
282
  },
235
- ],
236
- };
283
+ };
237
284
 
238
- const { config, diagnostics } = normalizeAndValidateConfig(
239
- expectedConfig as unknown as RawConfig,
240
- undefined
241
- );
285
+ const { config, diagnostics } = normalizeAndValidateConfig(
286
+ expectedConfig,
287
+ undefined,
288
+ { env: undefined }
289
+ );
242
290
 
243
- expect(config).toEqual(expect.objectContaining(expectedConfig));
244
- expect(diagnostics.hasWarnings()).toBe(false);
245
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
291
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
292
+ expect(diagnostics.hasErrors()).toBe(false);
293
+ expect(diagnostics.hasWarnings()).toBe(true);
294
+
295
+ expect(normalizeSlashes(diagnostics.renderWarnings()))
296
+ .toMatchInlineSnapshot(`
246
297
  "Processing wrangler configuration:
247
- - ERROR: \\"migrations[0].tag\\" should be of type string but got 111.
248
- - ERROR: \\"migrations[0].new_classes.[0]\\" should be of type string but got 222.
249
- - ERROR: \\"migrations[0].new_classes.[1]\\" should be of type string but got 333.
250
- - \\"migrations[0].renamed_classes\\" should be an array of \\"{from: string, to: string}\\" objects but got [{\\"from\\":444,\\"to\\":555}].
251
- - ERROR: \\"migrations[0].deleted_classes.[0]\\" should be of type string but got 666.
252
- - ERROR: \\"migrations[0].deleted_classes.[1]\\" should be of type string but got 777."
298
+ - Deprecation: \\"site.entry-point\\":
299
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
300
+ \`\`\`
301
+ main = \\"my-site/index.js\\"
302
+ \`\`\`"
253
303
  `);
304
+ });
305
+
306
+ it("should error if `site` config is missing `bucket`", () => {
307
+ const expectedConfig: RawConfig = {
308
+ // @ts-expect-error we're intentionally passing an invalid configuration here
309
+ site: {
310
+ "entry-point": "workers-site",
311
+ include: ["INCLUDE_1", "INCLUDE_2"],
312
+ exclude: ["EXCLUDE_1", "EXCLUDE_2"],
313
+ },
314
+ };
315
+
316
+ const { config, diagnostics } = normalizeAndValidateConfig(
317
+ expectedConfig,
318
+ undefined,
319
+ { env: undefined }
320
+ );
321
+
322
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
323
+ expect(diagnostics.hasWarnings()).toBe(true);
324
+ expect(diagnostics.hasErrors()).toBe(true);
325
+
326
+ expect(normalizeSlashes(diagnostics.renderWarnings()))
327
+ .toMatchInlineSnapshot(`
328
+ "Processing wrangler configuration:
329
+ - Deprecation: \\"site.entry-point\\":
330
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
331
+ \`\`\`
332
+ main = \\"workers-site/index.js\\"
333
+ \`\`\`"
334
+ `);
335
+
336
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
337
+ "Processing wrangler configuration:
338
+ - \\"site.bucket\\" is a required field."
339
+ `);
340
+ });
341
+
342
+ it("should error on invalid `site` values", () => {
343
+ const expectedConfig = {
344
+ site: {
345
+ bucket: "BUCKET",
346
+ "entry-point": 111,
347
+ include: [222, 333],
348
+ exclude: [444, 555],
349
+ },
350
+ };
351
+
352
+ const { config, diagnostics } = normalizeAndValidateConfig(
353
+ expectedConfig as unknown as RawConfig,
354
+ undefined,
355
+ { env: undefined }
356
+ );
357
+
358
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
359
+ expect(diagnostics.hasWarnings()).toBe(true);
360
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
361
+ "Processing wrangler configuration:
362
+ - Expected \\"sites.include.[0]\\" to be of type string but got 222.
363
+ - Expected \\"sites.include.[1]\\" to be of type string but got 333.
364
+ - Expected \\"sites.exclude.[0]\\" to be of type string but got 444.
365
+ - Expected \\"sites.exclude.[1]\\" to be of type string but got 555.
366
+ - Expected \\"site.entry-point\\" to be of type string but got 111."
367
+ `);
368
+
369
+ expect(normalizeSlashes(diagnostics.renderWarnings()))
370
+ .toMatchInlineSnapshot(`
371
+ "Processing wrangler configuration:
372
+ - Deprecation: \\"site.entry-point\\":
373
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
374
+ \`\`\`
375
+ main = \\"111/index.js\\"
376
+ \`\`\`"
377
+ `);
378
+ });
379
+
380
+ it("should log a deprecation warning if entry-point is defined", async () => {
381
+ const { config, diagnostics } = normalizeAndValidateConfig(
382
+ {
383
+ site: {
384
+ bucket: "some/path",
385
+ "entry-point": "some/other/script.js",
386
+ },
387
+ } as unknown as RawConfig,
388
+ undefined,
389
+ { env: undefined }
390
+ );
391
+
392
+ expect(config.site).toMatchInlineSnapshot(`
393
+ Object {
394
+ "bucket": "some/path",
395
+ "entry-point": "some/other/script.js",
396
+ "exclude": Array [],
397
+ "include": Array [],
398
+ }
399
+ `);
400
+ expect(diagnostics.hasWarnings()).toBe(true);
401
+ expect(diagnostics.hasErrors()).toBe(false);
402
+
403
+ expect(normalizeSlashes(diagnostics.renderWarnings()))
404
+ .toMatchInlineSnapshot(`
405
+ "Processing wrangler configuration:
406
+ - Deprecation: \\"site.entry-point\\":
407
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
408
+ \`\`\`
409
+ main = \\"some/other/script.js\\"
410
+ \`\`\`"
411
+ `);
412
+ });
254
413
  });
255
414
 
256
- it("should override `site` config defaults with provided values", () => {
415
+ it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
257
416
  const expectedConfig: RawConfig = {
258
- site: {
259
- bucket: "BUCKET",
260
- "entry-point": "ENTRY_POINT",
261
- include: ["INCLUDE_1", "INCLUDE_2"],
262
- exclude: ["EXCLUDE_1", "EXCLUDE_2"],
417
+ wasm_modules: {
418
+ MODULE_1: "path/to/module_1.mjs",
419
+ MODULE_2: "module_2.mjs",
263
420
  },
264
421
  };
265
422
 
266
423
  const { config, diagnostics } = normalizeAndValidateConfig(
267
424
  expectedConfig,
268
- undefined
425
+ "project/wrangler.toml",
426
+ { env: undefined }
269
427
  );
270
428
 
271
- expect(config).toEqual(expect.objectContaining(expectedConfig));
429
+ expect(config).toEqual(
430
+ expect.objectContaining({
431
+ wasm_modules: {
432
+ MODULE_1: path.normalize("project/path/to/module_1.mjs"),
433
+ MODULE_2: path.normalize("project/module_2.mjs"),
434
+ },
435
+ })
436
+ );
272
437
  expect(diagnostics.hasErrors()).toBe(false);
273
438
  expect(diagnostics.hasWarnings()).toBe(false);
274
439
  });
275
440
 
276
- it("should error if `site` config is missing `bucket`", () => {
441
+ it("should warn on unexpected fields on `triggers`", async () => {
277
442
  const expectedConfig: RawConfig = {
278
- site: {
279
- "entry-point": "ENTRY_POINT",
280
- include: ["INCLUDE_1", "INCLUDE_2"],
281
- exclude: ["EXCLUDE_1", "EXCLUDE_2"],
443
+ triggers: {
444
+ crons: ["1 * * * *"],
445
+ // @ts-expect-error we're purposely adding a field
446
+ // that doesn't belong here
447
+ someOtherfield: 123,
282
448
  },
283
- } as RawConfig;
449
+ };
284
450
 
285
451
  const { config, diagnostics } = normalizeAndValidateConfig(
286
452
  expectedConfig,
287
- undefined
453
+ "project/wrangler.toml",
454
+ { env: undefined }
288
455
  );
289
456
 
290
- expect(config).toEqual(expect.objectContaining(expectedConfig));
291
- expect(diagnostics.hasErrors()).toBe(true);
292
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
293
- "Processing wrangler configuration:
294
- - ERROR: \\"site.bucket\\" is a required field."
295
- `);
296
- expect(diagnostics.hasWarnings()).toBe(false);
457
+ expect(config).toEqual(
458
+ expect.objectContaining({
459
+ triggers: {
460
+ crons: ["1 * * * *"],
461
+ someOtherfield: 123,
462
+ },
463
+ })
464
+ );
465
+ expect(diagnostics.hasErrors()).toBe(false);
466
+ expect(diagnostics.hasWarnings()).toBe(true);
467
+
468
+ expect(normalizePath(diagnostics.renderWarnings()))
469
+ .toMatchInlineSnapshot(`
470
+ "Processing project/wrangler.toml configuration:
471
+ - Unexpected fields found in triggers field: \\"someOtherfield\\""
472
+ `);
297
473
  });
298
474
 
299
- it("should error on invalid `site` values", () => {
475
+ it("should error on invalid `wasm_modules` paths", () => {
300
476
  const expectedConfig = {
301
- site: {
302
- bucket: "BUCKET",
303
- "entry-point": 111,
304
- include: [222, 333],
305
- exclude: [444, 555],
477
+ wasm_modules: {
478
+ MODULE_1: 111,
479
+ MODULE_2: 222,
306
480
  },
307
481
  };
308
482
 
309
483
  const { config, diagnostics } = normalizeAndValidateConfig(
310
484
  expectedConfig as unknown as RawConfig,
311
- undefined
485
+ "project/wrangler.toml",
486
+ { env: undefined }
312
487
  );
313
488
 
314
- expect(config).toEqual(expect.objectContaining(expectedConfig));
489
+ expect(config).toEqual(
490
+ expect.objectContaining({
491
+ wasm_modules: {},
492
+ })
493
+ );
315
494
  expect(diagnostics.hasWarnings()).toBe(false);
316
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
317
- "Processing wrangler configuration:
318
- - ERROR: \\"site.entry_point\\" should be of type string but got 111.
319
- - ERROR: \\"sites.include.[0]\\" should be of type string but got 222.
320
- - ERROR: \\"sites.include.[1]\\" should be of type string but got 333.
321
- - ERROR: \\"sites.exclude.[0]\\" should be of type string but got 444.
322
- - ERROR: \\"sites.exclude.[1]\\" should be of type string but got 555."
323
- `);
495
+ expect(normalizePath(diagnostics.renderErrors())).toMatchInlineSnapshot(`
496
+ "Processing project/wrangler.toml configuration:
497
+ - Expected \\"wasm_modules['MODULE_1']\\" to be of type string but got 111.
498
+ - Expected \\"wasm_modules['MODULE_2']\\" to be of type string but got 222."
499
+ `);
324
500
  });
325
501
 
326
- it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
502
+ it("should map `text_blobs` paths from relative to the config path to relative to the cwd", () => {
327
503
  const expectedConfig: RawConfig = {
328
- wasm_modules: {
329
- MODULE_1: "path/to/module_1.mjs",
330
- MODULE_2: "module_2.mjs",
504
+ text_blobs: {
505
+ BLOB_1: "path/to/text1.txt",
506
+ BLOB_2: "text2.md",
331
507
  },
332
508
  };
333
509
 
334
510
  const { config, diagnostics } = normalizeAndValidateConfig(
335
511
  expectedConfig,
336
- "project/wrangler.toml"
512
+ "project/wrangler.toml",
513
+ { env: undefined }
337
514
  );
338
515
 
339
516
  expect(config).toEqual(
340
517
  expect.objectContaining({
341
- wasm_modules: {
342
- MODULE_1: path.normalize("project/path/to/module_1.mjs"),
343
- MODULE_2: path.normalize("project/module_2.mjs"),
518
+ text_blobs: {
519
+ BLOB_1: path.normalize("project/path/to/text1.txt"),
520
+ BLOB_2: path.normalize("project/text2.md"),
344
521
  },
345
522
  })
346
523
  );
@@ -348,9 +525,9 @@ describe("normalizeAndValidateConfig()", () => {
348
525
  expect(diagnostics.hasWarnings()).toBe(false);
349
526
  });
350
527
 
351
- it("should error on invalid `wasm_module` paths", () => {
528
+ it("should error on invalid `text_blob` paths", () => {
352
529
  const expectedConfig = {
353
- wasm_modules: {
530
+ text_blobs: {
354
531
  MODULE_1: 111,
355
532
  MODULE_2: 222,
356
533
  },
@@ -358,40 +535,42 @@ describe("normalizeAndValidateConfig()", () => {
358
535
 
359
536
  const { config, diagnostics } = normalizeAndValidateConfig(
360
537
  expectedConfig as unknown as RawConfig,
361
- "project/wrangler.toml"
538
+ "project/wrangler.toml",
539
+ { env: undefined }
362
540
  );
363
541
 
364
542
  expect(config).toEqual(
365
543
  expect.objectContaining({
366
- wasm_modules: {},
544
+ text_blobs: {},
367
545
  })
368
546
  );
369
547
  expect(diagnostics.hasWarnings()).toBe(false);
370
548
  expect(normalizePath(diagnostics.renderErrors())).toMatchInlineSnapshot(`
371
- "Processing project/wrangler.toml configuration:
372
- - Expected \\"wasm_modules['MODULE_1']\\" field to be a string but got 111.
373
- - Expected \\"wasm_modules['MODULE_2']\\" field to be a string but got 222."
374
- `);
549
+ "Processing project/wrangler.toml configuration:
550
+ - Expected \\"text_blobs['MODULE_1']\\" to be of type string but got 111.
551
+ - Expected \\"text_blobs['MODULE_2']\\" to be of type string but got 222."
552
+ `);
375
553
  });
376
554
 
377
- it("should map `text_blobs` paths from relative to the config path to relative to the cwd", () => {
555
+ it("should map `data_blobs` paths from relative to the config path to relative to the cwd", () => {
378
556
  const expectedConfig: RawConfig = {
379
- text_blobs: {
380
- BLOB_1: "path/to/text1.txt",
381
- BLOB_2: "text2.md",
557
+ data_blobs: {
558
+ BLOB_1: "path/to/data1.bin",
559
+ BLOB_2: "data2.bin",
382
560
  },
383
561
  };
384
562
 
385
563
  const { config, diagnostics } = normalizeAndValidateConfig(
386
564
  expectedConfig,
387
- "project/wrangler.toml"
565
+ "project/wrangler.toml",
566
+ { env: undefined }
388
567
  );
389
568
 
390
569
  expect(config).toEqual(
391
570
  expect.objectContaining({
392
- text_blobs: {
393
- BLOB_1: path.normalize("project/path/to/text1.txt"),
394
- BLOB_2: path.normalize("project/text2.md"),
571
+ data_blobs: {
572
+ BLOB_1: path.normalize("project/path/to/data1.bin"),
573
+ BLOB_2: path.normalize("project/data2.bin"),
395
574
  },
396
575
  })
397
576
  );
@@ -399,9 +578,9 @@ describe("normalizeAndValidateConfig()", () => {
399
578
  expect(diagnostics.hasWarnings()).toBe(false);
400
579
  });
401
580
 
402
- it("should error on invalid `text_blob` paths", () => {
581
+ it("should error on invalid `data_blob` paths", () => {
403
582
  const expectedConfig = {
404
- text_blobs: {
583
+ data_blobs: {
405
584
  MODULE_1: 111,
406
585
  MODULE_2: 222,
407
586
  },
@@ -409,20 +588,42 @@ describe("normalizeAndValidateConfig()", () => {
409
588
 
410
589
  const { config, diagnostics } = normalizeAndValidateConfig(
411
590
  expectedConfig as unknown as RawConfig,
412
- "project/wrangler.toml"
591
+ "project/wrangler.toml",
592
+ { env: undefined }
413
593
  );
414
594
 
415
595
  expect(config).toEqual(
416
596
  expect.objectContaining({
417
- text_blobs: {},
597
+ data_blobs: {},
418
598
  })
419
599
  );
420
600
  expect(diagnostics.hasWarnings()).toBe(false);
421
601
  expect(normalizePath(diagnostics.renderErrors())).toMatchInlineSnapshot(`
422
- "Processing project/wrangler.toml configuration:
423
- - Expected \\"text_blobs['MODULE_1']\\" field to be a string but got 111.
424
- - Expected \\"text_blobs['MODULE_2']\\" field to be a string but got 222."
425
- `);
602
+ "Processing project/wrangler.toml configuration:
603
+ - Expected \\"data_blobs['MODULE_1']\\" to be of type string but got 111.
604
+ - Expected \\"data_blobs['MODULE_2']\\" to be of type string but got 222."
605
+ `);
606
+ });
607
+
608
+ it("should resolve tsconfig relative to wrangler.toml", async () => {
609
+ const expectedConfig: RawEnvironment = {
610
+ tsconfig: "path/to/some-tsconfig.json",
611
+ };
612
+
613
+ const { config, diagnostics } = normalizeAndValidateConfig(
614
+ expectedConfig,
615
+ "project/wrangler.toml",
616
+ { env: undefined }
617
+ );
618
+
619
+ expect(config).toEqual(
620
+ expect.objectContaining({
621
+ tsconfig: path.normalize("project/path/to/some-tsconfig.json"),
622
+ })
623
+ );
624
+
625
+ expect(diagnostics.hasErrors()).toBe(false);
626
+ expect(diagnostics.hasWarnings()).toBe(false);
426
627
  });
427
628
 
428
629
  describe("(deprecated)", () => {
@@ -434,7 +635,8 @@ describe("normalizeAndValidateConfig()", () => {
434
635
 
435
636
  const { config, diagnostics } = normalizeAndValidateConfig(
436
637
  rawConfig,
437
- undefined
638
+ undefined,
639
+ { env: undefined }
438
640
  );
439
641
 
440
642
  // Note the `.not.` here...
@@ -447,30 +649,44 @@ describe("normalizeAndValidateConfig()", () => {
447
649
  expect(diagnostics.hasErrors()).toBe(false);
448
650
  expect(diagnostics.hasWarnings()).toBe(true);
449
651
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
450
- "Processing wrangler configuration:
451
- - DEPRECATION: \\"type\\":
452
- DO NOT USE THIS. Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.
453
- - DEPRECATION: \\"webpack_config\\":
454
- DO NOT USE THIS. Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build."
455
- `);
652
+ "Processing wrangler configuration:
653
+ - 😶 Ignored: \\"type\\":
654
+ Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.
655
+ - 😶 Ignored: \\"webpack_config\\":
656
+ Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build."
657
+ `);
456
658
  });
457
659
  });
458
660
  });
459
661
 
460
- describe("top-level environment configuration", () => {
461
- it("should override config defaults with provided values", () => {
462
- const expectedConfig: RawConfig = {
463
- name: "NAME",
662
+ describe("top-level environment configuration", () => {
663
+ it("should override config defaults with provided values", () => {
664
+ const main = "src/index.ts";
665
+ const resolvedMain = path.resolve(process.cwd(), main);
666
+
667
+ const expectedConfig: RawEnvironment = {
668
+ name: "mock-name",
464
669
  account_id: "ACCOUNT_ID",
465
670
  compatibility_date: "2022-01-01",
466
671
  compatibility_flags: ["FLAG1", "FLAG2"],
467
672
  workers_dev: false,
468
- routes: ["ROUTE_1", "ROUTE_2"],
469
- route: "ROUTE_3",
673
+ routes: [
674
+ "ROUTE_1",
675
+ "ROUTE_2",
676
+ { pattern: "ROUTE3", zone_id: "ZONE_ID_3" },
677
+ "ROUTE_4",
678
+ ],
470
679
  jsx_factory: "JSX_FACTORY",
471
680
  jsx_fragment: "JSX_FRAGMENT",
681
+ tsconfig: "path/to/tsconfig",
472
682
  triggers: { crons: ["CRON_1", "CRON_2"] },
473
683
  usage_model: "bundled",
684
+ main,
685
+ build: {
686
+ command: "COMMAND",
687
+ cwd: "CWD",
688
+ watch_dir: "WATCH_DIR",
689
+ },
474
690
  vars: {
475
691
  VAR1: "VALUE_1",
476
692
  VAR2: "VALUE_2",
@@ -483,6 +699,12 @@ describe("normalizeAndValidateConfig()", () => {
483
699
  class_name: "CLASS2",
484
700
  script_name: "SCRIPT2",
485
701
  },
702
+ {
703
+ name: "DO_BINDING_3",
704
+ class_name: "CLASS3",
705
+ script_name: "SCRIPT3",
706
+ environment: "ENV3",
707
+ },
486
708
  ],
487
709
  },
488
710
  kv_namespaces: [
@@ -501,6 +723,13 @@ describe("normalizeAndValidateConfig()", () => {
501
723
  preview_bucket_name: "R2_PREVIEW_2",
502
724
  },
503
725
  ],
726
+ services: [
727
+ {
728
+ binding: "SERVICE_BINDING_1",
729
+ service: "SERVICE_TYPE_1",
730
+ environment: "SERVICE_BINDING_ENVIRONMENT_1",
731
+ },
732
+ ],
504
733
  unsafe: {
505
734
  bindings: [
506
735
  { name: "UNSAFE_BINDING_1", type: "UNSAFE_TYPE_1" },
@@ -511,63 +740,397 @@ describe("normalizeAndValidateConfig()", () => {
511
740
  },
512
741
  ],
513
742
  },
743
+ minify: true,
744
+ node_compat: true,
514
745
  };
515
746
 
516
747
  const { config, diagnostics } = normalizeAndValidateConfig(
517
748
  expectedConfig,
518
- undefined
749
+ undefined,
750
+ { env: undefined }
519
751
  );
520
752
 
521
- expect(config).toEqual(expect.objectContaining(expectedConfig));
753
+ expect(config).toEqual(
754
+ expect.objectContaining({ ...expectedConfig, main: resolvedMain })
755
+ );
522
756
  expect(diagnostics.hasErrors()).toBe(false);
523
757
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
524
- "Processing wrangler configuration:
525
- - \\"unsafe\\" fields are experimental and may change or break at any time."
526
- `);
758
+ "Processing wrangler configuration:
759
+ - \\"unsafe\\" fields are experimental and may change or break at any time.
760
+ - \\"services\\" fields are experimental and may change or break at any time.
761
+ - In wrangler.toml, you have configured [durable_objects] exported by this Worker (CLASS1), but no [migrations] for them. This may not work as expected until you add a [migrations] section to your wrangler.toml. Add this configuration to your wrangler.toml:
762
+
763
+ \`\`\`
764
+ [[migrations]]
765
+ tag = \\"v1\\" # Should be unique for each entry
766
+ new_classes = [\\"CLASS1\\"]
767
+ \`\`\`
768
+
769
+ Refer to https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml for more details."
770
+ `);
527
771
  });
528
772
 
529
773
  it("should error on invalid environment values", () => {
530
- const expectedConfig: RawConfig = {
774
+ const expectedConfig: RawEnvironment = {
531
775
  name: 111,
532
776
  account_id: 222,
533
777
  compatibility_date: 333,
534
778
  compatibility_flags: [444, 555],
535
779
  workers_dev: "BAD",
536
- routes: [666, 777],
780
+ routes: [
781
+ 666,
782
+ 777,
783
+ // this one's valid, but we add it here to make sure
784
+ // it doesn't get included in the error message
785
+ "example.com/*",
786
+ { pattern: 123, zone_id: "zone_id_1" },
787
+ { pattern: "route_2", zone_id: 123 },
788
+ { pattern: "route_2", zone_name: 123 },
789
+ { pattern: "route_3" },
790
+ { zone_id: "zone_id_4" },
791
+ { zone_name: "zone_name_4" },
792
+ { pattern: undefined },
793
+ { pattern: "route_5", zone_id: "zone_id_5", some_other_key: 123 },
794
+ { pattern: "route_5", zone_name: "zone_name_5", some_other_key: 123 },
795
+ // this one's valid too
796
+ { pattern: "route_6", zone_id: "zone_id_6" },
797
+ // as well as this one
798
+ { pattern: "route_6", zone_name: "zone_name_6" },
799
+ ],
537
800
  route: 888,
538
801
  jsx_factory: 999,
539
802
  jsx_fragment: 1000,
803
+ tsconfig: true,
540
804
  triggers: { crons: [1111, 1222] },
541
805
  usage_model: "INVALID",
542
- } as unknown as RawConfig;
806
+ main: 1333,
807
+ build: {
808
+ command: 1444,
809
+ cwd: 1555,
810
+ watch_dir: 1666,
811
+ },
812
+ minify: "INVALID",
813
+ node_compat: "INVALID",
814
+ } as unknown as RawEnvironment;
543
815
 
544
816
  const { config, diagnostics } = normalizeAndValidateConfig(
545
817
  expectedConfig,
546
- undefined
818
+ undefined,
819
+ { env: undefined }
547
820
  );
548
821
 
549
822
  expect(config).toEqual(expect.objectContaining(expectedConfig));
550
823
  expect(diagnostics.hasWarnings()).toBe(false);
551
824
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
552
825
  "Processing wrangler configuration:
553
- - Expected \\"route\\" field to be a string but got 888.
554
- - Expected \\"routes\\" field to be an array of strings but got [666,777].
555
- - Expected \\"workers_dev\\" field to be a boolean but got \\"BAD\\".
556
- - Expected \\"account_id\\" field to be a string but got 222.
557
- - Expected \\"compatibility_date\\" field to be a string but got 333.
558
- - Expected \\"compatibility_flags\\" field to be an array of strings but got [444,555].
559
- - Expected \\"jsx_factory\\" field to be a string but got 999.
560
- - Expected \\"jsx_fragment\\" field to be a string but got 1000.
561
- - Expected \\"name\\" field to be a string but got 111.
562
- - Expected \\"usage_model\\" field to be on of bundled,unbound but got \\"INVALID\\"."
826
+ - Expected \\"route\\" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got 888.
827
+ - Expected \\"routes\\" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: [
828
+ 666,
829
+ 777,
830
+ {
831
+ \\"pattern\\": 123,
832
+ \\"zone_id\\": \\"zone_id_1\\"
833
+ },
834
+ {
835
+ \\"pattern\\": \\"route_2\\",
836
+ \\"zone_id\\": 123
837
+ },
838
+ {
839
+ \\"pattern\\": \\"route_2\\",
840
+ \\"zone_name\\": 123
841
+ },
842
+ {
843
+ \\"pattern\\": \\"route_3\\"
844
+ },
845
+ {
846
+ \\"zone_id\\": \\"zone_id_4\\"
847
+ },
848
+ {
849
+ \\"zone_name\\": \\"zone_name_4\\"
850
+ },
851
+ {},
852
+ {
853
+ \\"pattern\\": \\"route_5\\",
854
+ \\"zone_id\\": \\"zone_id_5\\",
855
+ \\"some_other_key\\": 123
856
+ },
857
+ {
858
+ \\"pattern\\": \\"route_5\\",
859
+ \\"zone_name\\": \\"zone_name_5\\",
860
+ \\"some_other_key\\": 123
861
+ }
862
+ ].
863
+ - Expected exactly one of the following fields [\\"routes\\",\\"route\\"].
864
+ - Expected \\"workers_dev\\" to be of type boolean but got \\"BAD\\".
865
+ - Expected \\"build.command\\" to be of type string but got 1444.
866
+ - Expected \\"build.cwd\\" to be of type string but got 1555.
867
+ - Expected \\"build.watch_dir\\" to be of type string but got 1666.
868
+ - Expected \\"account_id\\" to be of type string but got 222.
869
+ - Expected \\"compatibility_date\\" to be of type string but got 333.
870
+ - Expected \\"compatibility_flags\\" to be of type string array but got [444,555].
871
+ - Expected \\"jsx_factory\\" to be of type string but got 999.
872
+ - Expected \\"jsx_fragment\\" to be of type string but got 1000.
873
+ - Expected \\"tsconfig\\" to be of type string but got true.
874
+ - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got 111.
875
+ - Expected \\"main\\" to be of type string but got 1333.
876
+ - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
877
+ - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
878
+ - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\"."
563
879
  `);
564
880
  });
565
881
 
882
+ describe("name", () => {
883
+ it("should error on invalid `name` value with spaces", () => {
884
+ const expectedConfig: RawEnvironment = {
885
+ name: "NCC 1701 D",
886
+ } as unknown as RawEnvironment;
887
+
888
+ const { config, diagnostics } = normalizeAndValidateConfig(
889
+ expectedConfig,
890
+ undefined,
891
+ { env: undefined }
892
+ );
893
+
894
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
895
+ expect(diagnostics.hasWarnings()).toBe(false);
896
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
897
+ "Processing wrangler configuration:
898
+ - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got \\"NCC 1701 D\\"."
899
+ `);
900
+ });
901
+
902
+ it("should be valid `name` with underscores", () => {
903
+ const expectedConfig: RawEnvironment = {
904
+ name: "enterprise_nx_01",
905
+ } as unknown as RawEnvironment;
906
+
907
+ const { config, diagnostics } = normalizeAndValidateConfig(
908
+ expectedConfig,
909
+ undefined,
910
+ { env: undefined }
911
+ );
912
+
913
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
914
+ expect(diagnostics.hasWarnings()).toBe(false);
915
+ expect(diagnostics.hasErrors()).toBe(false);
916
+ });
917
+
918
+ it("should error on invalid `name` value with special characters", () => {
919
+ const expectedConfig: RawEnvironment = {
920
+ name: "Thy'lek-Shran",
921
+ } as unknown as RawEnvironment;
922
+
923
+ const { config, diagnostics } = normalizeAndValidateConfig(
924
+ expectedConfig,
925
+ undefined,
926
+ { env: undefined }
927
+ );
928
+
929
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
930
+ expect(diagnostics.hasWarnings()).toBe(false);
931
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
932
+ "Processing wrangler configuration:
933
+ - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got \\"Thy'lek-Shran\\"."
934
+ `);
935
+ });
936
+
937
+ it("should error on invalid `name` value with only special characters", () => {
938
+ const expectedConfig: RawEnvironment = {
939
+ name: "!@#$%^&*(()",
940
+ } as unknown as RawEnvironment;
941
+
942
+ const { config, diagnostics } = normalizeAndValidateConfig(
943
+ expectedConfig,
944
+ undefined,
945
+ { env: undefined }
946
+ );
947
+
948
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
949
+ expect(diagnostics.hasWarnings()).toBe(false);
950
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
951
+ "Processing wrangler configuration:
952
+ - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got \\"!@#$%^&*(()\\"."
953
+ `);
954
+ });
955
+ });
956
+
957
+ describe("build", () => {
958
+ it("should override build.upload config defaults with provided values and warn about deprecations", () => {
959
+ const expectedConfig: RawEnvironment = {
960
+ build: {
961
+ upload: {
962
+ dir: "src",
963
+ format: "modules",
964
+ main: "index.ts",
965
+ rules: [{ type: "Text", globs: ["GLOB"], fallthrough: true }],
966
+ },
967
+ },
968
+ };
969
+
970
+ const { config, diagnostics } = normalizeAndValidateConfig(
971
+ expectedConfig,
972
+ path.resolve("project/wrangler.toml"),
973
+ { env: undefined }
974
+ );
975
+
976
+ expect(config.main).toEqual(path.resolve("project/src/index.ts"));
977
+ expect(config.build.upload).toBeUndefined();
978
+ expect(diagnostics.hasErrors()).toBe(false);
979
+ expect(diagnostics.hasWarnings()).toBe(true);
980
+ expect(normalizePath(diagnostics.renderWarnings()))
981
+ .toMatchInlineSnapshot(`
982
+ "Processing project/wrangler.toml configuration:
983
+ - Deprecation: \\"build.upload.format\\":
984
+ The format is inferred automatically from the code.
985
+ - Deprecation: \\"build.upload.main\\":
986
+ Delete the \`build.upload.main\` and \`build.upload.dir\` fields.
987
+ Then add the top level \`main\` field to your configuration file:
988
+ \`\`\`
989
+ main = \\"src/index.ts\\"
990
+ \`\`\`
991
+ - Deprecation: \\"build.upload.dir\\":
992
+ Use the top level \\"main\\" field or a command-line argument to specify the entry-point for the Worker.
993
+ - Deprecation: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:
994
+ \`\`\`
995
+ [[rules]]
996
+ type = \\"Text\\"
997
+ globs = [ \\"GLOB\\" ]
998
+ fallthrough = true
999
+ \`\`\`"
1000
+ `);
1001
+ });
1002
+
1003
+ it("should default custom build watch directories to src", () => {
1004
+ const expectedConfig: RawEnvironment = {
1005
+ build: {
1006
+ command: "execute some --build",
1007
+ },
1008
+ };
1009
+
1010
+ const { config, diagnostics } = normalizeAndValidateConfig(
1011
+ expectedConfig,
1012
+ undefined,
1013
+ { env: undefined }
1014
+ );
1015
+
1016
+ expect(config.build).toEqual(
1017
+ expect.objectContaining({
1018
+ command: "execute some --build",
1019
+ watch_dir: "./src",
1020
+ })
1021
+ );
1022
+
1023
+ expect(diagnostics.hasErrors()).toBe(false);
1024
+ expect(diagnostics.hasWarnings()).toBe(false);
1025
+ });
1026
+
1027
+ it("should resolve custom build watch directories relative to wrangler.toml", async () => {
1028
+ const expectedConfig: RawEnvironment = {
1029
+ build: {
1030
+ command: "execute some --build",
1031
+ watch_dir: "some/path",
1032
+ },
1033
+ };
1034
+
1035
+ const { config, diagnostics } = normalizeAndValidateConfig(
1036
+ expectedConfig,
1037
+ "project/wrangler.toml",
1038
+ { env: undefined }
1039
+ );
1040
+
1041
+ expect(config.build).toEqual(
1042
+ expect.objectContaining({
1043
+ command: "execute some --build",
1044
+ watch_dir: path.normalize("project/some/path"),
1045
+ })
1046
+ );
1047
+
1048
+ expect(diagnostics.hasErrors()).toBe(false);
1049
+ expect(diagnostics.hasWarnings()).toBe(false);
1050
+ });
1051
+
1052
+ it("should allow watch_dir to be an array of paths", () => {
1053
+ const expectedConfig: RawEnvironment = {
1054
+ build: {
1055
+ command: "execute some --build",
1056
+ watch_dir: ["some/path/a", "some/path/b", "some/path/c"],
1057
+ },
1058
+ };
1059
+
1060
+ const { config, diagnostics } = normalizeAndValidateConfig(
1061
+ expectedConfig,
1062
+ "project/wrangler.toml",
1063
+ { env: undefined }
1064
+ );
1065
+
1066
+ expect(config.build).toEqual(
1067
+ expect.objectContaining({
1068
+ command: "execute some --build",
1069
+ watch_dir: [
1070
+ path.normalize("project/some/path/a"),
1071
+ path.normalize("project/some/path/b"),
1072
+ path.normalize("project/some/path/c"),
1073
+ ],
1074
+ })
1075
+ );
1076
+
1077
+ expect(diagnostics.hasErrors()).toBe(false);
1078
+ expect(diagnostics.hasWarnings()).toBe(false);
1079
+ });
1080
+
1081
+ it("should error when the watch_dir array isn't an array of strings", () => {
1082
+ const expectedConfig: RawEnvironment = {
1083
+ build: {
1084
+ command: "execute some --build",
1085
+ watch_dir: [
1086
+ "some/path/a",
1087
+ "some/path/b",
1088
+ // @ts-expect-error intentionally bad "paths"
1089
+ 123,
1090
+ "some/path/c",
1091
+ // @ts-expect-error intentionally bad "paths"
1092
+ false,
1093
+ ],
1094
+ },
1095
+ };
1096
+
1097
+ const { config, diagnostics } = normalizeAndValidateConfig(
1098
+ expectedConfig,
1099
+ "project/wrangler.toml",
1100
+ { env: undefined }
1101
+ );
1102
+
1103
+ expect(config.build).toEqual(
1104
+ expect.objectContaining({
1105
+ command: "execute some --build",
1106
+ watch_dir: [
1107
+ path.normalize("project/some/path/a"),
1108
+ path.normalize("project/some/path/b"),
1109
+ path.normalize("project/123"),
1110
+ path.normalize("project/some/path/c"),
1111
+ path.normalize("project/false"),
1112
+ ],
1113
+ })
1114
+ );
1115
+
1116
+ expect(diagnostics.hasWarnings()).toBe(false);
1117
+ expect(diagnostics.hasErrors()).toBe(true);
1118
+
1119
+ expect(normalizePath(diagnostics.renderErrors()))
1120
+ .toMatchInlineSnapshot(`
1121
+ "Processing project/wrangler.toml configuration:
1122
+ - Expected \\"build.watch_dir.[2]\\" to be of type string but got 123.
1123
+ - Expected \\"build.watch_dir.[4]\\" to be of type string but got false."
1124
+ `);
1125
+ });
1126
+ });
1127
+
566
1128
  describe("durable_objects field", () => {
567
1129
  it("should error if durable_objects is an array", () => {
568
1130
  const { config, diagnostics } = normalizeAndValidateConfig(
569
1131
  { durable_objects: [] } as unknown as RawConfig,
570
- undefined
1132
+ undefined,
1133
+ { env: undefined }
571
1134
  );
572
1135
 
573
1136
  expect(config).toEqual(
@@ -583,7 +1146,8 @@ describe("normalizeAndValidateConfig()", () => {
583
1146
  it("should error if durable_objects is a string", () => {
584
1147
  const { config, diagnostics } = normalizeAndValidateConfig(
585
1148
  { durable_objects: "BAD" } as unknown as RawConfig,
586
- undefined
1149
+ undefined,
1150
+ { env: undefined }
587
1151
  );
588
1152
 
589
1153
  expect(config).toEqual(
@@ -599,7 +1163,8 @@ describe("normalizeAndValidateConfig()", () => {
599
1163
  it("should error if durable_objects is a number", () => {
600
1164
  const { config, diagnostics } = normalizeAndValidateConfig(
601
1165
  { durable_objects: 999 } as unknown as RawConfig,
602
- undefined
1166
+ undefined,
1167
+ { env: undefined }
603
1168
  );
604
1169
 
605
1170
  expect(config).toEqual(
@@ -615,7 +1180,8 @@ describe("normalizeAndValidateConfig()", () => {
615
1180
  it("should error if durable_objects is null", () => {
616
1181
  const { config, diagnostics } = normalizeAndValidateConfig(
617
1182
  { durable_objects: null } as unknown as RawConfig,
618
- undefined
1183
+ undefined,
1184
+ { env: undefined }
619
1185
  );
620
1186
 
621
1187
  expect(config).toEqual(
@@ -631,7 +1197,8 @@ describe("normalizeAndValidateConfig()", () => {
631
1197
  it("should error if durable_objects.bindings is not defined", () => {
632
1198
  const { config, diagnostics } = normalizeAndValidateConfig(
633
1199
  { durable_objects: {} } as unknown as RawConfig,
634
- undefined
1200
+ undefined,
1201
+ { env: undefined }
635
1202
  );
636
1203
 
637
1204
  expect(config).toEqual(
@@ -647,7 +1214,8 @@ describe("normalizeAndValidateConfig()", () => {
647
1214
  it("should error if durable_objects.bindings is an object", () => {
648
1215
  const { config, diagnostics } = normalizeAndValidateConfig(
649
1216
  { durable_objects: { bindings: {} } } as unknown as RawConfig,
650
- undefined
1217
+ undefined,
1218
+ { env: undefined }
651
1219
  );
652
1220
 
653
1221
  expect(config).toEqual(
@@ -665,7 +1233,8 @@ describe("normalizeAndValidateConfig()", () => {
665
1233
  it("should error if durable_objects.bindings is a string", () => {
666
1234
  const { config, diagnostics } = normalizeAndValidateConfig(
667
1235
  { durable_objects: { bindings: "BAD" } } as unknown as RawConfig,
668
- undefined
1236
+ undefined,
1237
+ { env: undefined }
669
1238
  );
670
1239
 
671
1240
  expect(config).toEqual(
@@ -683,7 +1252,8 @@ describe("normalizeAndValidateConfig()", () => {
683
1252
  it("should error if durable_objects.bindings is a number", () => {
684
1253
  const { config, diagnostics } = normalizeAndValidateConfig(
685
1254
  { durable_objects: { bindings: 999 } } as unknown as RawConfig,
686
- undefined
1255
+ undefined,
1256
+ { env: undefined }
687
1257
  );
688
1258
 
689
1259
  expect(config).toEqual(
@@ -701,7 +1271,8 @@ describe("normalizeAndValidateConfig()", () => {
701
1271
  it("should error if durable_objects.bindings is null", () => {
702
1272
  const { config, diagnostics } = normalizeAndValidateConfig(
703
1273
  { durable_objects: { bindings: null } } as unknown as RawConfig,
704
- undefined
1274
+ undefined,
1275
+ { env: undefined }
705
1276
  );
706
1277
 
707
1278
  expect(config).toEqual(
@@ -722,17 +1293,34 @@ describe("normalizeAndValidateConfig()", () => {
722
1293
  durable_objects: {
723
1294
  bindings: [
724
1295
  {},
725
- { name: "VALID" },
1296
+ { name: "MISSING_CLASS" },
726
1297
  { name: 1555, class_name: 1666 },
727
1298
  {
728
1299
  name: 1777,
729
1300
  class_name: 1888,
730
1301
  script_name: 1999,
731
1302
  },
1303
+ {
1304
+ name: "SOMENAME",
1305
+ class_name: "SomeClass",
1306
+ environment: "staging",
1307
+ },
1308
+ {
1309
+ name: 1778,
1310
+ class_name: 1889,
1311
+ script_name: 1992,
1312
+ environment: 2111,
1313
+ },
1314
+ {
1315
+ name: 1772,
1316
+ class_name: 1883,
1317
+ environment: 2112,
1318
+ },
732
1319
  ],
733
1320
  },
734
1321
  } as unknown as RawConfig,
735
- undefined
1322
+ undefined,
1323
+ { env: undefined }
736
1324
  );
737
1325
 
738
1326
  expect(config).toEqual(
@@ -741,24 +1329,41 @@ describe("normalizeAndValidateConfig()", () => {
741
1329
  })
742
1330
  );
743
1331
  expect(diagnostics.hasWarnings()).toBe(false);
1332
+
1333
+ expect(diagnostics.hasErrors()).toBe(true);
744
1334
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
745
1335
  "Processing wrangler configuration:
746
1336
 
747
1337
  - \\"durable_objects.bindings[0]\\": {}
748
- - ERROR: bindings should have a string \\"name\\" field.
749
- - ERROR: should have a string \\"class_name\\" field.
1338
+ - binding should have a string \\"name\\" field.
1339
+ - binding should have a string \\"class_name\\" field.
750
1340
 
751
- - \\"durable_objects.bindings[1]\\": {\\"name\\":\\"VALID\\"}
752
- - ERROR: should have a string \\"class_name\\" field.
1341
+ - \\"durable_objects.bindings[1]\\": {\\"name\\":\\"MISSING_CLASS\\"}
1342
+ - binding should have a string \\"class_name\\" field.
753
1343
 
754
1344
  - \\"durable_objects.bindings[2]\\": {\\"name\\":1555,\\"class_name\\":1666}
755
- - ERROR: bindings should have a string \\"name\\" field.
756
- - ERROR: should have a string \\"class_name\\" field.
1345
+ - binding should have a string \\"name\\" field.
1346
+ - binding should have a string \\"class_name\\" field.
757
1347
 
758
1348
  - \\"durable_objects.bindings[3]\\": {\\"name\\":1777,\\"class_name\\":1888,\\"script_name\\":1999}
759
- - ERROR: bindings should have a string \\"name\\" field.
760
- - ERROR: should have a string \\"class_name\\" field.
761
- - ERROR: should, optionally, have a string \\"script_name\\" field."
1349
+ - binding should have a string \\"name\\" field.
1350
+ - binding should have a string \\"class_name\\" field.
1351
+ - the field \\"script_name\\", when present, should be a string.
1352
+
1353
+ - \\"durable_objects.bindings[4]\\": {\\"name\\":\\"SOMENAME\\",\\"class_name\\":\\"SomeClass\\",\\"environment\\":\\"staging\\"}
1354
+ - binding should have a \\"script_name\\" field if \\"environment\\" is present.
1355
+
1356
+ - \\"durable_objects.bindings[5]\\": {\\"name\\":1778,\\"class_name\\":1889,\\"script_name\\":1992,\\"environment\\":2111}
1357
+ - binding should have a string \\"name\\" field.
1358
+ - binding should have a string \\"class_name\\" field.
1359
+ - the field \\"script_name\\", when present, should be a string.
1360
+ - the field \\"environment\\", when present, should be a string.
1361
+
1362
+ - \\"durable_objects.bindings[6]\\": {\\"name\\":1772,\\"class_name\\":1883,\\"environment\\":2112}
1363
+ - binding should have a string \\"name\\" field.
1364
+ - binding should have a string \\"class_name\\" field.
1365
+ - the field \\"environment\\", when present, should be a string.
1366
+ - binding should have a \\"script_name\\" field if \\"environment\\" is present."
762
1367
  `);
763
1368
  });
764
1369
  });
@@ -767,7 +1372,8 @@ describe("normalizeAndValidateConfig()", () => {
767
1372
  it("should error if kv_namespaces is an object", () => {
768
1373
  const { config, diagnostics } = normalizeAndValidateConfig(
769
1374
  { kv_namespaces: {} } as unknown as RawConfig,
770
- undefined
1375
+ undefined,
1376
+ { env: undefined }
771
1377
  );
772
1378
 
773
1379
  expect(config).toEqual(
@@ -783,7 +1389,8 @@ describe("normalizeAndValidateConfig()", () => {
783
1389
  it("should error if kv_namespaces is a string", () => {
784
1390
  const { config, diagnostics } = normalizeAndValidateConfig(
785
1391
  { kv_namespaces: "BAD" } as unknown as RawConfig,
786
- undefined
1392
+ undefined,
1393
+ { env: undefined }
787
1394
  );
788
1395
 
789
1396
  expect(config).toEqual(
@@ -799,7 +1406,8 @@ describe("normalizeAndValidateConfig()", () => {
799
1406
  it("should error if kv_namespaces is a number", () => {
800
1407
  const { config, diagnostics } = normalizeAndValidateConfig(
801
1408
  { kv_namespaces: 999 } as unknown as RawConfig,
802
- undefined
1409
+ undefined,
1410
+ { env: undefined }
803
1411
  );
804
1412
 
805
1413
  expect(config).toEqual(
@@ -815,7 +1423,8 @@ describe("normalizeAndValidateConfig()", () => {
815
1423
  it("should error if kv_namespaces is null", () => {
816
1424
  const { config, diagnostics } = normalizeAndValidateConfig(
817
1425
  { kv_namespaces: null } as unknown as RawConfig,
818
- undefined
1426
+ undefined,
1427
+ { env: undefined }
819
1428
  );
820
1429
 
821
1430
  expect(config).toEqual(
@@ -842,7 +1451,8 @@ describe("normalizeAndValidateConfig()", () => {
842
1451
  },
843
1452
  ],
844
1453
  } as unknown as RawConfig,
845
- undefined
1454
+ undefined,
1455
+ { env: undefined }
846
1456
  );
847
1457
 
848
1458
  expect(config).toEqual(
@@ -867,7 +1477,8 @@ describe("normalizeAndValidateConfig()", () => {
867
1477
  it("should error if r2_buckets is an object", () => {
868
1478
  const { config, diagnostics } = normalizeAndValidateConfig(
869
1479
  { r2_buckets: {} } as unknown as RawConfig,
870
- undefined
1480
+ undefined,
1481
+ { env: undefined }
871
1482
  );
872
1483
 
873
1484
  expect(config).toEqual(
@@ -883,7 +1494,8 @@ describe("normalizeAndValidateConfig()", () => {
883
1494
  it("should error if r2_buckets is a string", () => {
884
1495
  const { config, diagnostics } = normalizeAndValidateConfig(
885
1496
  { r2_buckets: "BAD" } as unknown as RawConfig,
886
- undefined
1497
+ undefined,
1498
+ { env: undefined }
887
1499
  );
888
1500
 
889
1501
  expect(config).toEqual(
@@ -899,7 +1511,8 @@ describe("normalizeAndValidateConfig()", () => {
899
1511
  it("should error if r2_buckets is a number", () => {
900
1512
  const { config, diagnostics } = normalizeAndValidateConfig(
901
1513
  { r2_buckets: 999 } as unknown as RawConfig,
902
- undefined
1514
+ undefined,
1515
+ { env: undefined }
903
1516
  );
904
1517
 
905
1518
  expect(config).toEqual(
@@ -915,7 +1528,8 @@ describe("normalizeAndValidateConfig()", () => {
915
1528
  it("should error if r2_buckets is null", () => {
916
1529
  const { config, diagnostics } = normalizeAndValidateConfig(
917
1530
  { r2_buckets: null } as unknown as RawConfig,
918
- undefined
1531
+ undefined,
1532
+ { env: undefined }
919
1533
  );
920
1534
 
921
1535
  expect(config).toEqual(
@@ -942,7 +1556,8 @@ describe("normalizeAndValidateConfig()", () => {
942
1556
  },
943
1557
  ],
944
1558
  } as unknown as RawConfig,
945
- undefined
1559
+ undefined,
1560
+ { env: undefined }
946
1561
  );
947
1562
 
948
1563
  expect(config).toEqual(
@@ -963,11 +1578,157 @@ describe("normalizeAndValidateConfig()", () => {
963
1578
  });
964
1579
  });
965
1580
 
1581
+ describe("services field", () => {
1582
+ it("should error if services is an object", () => {
1583
+ const { config, diagnostics } = normalizeAndValidateConfig(
1584
+ { services: {} } as unknown as RawConfig,
1585
+ undefined,
1586
+ { env: undefined }
1587
+ );
1588
+
1589
+ expect(config).toEqual(
1590
+ expect.not.objectContaining({ services: expect.anything })
1591
+ );
1592
+ expect(diagnostics.hasWarnings()).toBe(true);
1593
+ expect(diagnostics.hasErrors()).toBe(true);
1594
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1595
+ "Processing wrangler configuration:
1596
+ - \\"services\\" fields are experimental and may change or break at any time."
1597
+ `);
1598
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1599
+ "Processing wrangler configuration:
1600
+ - The field \\"services\\" should be an array but got {}."
1601
+ `);
1602
+ });
1603
+
1604
+ it("should error if services is a string", () => {
1605
+ const { config, diagnostics } = normalizeAndValidateConfig(
1606
+ { services: "BAD" } as unknown as RawConfig,
1607
+ undefined,
1608
+ { env: undefined }
1609
+ );
1610
+
1611
+ expect(config).toEqual(
1612
+ expect.not.objectContaining({ services: expect.anything })
1613
+ );
1614
+ expect(diagnostics.hasWarnings()).toBe(true);
1615
+ expect(diagnostics.hasErrors()).toBe(true);
1616
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1617
+ "Processing wrangler configuration:
1618
+ - \\"services\\" fields are experimental and may change or break at any time."
1619
+ `);
1620
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1621
+ "Processing wrangler configuration:
1622
+ - The field \\"services\\" should be an array but got \\"BAD\\"."
1623
+ `);
1624
+ });
1625
+
1626
+ it("should error if services is a number", () => {
1627
+ const { config, diagnostics } = normalizeAndValidateConfig(
1628
+ { services: 999 } as unknown as RawConfig,
1629
+ undefined,
1630
+ { env: undefined }
1631
+ );
1632
+
1633
+ expect(config).toEqual(
1634
+ expect.not.objectContaining({ services: expect.anything })
1635
+ );
1636
+ expect(diagnostics.hasWarnings()).toBe(true);
1637
+ expect(diagnostics.hasErrors()).toBe(true);
1638
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1639
+ "Processing wrangler configuration:
1640
+ - \\"services\\" fields are experimental and may change or break at any time."
1641
+ `);
1642
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1643
+ "Processing wrangler configuration:
1644
+ - The field \\"services\\" should be an array but got 999."
1645
+ `);
1646
+ });
1647
+
1648
+ it("should error if services is null", () => {
1649
+ const { config, diagnostics } = normalizeAndValidateConfig(
1650
+ { services: null } as unknown as RawConfig,
1651
+ undefined,
1652
+ { env: undefined }
1653
+ );
1654
+
1655
+ expect(config).toEqual(
1656
+ expect.not.objectContaining({ services: expect.anything })
1657
+ );
1658
+ expect(diagnostics.hasWarnings()).toBe(true);
1659
+ expect(diagnostics.hasErrors()).toBe(true);
1660
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1661
+ "Processing wrangler configuration:
1662
+ - \\"services\\" fields are experimental and may change or break at any time."
1663
+ `);
1664
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1665
+ "Processing wrangler configuration:
1666
+ - The field \\"services\\" should be an array but got null."
1667
+ `);
1668
+ });
1669
+
1670
+ it("should error if services bindings are not valid", () => {
1671
+ const { config, diagnostics } = normalizeAndValidateConfig(
1672
+ {
1673
+ services: [
1674
+ {},
1675
+ { binding: "SERVICE_BINDING_1" },
1676
+ { binding: 123, service: 456 },
1677
+ { binding: 123, service: 456, environment: 789 },
1678
+ { binding: "SERVICE_BINDING_1", service: 456, environment: 789 },
1679
+ {
1680
+ binding: 123,
1681
+ service: "SERVICE_BINDING_SERVICE_1",
1682
+ environment: 789,
1683
+ },
1684
+ {
1685
+ binding: 123,
1686
+ service: 456,
1687
+ environment: "SERVICE_BINDING_ENVIRONMENT_1",
1688
+ },
1689
+ ],
1690
+ } as unknown as RawConfig,
1691
+ undefined,
1692
+ { env: undefined }
1693
+ );
1694
+
1695
+ expect(config).toEqual(
1696
+ expect.not.objectContaining({
1697
+ services: { bindings: expect.anything },
1698
+ })
1699
+ );
1700
+ expect(diagnostics.hasWarnings()).toBe(true);
1701
+ expect(diagnostics.hasErrors()).toBe(true);
1702
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1703
+ "Processing wrangler configuration:
1704
+ - \\"services\\" fields are experimental and may change or break at any time."
1705
+ `);
1706
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1707
+ "Processing wrangler configuration:
1708
+ - \\"services[0]\\" bindings should have a string \\"binding\\" field but got {}.
1709
+ - \\"services[0]\\" bindings should have a string \\"service\\" field but got {}.
1710
+ - \\"services[1]\\" bindings should have a string \\"service\\" field but got {\\"binding\\":\\"SERVICE_BINDING_1\\"}.
1711
+ - \\"services[2]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":123,\\"service\\":456}.
1712
+ - \\"services[2]\\" bindings should have a string \\"service\\" field but got {\\"binding\\":123,\\"service\\":456}.
1713
+ - \\"services[3]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":123,\\"service\\":456,\\"environment\\":789}.
1714
+ - \\"services[3]\\" bindings should have a string \\"service\\" field but got {\\"binding\\":123,\\"service\\":456,\\"environment\\":789}.
1715
+ - \\"services[3]\\" bindings should have a string \\"environment\\" field but got {\\"binding\\":123,\\"service\\":456,\\"environment\\":789}.
1716
+ - \\"services[4]\\" bindings should have a string \\"service\\" field but got {\\"binding\\":\\"SERVICE_BINDING_1\\",\\"service\\":456,\\"environment\\":789}.
1717
+ - \\"services[4]\\" bindings should have a string \\"environment\\" field but got {\\"binding\\":\\"SERVICE_BINDING_1\\",\\"service\\":456,\\"environment\\":789}.
1718
+ - \\"services[5]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":123,\\"service\\":\\"SERVICE_BINDING_SERVICE_1\\",\\"environment\\":789}.
1719
+ - \\"services[5]\\" bindings should have a string \\"environment\\" field but got {\\"binding\\":123,\\"service\\":\\"SERVICE_BINDING_SERVICE_1\\",\\"environment\\":789}.
1720
+ - \\"services[6]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":123,\\"service\\":456,\\"environment\\":\\"SERVICE_BINDING_ENVIRONMENT_1\\"}.
1721
+ - \\"services[6]\\" bindings should have a string \\"service\\" field but got {\\"binding\\":123,\\"service\\":456,\\"environment\\":\\"SERVICE_BINDING_ENVIRONMENT_1\\"}."
1722
+ `);
1723
+ });
1724
+ });
1725
+
966
1726
  describe("unsafe field", () => {
967
1727
  it("should error if unsafe is an array", () => {
968
1728
  const { config, diagnostics } = normalizeAndValidateConfig(
969
1729
  { unsafe: [] } as unknown as RawConfig,
970
- undefined
1730
+ undefined,
1731
+ { env: undefined }
971
1732
  );
972
1733
 
973
1734
  expect(config).toEqual(
@@ -986,7 +1747,8 @@ describe("normalizeAndValidateConfig()", () => {
986
1747
  it("should error if unsafe is a string", () => {
987
1748
  const { config, diagnostics } = normalizeAndValidateConfig(
988
1749
  { unsafe: "BAD" } as unknown as RawConfig,
989
- undefined
1750
+ undefined,
1751
+ { env: undefined }
990
1752
  );
991
1753
 
992
1754
  expect(config).toEqual(
@@ -1005,7 +1767,8 @@ describe("normalizeAndValidateConfig()", () => {
1005
1767
  it("should error if unsafe is a number", () => {
1006
1768
  const { config, diagnostics } = normalizeAndValidateConfig(
1007
1769
  { unsafe: 999 } as unknown as RawConfig,
1008
- undefined
1770
+ undefined,
1771
+ { env: undefined }
1009
1772
  );
1010
1773
 
1011
1774
  expect(config).toEqual(
@@ -1024,7 +1787,8 @@ describe("normalizeAndValidateConfig()", () => {
1024
1787
  it("should error if unsafe is null", () => {
1025
1788
  const { config, diagnostics } = normalizeAndValidateConfig(
1026
1789
  { unsafe: null } as unknown as RawConfig,
1027
- undefined
1790
+ undefined,
1791
+ { env: undefined }
1028
1792
  );
1029
1793
 
1030
1794
  expect(config).toEqual(
@@ -1043,7 +1807,8 @@ describe("normalizeAndValidateConfig()", () => {
1043
1807
  it("should error if unsafe.bindings is not defined", () => {
1044
1808
  const { config, diagnostics } = normalizeAndValidateConfig(
1045
1809
  { unsafe: {} } as unknown as RawConfig,
1046
- undefined
1810
+ undefined,
1811
+ { env: undefined }
1047
1812
  );
1048
1813
 
1049
1814
  expect(config).toEqual(
@@ -1062,7 +1827,8 @@ describe("normalizeAndValidateConfig()", () => {
1062
1827
  it("should error if unsafe.bindings is an object", () => {
1063
1828
  const { config, diagnostics } = normalizeAndValidateConfig(
1064
1829
  { unsafe: { bindings: {} } } as unknown as RawConfig,
1065
- undefined
1830
+ undefined,
1831
+ { env: undefined }
1066
1832
  );
1067
1833
 
1068
1834
  expect(config).toEqual(
@@ -1083,7 +1849,8 @@ describe("normalizeAndValidateConfig()", () => {
1083
1849
  it("should error if unsafe.bindings is a string", () => {
1084
1850
  const { config, diagnostics } = normalizeAndValidateConfig(
1085
1851
  { unsafe: { bindings: "BAD" } } as unknown as RawConfig,
1086
- undefined
1852
+ undefined,
1853
+ { env: undefined }
1087
1854
  );
1088
1855
 
1089
1856
  expect(config).toEqual(
@@ -1104,7 +1871,8 @@ describe("normalizeAndValidateConfig()", () => {
1104
1871
  it("should error if unsafe.bindings is a number", () => {
1105
1872
  const { config, diagnostics } = normalizeAndValidateConfig(
1106
1873
  { unsafe: { bindings: 999 } } as unknown as RawConfig,
1107
- undefined
1874
+ undefined,
1875
+ { env: undefined }
1108
1876
  );
1109
1877
 
1110
1878
  expect(config).toEqual(
@@ -1125,7 +1893,8 @@ describe("normalizeAndValidateConfig()", () => {
1125
1893
  it("should error if unsafe.bindings is null", () => {
1126
1894
  const { config, diagnostics } = normalizeAndValidateConfig(
1127
1895
  { unsafe: { bindings: null } } as unknown as RawConfig,
1128
- undefined
1896
+ undefined,
1897
+ { env: undefined }
1129
1898
  );
1130
1899
 
1131
1900
  expect(config).toEqual(
@@ -1159,7 +1928,8 @@ describe("normalizeAndValidateConfig()", () => {
1159
1928
  ],
1160
1929
  },
1161
1930
  } as unknown as RawConfig,
1162
- undefined
1931
+ undefined,
1932
+ { env: undefined }
1163
1933
  );
1164
1934
 
1165
1935
  expect(config).toEqual(
@@ -1175,15 +1945,15 @@ describe("normalizeAndValidateConfig()", () => {
1175
1945
  "Processing wrangler configuration:
1176
1946
 
1177
1947
  - \\"unsafe.bindings[0]\\": {}
1178
- - ERROR: should have a string \\"name\\" field.
1179
- - ERROR: should have a string \\"type\\" field.
1948
+ - binding should have a string \\"name\\" field.
1949
+ - binding should have a string \\"type\\" field.
1180
1950
 
1181
1951
  - \\"unsafe.bindings[1]\\": {\\"name\\":\\"UNSAFE_BINDING_1\\"}
1182
- - ERROR: should have a string \\"type\\" field.
1952
+ - binding should have a string \\"type\\" field.
1183
1953
 
1184
1954
  - \\"unsafe.bindings[2]\\": {\\"name\\":2666,\\"type\\":2777}
1185
- - ERROR: should have a string \\"name\\" field.
1186
- - ERROR: should have a string \\"type\\" field."
1955
+ - binding should have a string \\"name\\" field.
1956
+ - binding should have a string \\"type\\" field."
1187
1957
  `);
1188
1958
  });
1189
1959
  });
@@ -1194,7 +1964,7 @@ describe("normalizeAndValidateConfig()", () => {
1194
1964
  zone_id: "ZONE_ID",
1195
1965
  experimental_services: [
1196
1966
  {
1197
- name: "NAME",
1967
+ name: "mock-name",
1198
1968
  service: "SERVICE",
1199
1969
  environment: "ENV",
1200
1970
  },
@@ -1203,7 +1973,8 @@ describe("normalizeAndValidateConfig()", () => {
1203
1973
 
1204
1974
  const { config, diagnostics } = normalizeAndValidateConfig(
1205
1975
  rawConfig,
1206
- undefined
1976
+ undefined,
1977
+ { env: undefined }
1207
1978
  );
1208
1979
 
1209
1980
  expect("experimental_services" in config).toBe(false);
@@ -1212,90 +1983,339 @@ describe("normalizeAndValidateConfig()", () => {
1212
1983
  expect(diagnostics.hasErrors()).toBe(false);
1213
1984
  expect(diagnostics.hasWarnings()).toBe(true);
1214
1985
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
1215
- "Processing wrangler configuration:
1216
- - DEPRECATION: \\"zone_id\\":
1217
- This is unnecessary since we can deduce this from routes directly.
1218
- - DEPRECATION: \\"experimental_services\\":
1219
- The \\"experimental_services\\" field is no longer supported. Instead, use [[unsafe.bindings]] to enable experimental features. Add this to your wrangler.toml:
1220
- \`\`\`
1221
- [[unsafe.bindings]]
1222
- name = \\"NAME\\"
1223
- type = \\"service\\"
1224
- service = \\"SERVICE\\"
1225
- environment = \\"ENV\\"
1226
- \`\`\`"
1227
- `);
1986
+ "Processing wrangler configuration:
1987
+ - Deprecation: \\"zone_id\\":
1988
+ This is unnecessary since we can deduce this from routes directly.
1989
+ - Deprecation: \\"experimental_services\\":
1990
+ The \\"experimental_services\\" field is no longer supported. Simply rename the [experimental_services] field to [services]."
1991
+ `);
1992
+ });
1993
+ });
1994
+
1995
+ describe("route & routes fields", () => {
1996
+ it("should error if both route and routes are specified", () => {
1997
+ const rawConfig: RawConfig = {
1998
+ route: "route1",
1999
+ routes: ["route2", "route3"],
2000
+ };
2001
+
2002
+ const { diagnostics } = normalizeAndValidateConfig(
2003
+ rawConfig,
2004
+ undefined,
2005
+ { env: undefined }
2006
+ );
2007
+
2008
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2009
+ "Processing wrangler configuration:
2010
+ - Expected exactly one of the following fields [\\"routes\\",\\"route\\"]."
2011
+ `);
1228
2012
  });
1229
2013
  });
1230
2014
  });
1231
2015
 
1232
2016
  describe("named environments", () => {
2017
+ it("should warn if we specify an environment but there are no named environments", () => {
2018
+ const rawConfig: RawConfig = {};
2019
+ const { diagnostics } = normalizeAndValidateConfig(rawConfig, undefined, {
2020
+ env: "DEV",
2021
+ });
2022
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2023
+ "Processing wrangler configuration:
2024
+ "
2025
+ `);
2026
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2027
+ "Processing wrangler configuration:
2028
+ - No environment found in configuration with name \\"DEV\\".
2029
+ Before using \`--env=DEV\` there should be an equivalent environment section in the configuration.
2030
+
2031
+ Consider adding an environment configuration section to the wrangler.toml file:
2032
+ \`\`\`
2033
+ [env.DEV]
2034
+ \`\`\`
2035
+ "
2036
+ `);
2037
+ });
2038
+
2039
+ it("should error if we specify an environment that does not match the named environments", () => {
2040
+ const rawConfig: RawConfig = { env: { ENV1: {} } };
2041
+ const { diagnostics } = normalizeAndValidateConfig(rawConfig, undefined, {
2042
+ env: "DEV",
2043
+ });
2044
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2045
+ "Processing wrangler configuration:
2046
+ - No environment found in configuration with name \\"DEV\\".
2047
+ Before using \`--env=DEV\` there should be an equivalent environment section in the configuration.
2048
+ The available configured environment names are: [\\"ENV1\\"]
2049
+
2050
+ Consider adding an environment configuration section to the wrangler.toml file:
2051
+ \`\`\`
2052
+ [env.DEV]
2053
+ \`\`\`
2054
+ "
2055
+ `);
2056
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2057
+ "Processing wrangler configuration:
2058
+ "
2059
+ `);
2060
+ });
2061
+
1233
2062
  it("should use top-level values for inheritable config fields", () => {
1234
- const expectedConfig: RawConfig = {
1235
- name: "NAME",
2063
+ const main = "src/index.ts";
2064
+ const resolvedMain = path.resolve(process.cwd(), main);
2065
+ const rawConfig: RawConfig = {
2066
+ name: "mock-name",
1236
2067
  account_id: "ACCOUNT_ID",
1237
2068
  compatibility_date: "2022-01-01",
1238
2069
  compatibility_flags: ["FLAG1", "FLAG2"],
1239
2070
  workers_dev: false,
1240
2071
  routes: ["ROUTE_1", "ROUTE_2"],
1241
- route: "ROUTE_3",
1242
2072
  jsx_factory: "JSX_FACTORY",
1243
2073
  jsx_fragment: "JSX_FRAGMENT",
2074
+ tsconfig: "path/to/tsconfig.json",
1244
2075
  triggers: { crons: ["CRON_1", "CRON_2"] },
1245
2076
  usage_model: "bundled",
2077
+ main,
2078
+ build: {
2079
+ command: "COMMAND",
2080
+ cwd: "CWD",
2081
+ watch_dir: "WATCH_DIR",
2082
+ },
2083
+ minify: true,
2084
+ node_compat: true,
1246
2085
  };
1247
2086
 
1248
2087
  const { config, diagnostics } = normalizeAndValidateConfig(
1249
- { ...expectedConfig, env: { DEV: {} } },
1250
- undefined
2088
+ { ...rawConfig, env: { dev: {} } },
2089
+ undefined,
2090
+ { env: "dev" }
1251
2091
  );
1252
2092
 
1253
- expect(config.env.DEV).toEqual(expect.objectContaining(expectedConfig));
2093
+ expect(config).toEqual(
2094
+ expect.objectContaining({
2095
+ ...rawConfig,
2096
+ main: resolvedMain,
2097
+ name: "mock-name-dev",
2098
+ })
2099
+ );
1254
2100
  expect(diagnostics.hasErrors()).toBe(false);
1255
2101
  expect(diagnostics.hasWarnings()).toBe(false);
1256
2102
  });
1257
2103
 
1258
2104
  it("should override top-level values for inheritable config fields", () => {
1259
- const environment: RawEnvironment = {
1260
- name: "ENV_NAME",
2105
+ const main = "src/index.ts";
2106
+ const resolvedMain = path.resolve(process.cwd(), main);
2107
+ const rawEnv: RawEnvironment = {
2108
+ name: "mock-env-name",
1261
2109
  account_id: "ENV_ACCOUNT_ID",
1262
2110
  compatibility_date: "2022-02-02",
1263
2111
  compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
1264
2112
  workers_dev: true,
1265
2113
  routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
1266
- route: "ENV_ROUTE_3",
1267
2114
  jsx_factory: "ENV_JSX_FACTORY",
1268
2115
  jsx_fragment: "ENV_JSX_FRAGMENT",
2116
+ tsconfig: "ENV_path/to/tsconfig.json",
1269
2117
  triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
1270
2118
  usage_model: "unbound",
2119
+ main,
2120
+ build: {
2121
+ command: "ENV_COMMAND",
2122
+ cwd: "ENV_CWD",
2123
+ watch_dir: "ENV_WATCH_DIR",
2124
+ },
2125
+ minify: false,
2126
+ node_compat: false,
1271
2127
  };
1272
- const expectedConfig: RawConfig = {
1273
- name: "NAME",
2128
+ const rawConfig: RawConfig = {
2129
+ name: "mock-name",
1274
2130
  account_id: "ACCOUNT_ID",
1275
2131
  compatibility_date: "2022-01-01",
1276
2132
  compatibility_flags: ["FLAG1", "FLAG2"],
1277
2133
  workers_dev: false,
1278
2134
  routes: ["ROUTE_1", "ROUTE_2"],
1279
- route: "ROUTE_3",
1280
2135
  jsx_factory: "JSX_FACTORY",
1281
2136
  jsx_fragment: "JSX_FRAGMENT",
2137
+ tsconfig: "path/to/tsconfig.json",
1282
2138
  triggers: { crons: ["CRON_1", "CRON_2"] },
1283
2139
  usage_model: "bundled",
2140
+ main: "top-level.js",
2141
+ build: {
2142
+ command: "COMMAND",
2143
+ cwd: "CWD",
2144
+ watch_dir: "WATCH_DIR",
2145
+ },
2146
+ minify: true,
2147
+ node_compat: true,
1284
2148
  env: {
1285
- ENV1: environment,
2149
+ ENV1: rawEnv,
1286
2150
  },
1287
2151
  };
1288
2152
 
1289
2153
  const { config, diagnostics } = normalizeAndValidateConfig(
1290
- expectedConfig,
1291
- undefined
2154
+ rawConfig,
2155
+ undefined,
2156
+ { env: "ENV1" }
1292
2157
  );
1293
2158
 
1294
- expect(config.env.ENV1).toEqual(expect.objectContaining(environment));
2159
+ expect(config).toEqual(
2160
+ expect.objectContaining({ ...rawEnv, main: resolvedMain })
2161
+ );
1295
2162
  expect(diagnostics.hasErrors()).toBe(false);
1296
2163
  expect(diagnostics.hasWarnings()).toBe(false);
1297
2164
  });
1298
2165
 
2166
+ describe("non-legacy", () => {
2167
+ it("should use top-level `name` field", () => {
2168
+ const rawConfig: RawConfig = {
2169
+ name: "mock-name",
2170
+ legacy_env: false,
2171
+ env: { DEV: {} },
2172
+ };
2173
+
2174
+ const { config, diagnostics } = normalizeAndValidateConfig(
2175
+ rawConfig,
2176
+ undefined,
2177
+ { env: "DEV" }
2178
+ );
2179
+
2180
+ expect(config.name).toEqual("mock-name");
2181
+ expect(diagnostics.hasErrors()).toBe(false);
2182
+ expect(diagnostics.hasWarnings()).toBe(true);
2183
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2184
+ "Processing wrangler configuration:
2185
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
2186
+ `);
2187
+ });
2188
+
2189
+ it("should error if named environment contains a `name` field, even if there is no top-level name", () => {
2190
+ const rawConfig: RawConfig = {
2191
+ legacy_env: false,
2192
+ env: {
2193
+ DEV: {
2194
+ name: "mock-env-name",
2195
+ },
2196
+ },
2197
+ };
2198
+
2199
+ const { config, diagnostics } = normalizeAndValidateConfig(
2200
+ rawConfig,
2201
+ undefined,
2202
+ { env: "DEV" }
2203
+ );
2204
+
2205
+ expect(config.name).toBeUndefined();
2206
+ expect(diagnostics.hasWarnings()).toBe(true);
2207
+ expect(diagnostics.hasErrors()).toBe(true);
2208
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2209
+ "Processing wrangler configuration:
2210
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
2211
+ `);
2212
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2213
+ "Processing wrangler configuration:
2214
+
2215
+ - \\"env.DEV\\" environment configuration
2216
+ - The \\"name\\" field is not allowed in named service environments.
2217
+ Please remove the field from this environment."
2218
+ `);
2219
+ });
2220
+
2221
+ it("should error if top-level config and a named environment both contain a `name` field", () => {
2222
+ const rawConfig: RawConfig = {
2223
+ name: "mock-name",
2224
+ legacy_env: false,
2225
+ env: {
2226
+ DEV: {
2227
+ name: "mock-env-name",
2228
+ },
2229
+ },
2230
+ };
2231
+
2232
+ const { config, diagnostics } = normalizeAndValidateConfig(
2233
+ rawConfig,
2234
+ undefined,
2235
+ { env: "DEV" }
2236
+ );
2237
+
2238
+ expect(config.name).toEqual("mock-name");
2239
+ expect(diagnostics.hasWarnings()).toBe(true);
2240
+ expect(diagnostics.hasErrors()).toBe(true);
2241
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2242
+ "Processing wrangler configuration:
2243
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
2244
+ `);
2245
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2246
+ "Processing wrangler configuration:
2247
+
2248
+ - \\"env.DEV\\" environment configuration
2249
+ - The \\"name\\" field is not allowed in named service environments.
2250
+ Please remove the field from this environment."
2251
+ `);
2252
+ });
2253
+ });
2254
+
2255
+ it("should error if named environment contains a `account_id` field, even if there is no top-level name", () => {
2256
+ const rawConfig: RawConfig = {
2257
+ legacy_env: false,
2258
+ env: {
2259
+ DEV: {
2260
+ account_id: "some_account_id",
2261
+ },
2262
+ },
2263
+ };
2264
+
2265
+ const { config, diagnostics } = normalizeAndValidateConfig(
2266
+ rawConfig,
2267
+ undefined,
2268
+ { env: "DEV" }
2269
+ );
2270
+
2271
+ expect(diagnostics.hasWarnings()).toBe(true);
2272
+ expect(config.account_id).toBeUndefined();
2273
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2274
+ "Processing wrangler configuration:
2275
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
2276
+ `);
2277
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2278
+ "Processing wrangler configuration:
2279
+
2280
+ - \\"env.DEV\\" environment configuration
2281
+ - The \\"account_id\\" field is not allowed in named service environments.
2282
+ Please remove the field from this environment."
2283
+ `);
2284
+ });
2285
+
2286
+ it("should error if top-level config and a named environment both contain a `account_id` field", () => {
2287
+ const rawConfig: RawConfig = {
2288
+ account_id: "ACCOUNT_ID",
2289
+ legacy_env: false,
2290
+ env: {
2291
+ DEV: {
2292
+ account_id: "ENV_ACCOUNT_ID",
2293
+ },
2294
+ },
2295
+ };
2296
+
2297
+ const { config, diagnostics } = normalizeAndValidateConfig(
2298
+ rawConfig,
2299
+ undefined,
2300
+ { env: "DEV" }
2301
+ );
2302
+
2303
+ expect(config.account_id).toEqual("ACCOUNT_ID");
2304
+ expect(diagnostics.hasErrors()).toBe(true);
2305
+ expect(diagnostics.hasWarnings()).toBe(true);
2306
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2307
+ "Processing wrangler configuration:
2308
+ - Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
2309
+ `);
2310
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2311
+ "Processing wrangler configuration:
2312
+
2313
+ - \\"env.DEV\\" environment configuration
2314
+ - The \\"account_id\\" field is not allowed in named service environments.
2315
+ Please remove the field from this environment."
2316
+ `);
2317
+ });
2318
+
1299
2319
  it("should warn for non-inherited fields that are missing in environments", () => {
1300
2320
  const vars: RawConfig["vars"] = {
1301
2321
  FOO: "foo",
@@ -1319,10 +2339,11 @@ describe("normalizeAndValidateConfig()", () => {
1319
2339
 
1320
2340
  const { config, diagnostics } = normalizeAndValidateConfig(
1321
2341
  rawConfig,
1322
- undefined
2342
+ undefined,
2343
+ { env: "ENV1" }
1323
2344
  );
1324
2345
 
1325
- expect(config.env.ENV1).toEqual(
2346
+ expect(config).toEqual(
1326
2347
  expect.not.objectContaining({
1327
2348
  vars,
1328
2349
  durable_objects,
@@ -1365,31 +2386,52 @@ describe("normalizeAndValidateConfig()", () => {
1365
2386
  route: 888,
1366
2387
  jsx_factory: 999,
1367
2388
  jsx_fragment: 1000,
2389
+ tsconfig: 123,
1368
2390
  triggers: { crons: [1111, 1222] },
1369
2391
  usage_model: "INVALID",
2392
+ main: 1333,
2393
+ build: {
2394
+ command: 1444,
2395
+ cwd: 1555,
2396
+ watch_dir: 1666,
2397
+ },
2398
+ minify: "INVALID",
2399
+ node_compat: "INVALID",
1370
2400
  } as unknown as RawEnvironment;
1371
2401
 
1372
2402
  const { config, diagnostics } = normalizeAndValidateConfig(
1373
2403
  { env: { ENV1: expectedConfig } },
1374
- undefined
2404
+ undefined,
2405
+ { env: "ENV1" }
1375
2406
  );
1376
2407
 
1377
- expect(config.env.ENV1).toEqual(expect.objectContaining(expectedConfig));
2408
+ expect(config).toEqual(expect.objectContaining(expectedConfig));
1378
2409
  expect(diagnostics.hasWarnings()).toBe(false);
1379
2410
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1380
2411
  "Processing wrangler configuration:
1381
2412
 
1382
2413
  - \\"env.ENV1\\" environment configuration
1383
- - Expected \\"route\\" field to be a string but got 888.
1384
- - Expected \\"routes\\" field to be an array of strings but got [666,777].
1385
- - Expected \\"workers_dev\\" field to be a boolean but got \\"BAD\\".
1386
- - Expected \\"account_id\\" field to be a string but got 222.
1387
- - Expected \\"compatibility_date\\" field to be a string but got 333.
1388
- - Expected \\"compatibility_flags\\" field to be an array of strings but got [444,555].
1389
- - Expected \\"jsx_factory\\" field to be a string but got 999.
1390
- - Expected \\"jsx_fragment\\" field to be a string but got 1000.
1391
- - Expected \\"name\\" field to be a string but got 111.
1392
- - Expected \\"usage_model\\" field to be on of bundled,unbound but got \\"INVALID\\"."
2414
+ - Expected \\"route\\" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got 888.
2415
+ - Expected \\"routes\\" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: [
2416
+ 666,
2417
+ 777
2418
+ ].
2419
+ - Expected exactly one of the following fields [\\"routes\\",\\"route\\"].
2420
+ - Expected \\"workers_dev\\" to be of type boolean but got \\"BAD\\".
2421
+ - Expected \\"build.command\\" to be of type string but got 1444.
2422
+ - Expected \\"build.cwd\\" to be of type string but got 1555.
2423
+ - Expected \\"build.watch_dir\\" to be of type string but got 1666.
2424
+ - Expected \\"account_id\\" to be of type string but got 222.
2425
+ - Expected \\"compatibility_date\\" to be of type string but got 333.
2426
+ - Expected \\"compatibility_flags\\" to be of type string array but got [444,555].
2427
+ - Expected \\"jsx_factory\\" to be of type string but got 999.
2428
+ - Expected \\"jsx_fragment\\" to be of type string but got 1000.
2429
+ - Expected \\"tsconfig\\" to be of type string but got 123.
2430
+ - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got 111.
2431
+ - Expected \\"main\\" to be of type string but got 1333.
2432
+ - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
2433
+ - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
2434
+ - Expected \\"node_compat\\" to be of type boolean but got \\"INVALID\\"."
1393
2435
  `);
1394
2436
  });
1395
2437
 
@@ -1397,10 +2439,11 @@ describe("normalizeAndValidateConfig()", () => {
1397
2439
  it("should error if durable_objects is an array", () => {
1398
2440
  const { config, diagnostics } = normalizeAndValidateConfig(
1399
2441
  { env: { ENV1: { durable_objects: [] } } } as unknown as RawConfig,
1400
- undefined
2442
+ undefined,
2443
+ { env: "ENV1" }
1401
2444
  );
1402
2445
 
1403
- expect(config.env.ENV1).toEqual(
2446
+ expect(config).toEqual(
1404
2447
  expect.not.objectContaining({ durable_objects: expect.anything })
1405
2448
  );
1406
2449
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1415,10 +2458,11 @@ describe("normalizeAndValidateConfig()", () => {
1415
2458
  it("should error if durable_objects is a string", () => {
1416
2459
  const { config, diagnostics } = normalizeAndValidateConfig(
1417
2460
  { env: { ENV1: { durable_objects: "BAD" } } } as unknown as RawConfig,
1418
- undefined
2461
+ undefined,
2462
+ { env: "ENV1" }
1419
2463
  );
1420
2464
 
1421
- expect(config.env.ENV1).toEqual(
2465
+ expect(config).toEqual(
1422
2466
  expect.not.objectContaining({ durable_objects: expect.anything })
1423
2467
  );
1424
2468
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1433,10 +2477,11 @@ describe("normalizeAndValidateConfig()", () => {
1433
2477
  it("should error if durable_objects is a number", () => {
1434
2478
  const { config, diagnostics } = normalizeAndValidateConfig(
1435
2479
  { env: { ENV1: { durable_objects: 999 } } } as unknown as RawConfig,
1436
- undefined
2480
+ undefined,
2481
+ { env: "ENV1" }
1437
2482
  );
1438
2483
 
1439
- expect(config.env.ENV1).toEqual(
2484
+ expect(config).toEqual(
1440
2485
  expect.not.objectContaining({ durable_objects: expect.anything })
1441
2486
  );
1442
2487
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1451,10 +2496,11 @@ describe("normalizeAndValidateConfig()", () => {
1451
2496
  it("should error if durable_objects is null", () => {
1452
2497
  const { config, diagnostics } = normalizeAndValidateConfig(
1453
2498
  { env: { ENV1: { durable_objects: null } } } as unknown as RawConfig,
1454
- undefined
2499
+ undefined,
2500
+ { env: "ENV1" }
1455
2501
  );
1456
2502
 
1457
- expect(config.env.ENV1).toEqual(
2503
+ expect(config).toEqual(
1458
2504
  expect.not.objectContaining({ durable_objects: expect.anything })
1459
2505
  );
1460
2506
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1469,10 +2515,11 @@ describe("normalizeAndValidateConfig()", () => {
1469
2515
  it("should error if durable_objects.bindings is not defined", () => {
1470
2516
  const { config, diagnostics } = normalizeAndValidateConfig(
1471
2517
  { env: { ENV1: { durable_objects: {} } } } as unknown as RawConfig,
1472
- undefined
2518
+ undefined,
2519
+ { env: "ENV1" }
1473
2520
  );
1474
2521
 
1475
- expect(config.env.ENV1).toEqual(
2522
+ expect(config).toEqual(
1476
2523
  expect.not.objectContaining({ durable_objects: expect.anything })
1477
2524
  );
1478
2525
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1489,10 +2536,11 @@ describe("normalizeAndValidateConfig()", () => {
1489
2536
  {
1490
2537
  env: { ENV1: { durable_objects: { bindings: {} } } },
1491
2538
  } as unknown as RawConfig,
1492
- undefined
2539
+ undefined,
2540
+ { env: "ENV1" }
1493
2541
  );
1494
2542
 
1495
- expect(config.env.ENV1).toEqual(
2543
+ expect(config).toEqual(
1496
2544
  expect.not.objectContaining({
1497
2545
  durable_objects: { bindings: expect.anything },
1498
2546
  })
@@ -1511,10 +2559,11 @@ describe("normalizeAndValidateConfig()", () => {
1511
2559
  {
1512
2560
  env: { ENV1: { durable_objects: { bindings: "BAD" } } },
1513
2561
  } as unknown as RawConfig,
1514
- undefined
2562
+ undefined,
2563
+ { env: "ENV1" }
1515
2564
  );
1516
2565
 
1517
- expect(config.env.ENV1).toEqual(
2566
+ expect(config).toEqual(
1518
2567
  expect.not.objectContaining({
1519
2568
  durable_objects: { bindings: expect.anything },
1520
2569
  })
@@ -1533,10 +2582,11 @@ describe("normalizeAndValidateConfig()", () => {
1533
2582
  {
1534
2583
  env: { ENV1: { durable_objects: { bindings: 999 } } },
1535
2584
  } as unknown as RawConfig,
1536
- undefined
2585
+ undefined,
2586
+ { env: "ENV1" }
1537
2587
  );
1538
2588
 
1539
- expect(config.env.ENV1).toEqual(
2589
+ expect(config).toEqual(
1540
2590
  expect.not.objectContaining({
1541
2591
  durable_objects: { bindings: expect.anything },
1542
2592
  })
@@ -1555,10 +2605,11 @@ describe("normalizeAndValidateConfig()", () => {
1555
2605
  {
1556
2606
  env: { ENV1: { durable_objects: { bindings: null } } },
1557
2607
  } as unknown as RawConfig,
1558
- undefined
2608
+ undefined,
2609
+ { env: "ENV1" }
1559
2610
  );
1560
2611
 
1561
- expect(config.env.ENV1).toEqual(
2612
+ expect(config).toEqual(
1562
2613
  expect.not.objectContaining({
1563
2614
  durable_objects: { bindings: expect.anything },
1564
2615
  })
@@ -1592,35 +2643,37 @@ describe("normalizeAndValidateConfig()", () => {
1592
2643
  },
1593
2644
  },
1594
2645
  } as unknown as RawConfig,
1595
- undefined
2646
+ undefined,
2647
+ { env: "ENV1" }
1596
2648
  );
1597
2649
 
1598
- expect(config.env.ENV1).toEqual(
2650
+ expect(config).toEqual(
1599
2651
  expect.not.objectContaining({
1600
2652
  durable_objects: { bindings: expect.anything },
1601
2653
  })
1602
2654
  );
1603
2655
  expect(diagnostics.hasWarnings()).toBe(false);
2656
+ expect(diagnostics.hasErrors()).toBe(true);
1604
2657
  expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
1605
2658
  "Processing wrangler configuration:
1606
2659
 
1607
2660
  - \\"env.ENV1\\" environment configuration
1608
2661
 
1609
2662
  - \\"env.ENV1.durable_objects.bindings[0]\\": {}
1610
- - ERROR: bindings should have a string \\"name\\" field.
1611
- - ERROR: should have a string \\"class_name\\" field.
2663
+ - binding should have a string \\"name\\" field.
2664
+ - binding should have a string \\"class_name\\" field.
1612
2665
 
1613
2666
  - \\"env.ENV1.durable_objects.bindings[1]\\": {\\"name\\":\\"VALID\\"}
1614
- - ERROR: should have a string \\"class_name\\" field.
2667
+ - binding should have a string \\"class_name\\" field.
1615
2668
 
1616
2669
  - \\"env.ENV1.durable_objects.bindings[2]\\": {\\"name\\":1555,\\"class_name\\":1666}
1617
- - ERROR: bindings should have a string \\"name\\" field.
1618
- - ERROR: should have a string \\"class_name\\" field.
2670
+ - binding should have a string \\"name\\" field.
2671
+ - binding should have a string \\"class_name\\" field.
1619
2672
 
1620
2673
  - \\"env.ENV1.durable_objects.bindings[3]\\": {\\"name\\":1777,\\"class_name\\":1888,\\"script_name\\":1999}
1621
- - ERROR: bindings should have a string \\"name\\" field.
1622
- - ERROR: should have a string \\"class_name\\" field.
1623
- - ERROR: should, optionally, have a string \\"script_name\\" field."
2674
+ - binding should have a string \\"name\\" field.
2675
+ - binding should have a string \\"class_name\\" field.
2676
+ - the field \\"script_name\\", when present, should be a string."
1624
2677
  `);
1625
2678
  });
1626
2679
  });
@@ -1629,10 +2682,11 @@ describe("normalizeAndValidateConfig()", () => {
1629
2682
  it("should error if kv_namespaces is an object", () => {
1630
2683
  const { config, diagnostics } = normalizeAndValidateConfig(
1631
2684
  { env: { ENV1: { kv_namespaces: {} } } } as unknown as RawConfig,
1632
- undefined
2685
+ undefined,
2686
+ { env: "ENV1" }
1633
2687
  );
1634
2688
 
1635
- expect(config.env.ENV1).toEqual(
2689
+ expect(config).toEqual(
1636
2690
  expect.not.objectContaining({ kv_namespaces: expect.anything })
1637
2691
  );
1638
2692
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1647,10 +2701,11 @@ describe("normalizeAndValidateConfig()", () => {
1647
2701
  it("should error if kv_namespaces is a string", () => {
1648
2702
  const { config, diagnostics } = normalizeAndValidateConfig(
1649
2703
  { env: { ENV1: { kv_namespaces: "BAD" } } } as unknown as RawConfig,
1650
- undefined
2704
+ undefined,
2705
+ { env: "ENV1" }
1651
2706
  );
1652
2707
 
1653
- expect(config.env.ENV1).toEqual(
2708
+ expect(config).toEqual(
1654
2709
  expect.not.objectContaining({ kv_namespaces: expect.anything })
1655
2710
  );
1656
2711
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1665,10 +2720,11 @@ describe("normalizeAndValidateConfig()", () => {
1665
2720
  it("should error if kv_namespaces is a number", () => {
1666
2721
  const { config, diagnostics } = normalizeAndValidateConfig(
1667
2722
  { env: { ENV1: { kv_namespaces: 999 } } } as unknown as RawConfig,
1668
- undefined
2723
+ undefined,
2724
+ { env: "ENV1" }
1669
2725
  );
1670
2726
 
1671
- expect(config.env.ENV1).toEqual(
2727
+ expect(config).toEqual(
1672
2728
  expect.not.objectContaining({ kv_namespaces: expect.anything })
1673
2729
  );
1674
2730
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1683,10 +2739,11 @@ describe("normalizeAndValidateConfig()", () => {
1683
2739
  it("should error if kv_namespaces is null", () => {
1684
2740
  const { config, diagnostics } = normalizeAndValidateConfig(
1685
2741
  { env: { ENV1: { kv_namespaces: null } } } as unknown as RawConfig,
1686
- undefined
2742
+ undefined,
2743
+ { env: "ENV1" }
1687
2744
  );
1688
2745
 
1689
- expect(config.env.ENV1).toEqual(
2746
+ expect(config).toEqual(
1690
2747
  expect.not.objectContaining({ kv_namespaces: expect.anything })
1691
2748
  );
1692
2749
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1716,10 +2773,11 @@ describe("normalizeAndValidateConfig()", () => {
1716
2773
  },
1717
2774
  },
1718
2775
  } as unknown as RawConfig,
1719
- undefined
2776
+ undefined,
2777
+ { env: "ENV1" }
1720
2778
  );
1721
2779
 
1722
- expect(config.env.ENV1).toEqual(
2780
+ expect(config).toEqual(
1723
2781
  expect.not.objectContaining({
1724
2782
  kv_namespaces: { bindings: expect.anything },
1725
2783
  })
@@ -1743,10 +2801,11 @@ describe("normalizeAndValidateConfig()", () => {
1743
2801
  it("should error if r2_buckets is an object", () => {
1744
2802
  const { config, diagnostics } = normalizeAndValidateConfig(
1745
2803
  { env: { ENV1: { r2_buckets: {} } } } as unknown as RawConfig,
1746
- undefined
2804
+ undefined,
2805
+ { env: "ENV1" }
1747
2806
  );
1748
2807
 
1749
- expect(config.env.ENV1).toEqual(
2808
+ expect(config).toEqual(
1750
2809
  expect.not.objectContaining({ r2_buckets: expect.anything })
1751
2810
  );
1752
2811
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1761,10 +2820,11 @@ describe("normalizeAndValidateConfig()", () => {
1761
2820
  it("should error if r2_buckets is a string", () => {
1762
2821
  const { config, diagnostics } = normalizeAndValidateConfig(
1763
2822
  { env: { ENV1: { r2_buckets: "BAD" } } } as unknown as RawConfig,
1764
- undefined
2823
+ undefined,
2824
+ { env: "ENV1" }
1765
2825
  );
1766
2826
 
1767
- expect(config.env.ENV1).toEqual(
2827
+ expect(config).toEqual(
1768
2828
  expect.not.objectContaining({ r2_buckets: expect.anything })
1769
2829
  );
1770
2830
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1779,10 +2839,11 @@ describe("normalizeAndValidateConfig()", () => {
1779
2839
  it("should error if r2_buckets is a number", () => {
1780
2840
  const { config, diagnostics } = normalizeAndValidateConfig(
1781
2841
  { env: { ENV1: { r2_buckets: 999 } } } as unknown as RawConfig,
1782
- undefined
2842
+ undefined,
2843
+ { env: "ENV1" }
1783
2844
  );
1784
2845
 
1785
- expect(config.env.ENV1).toEqual(
2846
+ expect(config).toEqual(
1786
2847
  expect.not.objectContaining({ r2_buckets: expect.anything })
1787
2848
  );
1788
2849
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1797,10 +2858,11 @@ describe("normalizeAndValidateConfig()", () => {
1797
2858
  it("should error if r2_buckets is null", () => {
1798
2859
  const { config, diagnostics } = normalizeAndValidateConfig(
1799
2860
  { env: { ENV1: { r2_buckets: null } } } as unknown as RawConfig,
1800
- undefined
2861
+ undefined,
2862
+ { env: "ENV1" }
1801
2863
  );
1802
2864
 
1803
- expect(config.env.ENV1).toEqual(
2865
+ expect(config).toEqual(
1804
2866
  expect.not.objectContaining({ r2_buckets: expect.anything })
1805
2867
  );
1806
2868
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -1830,10 +2892,11 @@ describe("normalizeAndValidateConfig()", () => {
1830
2892
  },
1831
2893
  },
1832
2894
  } as unknown as RawConfig,
1833
- undefined
2895
+ undefined,
2896
+ { env: "ENV1" }
1834
2897
  );
1835
2898
 
1836
- expect(config.env.ENV1).toEqual(
2899
+ expect(config).toEqual(
1837
2900
  expect.not.objectContaining({
1838
2901
  r2_buckets: { bindings: expect.anything },
1839
2902
  })
@@ -1857,10 +2920,11 @@ describe("normalizeAndValidateConfig()", () => {
1857
2920
  it("should error if unsafe is an array", () => {
1858
2921
  const { config, diagnostics } = normalizeAndValidateConfig(
1859
2922
  { env: { ENV1: { unsafe: [] } } } as unknown as RawConfig,
1860
- undefined
2923
+ undefined,
2924
+ { env: "ENV1" }
1861
2925
  );
1862
2926
 
1863
- expect(config.env.ENV1).toEqual(
2927
+ expect(config).toEqual(
1864
2928
  expect.not.objectContaining({ unsafe: expect.anything })
1865
2929
  );
1866
2930
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
@@ -1880,10 +2944,11 @@ describe("normalizeAndValidateConfig()", () => {
1880
2944
  it("should error if unsafe is a string", () => {
1881
2945
  const { config, diagnostics } = normalizeAndValidateConfig(
1882
2946
  { env: { ENV1: { unsafe: "BAD" } } } as unknown as RawConfig,
1883
- undefined
2947
+ undefined,
2948
+ { env: "ENV1" }
1884
2949
  );
1885
2950
 
1886
- expect(config.env.ENV1).toEqual(
2951
+ expect(config).toEqual(
1887
2952
  expect.not.objectContaining({ unsafe: expect.anything })
1888
2953
  );
1889
2954
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
@@ -1903,10 +2968,11 @@ describe("normalizeAndValidateConfig()", () => {
1903
2968
  it("should error if unsafe is a number", () => {
1904
2969
  const { config, diagnostics } = normalizeAndValidateConfig(
1905
2970
  { env: { ENV1: { unsafe: 999 } } } as unknown as RawConfig,
1906
- undefined
2971
+ undefined,
2972
+ { env: "ENV1" }
1907
2973
  );
1908
2974
 
1909
- expect(config.env.ENV1).toEqual(
2975
+ expect(config).toEqual(
1910
2976
  expect.not.objectContaining({ unsafe: expect.anything })
1911
2977
  );
1912
2978
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
@@ -1926,10 +2992,11 @@ describe("normalizeAndValidateConfig()", () => {
1926
2992
  it("should error if unsafe is null", () => {
1927
2993
  const { config, diagnostics } = normalizeAndValidateConfig(
1928
2994
  { env: { ENV1: { unsafe: null } } } as unknown as RawConfig,
1929
- undefined
2995
+ undefined,
2996
+ { env: "ENV1" }
1930
2997
  );
1931
2998
 
1932
- expect(config.env.ENV1).toEqual(
2999
+ expect(config).toEqual(
1933
3000
  expect.not.objectContaining({ unsafe: expect.anything })
1934
3001
  );
1935
3002
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
@@ -1949,10 +3016,11 @@ describe("normalizeAndValidateConfig()", () => {
1949
3016
  it("should error if unsafe.bindings is not defined", () => {
1950
3017
  const { config, diagnostics } = normalizeAndValidateConfig(
1951
3018
  { env: { ENV1: { unsafe: {} } } } as unknown as RawConfig,
1952
- undefined
3019
+ undefined,
3020
+ { env: "ENV1" }
1953
3021
  );
1954
3022
 
1955
- expect(config.env.ENV1).toEqual(
3023
+ expect(config).toEqual(
1956
3024
  expect.not.objectContaining({ unsafe: expect.anything })
1957
3025
  );
1958
3026
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
@@ -1974,10 +3042,11 @@ describe("normalizeAndValidateConfig()", () => {
1974
3042
  {
1975
3043
  env: { ENV1: { unsafe: { bindings: {} } } },
1976
3044
  } as unknown as RawConfig,
1977
- undefined
3045
+ undefined,
3046
+ { env: "ENV1" }
1978
3047
  );
1979
3048
 
1980
- expect(config.env.ENV1).toEqual(
3049
+ expect(config).toEqual(
1981
3050
  expect.not.objectContaining({
1982
3051
  unsafe: { bindings: expect.anything },
1983
3052
  })
@@ -2001,10 +3070,11 @@ describe("normalizeAndValidateConfig()", () => {
2001
3070
  {
2002
3071
  env: { ENV1: { unsafe: { bindings: "BAD" } } },
2003
3072
  } as unknown as RawConfig,
2004
- undefined
3073
+ undefined,
3074
+ { env: "ENV1" }
2005
3075
  );
2006
3076
 
2007
- expect(config.env.ENV1).toEqual(
3077
+ expect(config).toEqual(
2008
3078
  expect.not.objectContaining({
2009
3079
  unsafe: { bindings: expect.anything },
2010
3080
  })
@@ -2028,10 +3098,11 @@ describe("normalizeAndValidateConfig()", () => {
2028
3098
  {
2029
3099
  env: { ENV1: { unsafe: { bindings: 999 } } },
2030
3100
  } as unknown as RawConfig,
2031
- undefined
3101
+ undefined,
3102
+ { env: "ENV1" }
2032
3103
  );
2033
3104
 
2034
- expect(config.env.ENV1).toEqual(
3105
+ expect(config).toEqual(
2035
3106
  expect.not.objectContaining({
2036
3107
  unsafe: { bindings: expect.anything },
2037
3108
  })
@@ -2055,10 +3126,11 @@ describe("normalizeAndValidateConfig()", () => {
2055
3126
  {
2056
3127
  env: { ENV1: { unsafe: { bindings: null } } },
2057
3128
  } as unknown as RawConfig,
2058
- undefined
3129
+ undefined,
3130
+ { env: "ENV1" }
2059
3131
  );
2060
3132
 
2061
- expect(config.env.ENV1).toEqual(
3133
+ expect(config).toEqual(
2062
3134
  expect.not.objectContaining({
2063
3135
  unsafe: { bindings: expect.anything },
2064
3136
  })
@@ -2097,10 +3169,11 @@ describe("normalizeAndValidateConfig()", () => {
2097
3169
  },
2098
3170
  },
2099
3171
  } as unknown as RawConfig,
2100
- undefined
3172
+ undefined,
3173
+ { env: "ENV1" }
2101
3174
  );
2102
3175
 
2103
- expect(config.env.ENV1).toEqual(
3176
+ expect(config).toEqual(
2104
3177
  expect.not.objectContaining({
2105
3178
  durable_objects: { bindings: expect.anything },
2106
3179
  })
@@ -2117,15 +3190,15 @@ describe("normalizeAndValidateConfig()", () => {
2117
3190
  - \\"env.ENV1\\" environment configuration
2118
3191
 
2119
3192
  - \\"env.ENV1.unsafe.bindings[0]\\": {}
2120
- - ERROR: should have a string \\"name\\" field.
2121
- - ERROR: should have a string \\"type\\" field.
3193
+ - binding should have a string \\"name\\" field.
3194
+ - binding should have a string \\"type\\" field.
2122
3195
 
2123
3196
  - \\"env.ENV1.unsafe.bindings[1]\\": {\\"name\\":\\"UNSAFE_BINDING_1\\"}
2124
- - ERROR: should have a string \\"type\\" field.
3197
+ - binding should have a string \\"type\\" field.
2125
3198
 
2126
3199
  - \\"env.ENV1.unsafe.bindings[2]\\": {\\"name\\":2666,\\"type\\":2777}
2127
- - ERROR: should have a string \\"name\\" field.
2128
- - ERROR: should have a string \\"type\\" field."
3200
+ - binding should have a string \\"name\\" field.
3201
+ - binding should have a string \\"type\\" field."
2129
3202
  `);
2130
3203
  });
2131
3204
  });
@@ -2136,7 +3209,7 @@ describe("normalizeAndValidateConfig()", () => {
2136
3209
  zone_id: "ZONE_ID",
2137
3210
  experimental_services: [
2138
3211
  {
2139
- name: "NAME",
3212
+ name: "mock-name",
2140
3213
  service: "SERVICE",
2141
3214
  environment: "ENV",
2142
3215
  },
@@ -2149,31 +3222,260 @@ describe("normalizeAndValidateConfig()", () => {
2149
3222
  ENV1: environment,
2150
3223
  },
2151
3224
  },
2152
- undefined
3225
+ undefined,
3226
+ { env: "ENV1" }
2153
3227
  );
2154
3228
 
2155
- expect("experimental_services" in config.env.ENV1).toBe(false);
3229
+ expect("experimental_services" in config).toBe(false);
2156
3230
  // Zone is not removed yet, since `route` commands might use it
2157
- expect(config.env.ENV1.zone_id).toEqual("ZONE_ID");
3231
+ expect(config.zone_id).toEqual("ZONE_ID");
2158
3232
  expect(diagnostics.hasErrors()).toBe(false);
2159
3233
  expect(diagnostics.hasWarnings()).toBe(true);
2160
3234
  expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2161
3235
  "Processing wrangler configuration:
2162
3236
 
2163
3237
  - \\"env.ENV1\\" environment configuration
2164
- - DEPRECATION: \\"zone_id\\":
3238
+ - Deprecation: \\"zone_id\\":
2165
3239
  This is unnecessary since we can deduce this from routes directly.
2166
- - DEPRECATION: \\"experimental_services\\":
2167
- The \\"experimental_services\\" field is no longer supported. Instead, use [[unsafe.bindings]] to enable experimental features. Add this to your wrangler.toml:
2168
- \`\`\`
2169
- [[unsafe.bindings]]
2170
- name = \\"NAME\\"
2171
- type = \\"service\\"
2172
- service = \\"SERVICE\\"
2173
- environment = \\"ENV\\"
2174
- \`\`\`"
3240
+ - Deprecation: \\"experimental_services\\":
3241
+ The \\"experimental_services\\" field is no longer supported. Simply rename the [experimental_services] field to [services]."
3242
+ `);
3243
+ });
3244
+ });
3245
+
3246
+ describe("route & routes fields", () => {
3247
+ it("should error if both route and routes are specified in the same environment", () => {
3248
+ const environment: RawEnvironment = {
3249
+ name: "mock-env-name",
3250
+ account_id: "ENV_ACCOUNT_ID",
3251
+ compatibility_date: "2022-02-02",
3252
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3253
+ workers_dev: true,
3254
+ route: "ENV_ROUTE_1",
3255
+ routes: ["ENV_ROUTE_2", "ENV_ROUTE_3"],
3256
+ jsx_factory: "ENV_JSX_FACTORY",
3257
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3258
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3259
+ usage_model: "unbound",
3260
+ };
3261
+ const expectedConfig: RawConfig = {
3262
+ name: "mock-name",
3263
+ account_id: "ACCOUNT_ID",
3264
+ compatibility_date: "2022-01-01",
3265
+ compatibility_flags: ["FLAG1", "FLAG2"],
3266
+ workers_dev: false,
3267
+ routes: ["ROUTE_1", "ROUTE_2"],
3268
+ jsx_factory: "JSX_FACTORY",
3269
+ jsx_fragment: "JSX_FRAGMENT",
3270
+ triggers: { crons: ["CRON_1", "CRON_2"] },
3271
+ usage_model: "bundled",
3272
+ env: {
3273
+ ENV1: environment,
3274
+ },
3275
+ };
3276
+
3277
+ const { config, diagnostics } = normalizeAndValidateConfig(
3278
+ expectedConfig,
3279
+ undefined,
3280
+ { env: "ENV1" }
3281
+ );
3282
+
3283
+ expect(config).toEqual(expect.objectContaining(environment));
3284
+ expect(diagnostics.hasErrors()).toBe(true);
3285
+ expect(diagnostics.hasWarnings()).toBe(false);
3286
+
3287
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3288
+ "Processing wrangler configuration:
3289
+
3290
+ - \\"env.ENV1\\" environment configuration
3291
+ - Expected exactly one of the following fields [\\"routes\\",\\"route\\"]."
3292
+ `);
3293
+ });
3294
+
3295
+ it("should error if both route and routes are specified in the top-level environment", () => {
3296
+ const environment: RawEnvironment = {
3297
+ name: "mock-env-name",
3298
+ account_id: "ENV_ACCOUNT_ID",
3299
+ compatibility_date: "2022-02-02",
3300
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3301
+ workers_dev: true,
3302
+ routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
3303
+ jsx_factory: "ENV_JSX_FACTORY",
3304
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3305
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3306
+ usage_model: "unbound",
3307
+ };
3308
+ const expectedConfig: RawConfig = {
3309
+ name: "mock-name",
3310
+ account_id: "ACCOUNT_ID",
3311
+ compatibility_date: "2022-01-01",
3312
+ compatibility_flags: ["FLAG1", "FLAG2"],
3313
+ workers_dev: false,
3314
+ route: "ROUTE_1",
3315
+ routes: ["ROUTE_2", "ROUTE_3"],
3316
+ jsx_factory: "JSX_FACTORY",
3317
+ jsx_fragment: "JSX_FRAGMENT",
3318
+ triggers: { crons: ["CRON_1", "CRON_2"] },
3319
+ usage_model: "bundled",
3320
+ env: {
3321
+ ENV1: environment,
3322
+ },
3323
+ };
3324
+
3325
+ const { config, diagnostics } = normalizeAndValidateConfig(
3326
+ expectedConfig,
3327
+ undefined,
3328
+ { env: "ENV1" }
3329
+ );
3330
+
3331
+ expect(config).toEqual(expect.objectContaining(environment));
3332
+ expect(diagnostics.hasErrors()).toBe(true);
3333
+ expect(diagnostics.hasWarnings()).toBe(false);
3334
+
3335
+ expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
3336
+ "Processing wrangler configuration:
3337
+ - Expected exactly one of the following fields [\\"routes\\",\\"route\\"]."
2175
3338
  `);
2176
3339
  });
3340
+
3341
+ it("should not error if <env>.route and <top-level>.routes are specified", () => {
3342
+ const environment: RawEnvironment = {
3343
+ name: "mock-env-name",
3344
+ account_id: "ENV_ACCOUNT_ID",
3345
+ compatibility_date: "2022-02-02",
3346
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3347
+ workers_dev: true,
3348
+ route: "ENV_ROUTE_1",
3349
+ jsx_factory: "ENV_JSX_FACTORY",
3350
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3351
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3352
+ usage_model: "unbound",
3353
+ };
3354
+ const expectedConfig: RawConfig = {
3355
+ name: "mock-name",
3356
+ account_id: "ACCOUNT_ID",
3357
+ compatibility_date: "2022-01-01",
3358
+ compatibility_flags: ["FLAG1", "FLAG2"],
3359
+ workers_dev: false,
3360
+ routes: ["ROUTE_1", "ROUTE_2"],
3361
+ jsx_factory: "JSX_FACTORY",
3362
+ jsx_fragment: "JSX_FRAGMENT",
3363
+ triggers: { crons: ["CRON_1", "CRON_2"] },
3364
+ usage_model: "bundled",
3365
+ env: {
3366
+ ENV1: environment,
3367
+ },
3368
+ };
3369
+
3370
+ const { config, diagnostics } = normalizeAndValidateConfig(
3371
+ expectedConfig,
3372
+ undefined,
3373
+ { env: "ENV1" }
3374
+ );
3375
+
3376
+ expect(config).toEqual(expect.objectContaining(environment));
3377
+ expect(diagnostics.hasErrors()).toBe(false);
3378
+ expect(diagnostics.hasWarnings()).toBe(false);
3379
+ });
3380
+
3381
+ it("should not error if <env>.routes and <top-level>.route are specified", () => {
3382
+ const environment: RawEnvironment = {
3383
+ name: "mock-env-name",
3384
+ account_id: "ENV_ACCOUNT_ID",
3385
+ compatibility_date: "2022-02-02",
3386
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3387
+ workers_dev: true,
3388
+ routes: ["ENV_ROUTE_1", "ENV_ROUTE_2"],
3389
+ jsx_factory: "ENV_JSX_FACTORY",
3390
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3391
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3392
+ usage_model: "unbound",
3393
+ };
3394
+ const expectedConfig: RawConfig = {
3395
+ name: "mock-name",
3396
+ account_id: "ACCOUNT_ID",
3397
+ compatibility_date: "2022-01-01",
3398
+ compatibility_flags: ["FLAG1", "FLAG2"],
3399
+ workers_dev: false,
3400
+ route: "ROUTE_1",
3401
+ jsx_factory: "JSX_FACTORY",
3402
+ jsx_fragment: "JSX_FRAGMENT",
3403
+ triggers: { crons: ["CRON_1", "CRON_2"] },
3404
+ usage_model: "bundled",
3405
+ env: {
3406
+ ENV1: environment,
3407
+ },
3408
+ };
3409
+
3410
+ const { config, diagnostics } = normalizeAndValidateConfig(
3411
+ expectedConfig,
3412
+ undefined,
3413
+ { env: "ENV1" }
3414
+ );
3415
+
3416
+ expect(config).toEqual(expect.objectContaining(environment));
3417
+ expect(diagnostics.hasErrors()).toBe(false);
3418
+ expect(diagnostics.hasWarnings()).toBe(false);
3419
+ });
3420
+
3421
+ it("should not error if <env1>.route and <env2>.routes are specified", () => {
3422
+ const environment1: RawEnvironment = {
3423
+ name: "mock-env-name",
3424
+ account_id: "ENV_ACCOUNT_ID",
3425
+ compatibility_date: "2022-02-02",
3426
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3427
+ workers_dev: true,
3428
+ routes: ["ENV1_ROUTE_1", "ENV2_ROUTE_2"],
3429
+ jsx_factory: "ENV_JSX_FACTORY",
3430
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3431
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3432
+ usage_model: "unbound",
3433
+ };
3434
+ const environment2: RawEnvironment = {
3435
+ name: "mock-env-name",
3436
+ account_id: "ENV_ACCOUNT_ID",
3437
+ compatibility_date: "2022-02-02",
3438
+ compatibility_flags: ["ENV_FLAG1", "ENV_FLAG2"],
3439
+ workers_dev: true,
3440
+ route: "ENV2_ROUTE_1",
3441
+ jsx_factory: "ENV_JSX_FACTORY",
3442
+ jsx_fragment: "ENV_JSX_FRAGMENT",
3443
+ triggers: { crons: ["ENV_CRON_1", "ENV_CRON_2"] },
3444
+ usage_model: "unbound",
3445
+ };
3446
+ const expectedConfig: RawConfig = {
3447
+ name: "mock-name",
3448
+ account_id: "ACCOUNT_ID",
3449
+ compatibility_date: "2022-01-01",
3450
+ compatibility_flags: ["FLAG1", "FLAG2"],
3451
+ workers_dev: false,
3452
+ route: "ROUTE_1",
3453
+ jsx_factory: "JSX_FACTORY",
3454
+ jsx_fragment: "JSX_FRAGMENT",
3455
+ triggers: { crons: ["CRON_1", "CRON_2"] },
3456
+ usage_model: "bundled",
3457
+ env: {
3458
+ ENV1: environment1,
3459
+ ENV2: environment2,
3460
+ },
3461
+ };
3462
+
3463
+ const result1 = normalizeAndValidateConfig(expectedConfig, undefined, {
3464
+ env: "ENV1",
3465
+ });
3466
+
3467
+ expect(result1.config).toEqual(expect.objectContaining(environment1));
3468
+ expect(result1.diagnostics.hasErrors()).toBe(false);
3469
+ expect(result1.diagnostics.hasWarnings()).toBe(false);
3470
+
3471
+ const result2 = normalizeAndValidateConfig(expectedConfig, undefined, {
3472
+ env: "ENV2",
3473
+ });
3474
+
3475
+ expect(result2.config).toEqual(expect.objectContaining(environment2));
3476
+ expect(result2.diagnostics.hasErrors()).toBe(false);
3477
+ expect(result2.diagnostics.hasWarnings()).toBe(false);
3478
+ });
2177
3479
  });
2178
3480
  });
2179
3481
  });