@netlify/config 18.2.5-rc → 18.2.7-rc

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 (56) hide show
  1. package/bin.js +5 -0
  2. package/lib/api/build_settings.js +28 -0
  3. package/lib/api/client.js +12 -0
  4. package/lib/api/site_info.js +60 -0
  5. package/lib/base.js +26 -0
  6. package/lib/bin/flags.js +173 -0
  7. package/lib/bin/main.js +59 -0
  8. package/lib/build_dir.js +22 -0
  9. package/lib/cached_config.js +26 -0
  10. package/lib/case.js +18 -0
  11. package/lib/context.js +86 -0
  12. package/lib/default.js +27 -0
  13. package/lib/env/envelope.js +24 -0
  14. package/lib/env/git.js +21 -0
  15. package/lib/env/main.js +150 -0
  16. package/lib/error.js +28 -0
  17. package/lib/events.js +21 -0
  18. package/lib/files.js +83 -0
  19. package/lib/functions_config.js +67 -0
  20. package/lib/headers.js +20 -0
  21. package/lib/inline_config.js +8 -0
  22. package/lib/log/cleanup.js +64 -0
  23. package/lib/log/logger.js +36 -0
  24. package/lib/log/main.js +39 -0
  25. package/lib/log/messages.js +87 -0
  26. package/lib/log/options.js +29 -0
  27. package/lib/log/serialize.js +4 -0
  28. package/lib/log/theme.js +13 -0
  29. package/lib/main.js +211 -0
  30. package/lib/merge.js +43 -0
  31. package/lib/merge_normalize.js +24 -0
  32. package/lib/mutations/apply.js +66 -0
  33. package/lib/mutations/config_prop_name.js +14 -0
  34. package/lib/mutations/update.js +96 -0
  35. package/lib/normalize.js +32 -0
  36. package/lib/options/base.js +54 -0
  37. package/lib/options/branch.js +29 -0
  38. package/lib/options/feature_flags.js +12 -0
  39. package/lib/options/main.js +91 -0
  40. package/lib/options/repository_root.js +16 -0
  41. package/lib/origin.js +31 -0
  42. package/lib/parse.js +56 -0
  43. package/lib/path.js +41 -0
  44. package/lib/redirects.js +19 -0
  45. package/lib/simplify.js +77 -0
  46. package/lib/utils/group.js +9 -0
  47. package/lib/utils/remove_falsy.js +14 -0
  48. package/lib/utils/set.js +28 -0
  49. package/lib/utils/toml.js +20 -0
  50. package/lib/validate/context.js +38 -0
  51. package/lib/validate/example.js +30 -0
  52. package/lib/validate/helpers.js +25 -0
  53. package/lib/validate/identical.js +16 -0
  54. package/lib/validate/main.js +99 -0
  55. package/lib/validate/validations.js +275 -0
  56. package/package.json +9 -3
@@ -0,0 +1,275 @@
1
+ import CronParser from 'cron-parser';
2
+ import isPlainObj from 'is-plain-obj';
3
+ import validateNpmPackageName from 'validate-npm-package-name';
4
+ import { bundlers, WILDCARD_ALL as FUNCTIONS_CONFIG_WILDCARD_ALL } from '../functions_config.js';
5
+ import { functionsDirectoryCheck, isArrayOfObjects, isArrayOfStrings, isString, validProperties } from './helpers.js';
6
+ /**
7
+ * @param {string} cron
8
+ * @returns {boolean}
9
+ */
10
+ const isValidCronExpression = (cron) => {
11
+ try {
12
+ CronParser.parseExpression(cron);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ };
19
+ // List of validations performed on the configuration file.
20
+ // Validation are performed in order: parent should be before children.
21
+ // Each validation is an object with the following properties:
22
+ // - `property` {string}: dot-delimited path to the property.
23
+ // Can contain `*` providing a previous check validates the parent is an
24
+ // object or an array.
25
+ // - `propertyName` {string}: human-friendly property name; overrides the
26
+ // value of `property` when displaying an error message
27
+ // - `check` {(value, key, prevPath) => boolean}: validation check function
28
+ // - `message` {string}: error message
29
+ // - `example` {string}: example of correct code
30
+ // - `formatInvalid` {(object) => object}: formats the invalid value when
31
+ // displaying an error message
32
+ // We use this instead of JSON schema (or others) to get nicer error messages.
33
+ // Validations done before case normalization
34
+ export const PRE_CASE_NORMALIZE_VALIDATIONS = [
35
+ {
36
+ property: 'build',
37
+ check: isPlainObj,
38
+ message: 'must be a plain object.',
39
+ example: () => ({ build: { command: 'npm run build' } }),
40
+ },
41
+ ];
42
+ // Properties with an `origin` property need to be validated twice:
43
+ // - Before the `origin` property is added
44
+ // - After `context.*` is merged, since they might contain that property
45
+ const ORIGIN_VALIDATIONS = [
46
+ {
47
+ property: 'build.command',
48
+ check: isString,
49
+ message: 'must be a string',
50
+ example: () => ({ build: { command: 'npm run build' } }),
51
+ },
52
+ {
53
+ property: 'plugins',
54
+ check: isArrayOfObjects,
55
+ message: 'must be an array of objects.',
56
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one' }, { package: 'netlify-plugin-two' }] }),
57
+ },
58
+ ];
59
+ // Validations done before `defaultConfig` merge
60
+ export const PRE_MERGE_VALIDATIONS = [...ORIGIN_VALIDATIONS];
61
+ // Validations done before context merge
62
+ export const PRE_CONTEXT_VALIDATIONS = [
63
+ {
64
+ property: 'context',
65
+ check: isPlainObj,
66
+ message: 'must be a plain object.',
67
+ example: () => ({ context: { production: { publish: 'dist' } } }),
68
+ },
69
+ {
70
+ property: 'context.*',
71
+ check: isPlainObj,
72
+ message: 'must be a plain object.',
73
+ example: (contextProps, key) => ({ context: { [key]: { publish: 'dist' } } }),
74
+ },
75
+ ];
76
+ // Validations done before normalization
77
+ export const PRE_NORMALIZE_VALIDATIONS = [
78
+ ...ORIGIN_VALIDATIONS,
79
+ {
80
+ property: 'functions',
81
+ check: isPlainObj,
82
+ message: 'must be an object.',
83
+ example: () => ({
84
+ functions: { external_node_modules: ['module-one', 'module-two'] },
85
+ }),
86
+ },
87
+ {
88
+ property: 'functions',
89
+ check: isPlainObj,
90
+ message: 'must be an object.',
91
+ example: () => ({
92
+ functions: { ignored_node_modules: ['module-one', 'module-two'] },
93
+ }),
94
+ },
95
+ {
96
+ property: 'edge_functions',
97
+ check: isArrayOfObjects,
98
+ message: 'must be an array of objects.',
99
+ example: () => ({
100
+ edge_functions: [
101
+ { path: '/hello', function: 'hello' },
102
+ { path: '/auth', function: 'auth' },
103
+ ],
104
+ }),
105
+ },
106
+ ];
107
+ const EXAMPLE_PORT = 80;
108
+ // Validations done after normalization
109
+ export const POST_NORMALIZE_VALIDATIONS = [
110
+ {
111
+ property: 'plugins.*',
112
+ ...validProperties(['package', 'pinned_version', 'inputs'], ['origin']),
113
+ example: { plugins: [{ package: 'netlify-plugin-one', inputs: { port: EXAMPLE_PORT } }] },
114
+ },
115
+ {
116
+ property: 'plugins.*',
117
+ check: (plugin) => plugin.package !== undefined,
118
+ message: '"package" property is required.',
119
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one' }] }),
120
+ },
121
+ {
122
+ property: 'plugins.*.package',
123
+ check: isString,
124
+ message: 'must be a string.',
125
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one' }] }),
126
+ },
127
+ // We don't allow `package@tag|version` nor `git:...`, `github:...`,
128
+ // `https://...`, etc.
129
+ // We skip this validation for local plugins.
130
+ // We ensure @scope/plugin still work.
131
+ {
132
+ property: 'plugins.*.package',
133
+ check: (packageName) => packageName.startsWith('.') ||
134
+ packageName.startsWith('/') ||
135
+ validateNpmPackageName(packageName).validForOldPackages,
136
+ message: 'must be a npm package name only.',
137
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one' }] }),
138
+ },
139
+ {
140
+ property: 'plugins.*.pinned_version',
141
+ check: isString,
142
+ message: 'must be a string.',
143
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one', pinned_version: '1' }] }),
144
+ },
145
+ {
146
+ property: 'plugins.*.inputs',
147
+ check: isPlainObj,
148
+ message: 'must be a plain object.',
149
+ example: () => ({ plugins: [{ package: 'netlify-plugin-one', inputs: { port: EXAMPLE_PORT } }] }),
150
+ },
151
+ {
152
+ property: 'build.base',
153
+ check: isString,
154
+ message: 'must be a string.',
155
+ example: () => ({ build: { base: 'packages/project' } }),
156
+ },
157
+ {
158
+ property: 'build.publish',
159
+ check: isString,
160
+ message: 'must be a string.',
161
+ example: () => ({ build: { publish: 'dist' } }),
162
+ },
163
+ {
164
+ property: 'build.functions',
165
+ check: isString,
166
+ message: 'must be a string.',
167
+ example: () => ({ build: { functions: 'functions' } }),
168
+ },
169
+ {
170
+ property: 'build.edge_functions',
171
+ check: isString,
172
+ message: 'must be a string.',
173
+ example: () => ({ build: { edge_functions: 'edge-functions' } }),
174
+ },
175
+ {
176
+ property: 'functions.*',
177
+ check: isPlainObj,
178
+ message: 'must be an object.',
179
+ example: (value, key, prevPath) => ({
180
+ functions: { [prevPath[1]]: { external_node_modules: ['module-one', 'module-two'] } },
181
+ }),
182
+ },
183
+ {
184
+ property: 'functions.*.external_node_modules',
185
+ check: isArrayOfStrings,
186
+ message: 'must be an array of strings.',
187
+ example: (value, key, prevPath) => ({
188
+ functions: { [prevPath[1]]: { external_node_modules: ['module-one', 'module-two'] } },
189
+ }),
190
+ },
191
+ {
192
+ property: 'functions.*.ignored_node_modules',
193
+ check: isArrayOfStrings,
194
+ message: 'must be an array of strings.',
195
+ example: (value, key, prevPath) => ({
196
+ functions: { [prevPath[1]]: { ignored_node_modules: ['module-one', 'module-two'] } },
197
+ }),
198
+ },
199
+ {
200
+ property: 'functions.*.included_files',
201
+ check: isArrayOfStrings,
202
+ message: 'must be an array of strings.',
203
+ example: (value, key, prevPath) => ({
204
+ functions: { [prevPath[1]]: { included_files: ['directory-one/file1', 'directory-two/**/*.jpg'] } },
205
+ }),
206
+ },
207
+ {
208
+ property: 'functions.*.node_bundler',
209
+ check: (value) => bundlers.includes(value),
210
+ message: `must be one of: ${bundlers.join(', ')}`,
211
+ example: (value, key, prevPath) => ({
212
+ functions: { [prevPath[1]]: { node_bundler: bundlers[0] } },
213
+ }),
214
+ },
215
+ {
216
+ property: 'functions.*.directory',
217
+ check: (value, key, prevPath) => prevPath[1] === FUNCTIONS_CONFIG_WILDCARD_ALL,
218
+ message: 'must be defined on the main `functions` object.',
219
+ example: () => ({
220
+ functions: { directory: 'my-functions' },
221
+ }),
222
+ },
223
+ {
224
+ property: 'functions.*.schedule',
225
+ check: isValidCronExpression,
226
+ message: 'must be a valid cron expression (see https://ntl.fyi/cron-syntax).',
227
+ example: (value, key, prevPath) => ({
228
+ functions: { [prevPath[1]]: { schedule: '5 4 * * *' } },
229
+ }),
230
+ },
231
+ {
232
+ property: 'functionsDirectory',
233
+ check: isString,
234
+ message: 'must be a string.',
235
+ ...functionsDirectoryCheck,
236
+ example: () => ({
237
+ functions: { directory: 'my-functions' },
238
+ }),
239
+ },
240
+ {
241
+ property: 'edge_functions.*',
242
+ ...validProperties(['path', 'function'], []),
243
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
244
+ },
245
+ {
246
+ property: 'edge_functions.*',
247
+ check: (edgeFunction) => edgeFunction.path !== undefined,
248
+ message: '"path" property is required.',
249
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
250
+ },
251
+ {
252
+ property: 'edge_functions.*',
253
+ check: (edgeFunction) => edgeFunction.function !== undefined,
254
+ message: '"function" property is required.',
255
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
256
+ },
257
+ {
258
+ property: 'edge_functions.*.path',
259
+ check: isString,
260
+ message: 'must be a string.',
261
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
262
+ },
263
+ {
264
+ property: 'edge_functions.*.function',
265
+ check: isString,
266
+ message: 'must be a string.',
267
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
268
+ },
269
+ {
270
+ property: 'edge_functions.*.path',
271
+ check: (pathName) => pathName.startsWith('/'),
272
+ message: 'must be a valid path.',
273
+ example: () => ({ edge_functions: [{ path: '/hello', function: 'hello' }] }),
274
+ },
275
+ ];
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@netlify/config",
3
- "version": "18.2.5-rc",
3
+ "version": "18.2.7-rc",
4
4
  "description": "Netlify config module",
5
5
  "type": "module",
6
6
  "exports": "./lib/main.js",
7
7
  "main": "./lib/main.js",
8
+ "types": "./lib/main.d.ts",
8
9
  "bin": {
9
- "netlify-config": "lib/bin/main.js"
10
+ "netlify-config": "./bin.js"
10
11
  },
11
12
  "files": [
13
+ "bin.js",
12
14
  "lib/**/*.js"
13
15
  ],
14
16
  "author": "Netlify Inc.",
@@ -17,7 +19,11 @@
17
19
  ],
18
20
  "scripts": {
19
21
  "prepublishOnly": "cd ../../ && npm run prepublishOnly",
20
- "build": "cp -a src lib/"
22
+ "prebuild": "rm -rf lib",
23
+ "build": "tsc",
24
+ "test": "ava",
25
+ "test:ci": "c8 -r lcovonly -r text -r json ava",
26
+ "test:measure": "node tools/tests_duration.mjs"
21
27
  },
22
28
  "keywords": [
23
29
  "javascript",