@netlify/config 18.2.4 → 18.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +5 -0
- package/lib/api/build_settings.js +20 -33
- package/lib/api/client.js +10 -13
- package/lib/api/site_info.js +48 -56
- package/lib/base.js +10 -18
- package/lib/bin/flags.js +134 -142
- package/lib/bin/main.js +49 -63
- package/lib/build_dir.js +11 -15
- package/lib/cached_config.js +14 -17
- package/lib/case.js +16 -35
- package/lib/context.js +62 -84
- package/lib/default.js +18 -22
- package/lib/env/envelope.js +23 -23
- package/lib/env/git.js +18 -18
- package/lib/env/main.js +127 -179
- package/lib/error.js +19 -27
- package/lib/events.js +18 -19
- package/lib/files.js +63 -87
- package/lib/functions_config.js +36 -52
- package/lib/headers.js +17 -27
- package/lib/inline_config.js +6 -7
- package/lib/log/cleanup.js +54 -82
- package/lib/log/logger.js +25 -36
- package/lib/log/main.js +31 -40
- package/lib/log/messages.js +56 -95
- package/lib/log/options.js +24 -38
- package/lib/log/serialize.js +3 -4
- package/lib/log/theme.js +10 -11
- package/lib/main.js +188 -263
- package/lib/merge.js +25 -35
- package/lib/merge_normalize.js +17 -24
- package/lib/mutations/apply.js +53 -65
- package/lib/mutations/config_prop_name.js +6 -8
- package/lib/mutations/update.js +79 -98
- package/lib/normalize.js +24 -28
- package/lib/options/base.js +39 -51
- package/lib/options/branch.js +23 -26
- package/lib/options/feature_flags.js +7 -10
- package/lib/options/main.js +76 -96
- package/lib/options/repository_root.js +11 -16
- package/lib/origin.js +22 -29
- package/lib/parse.js +42 -55
- package/lib/path.js +29 -40
- package/lib/redirects.js +16 -26
- package/lib/simplify.js +66 -92
- package/lib/utils/group.js +5 -6
- package/lib/utils/remove_falsy.js +9 -13
- package/lib/utils/set.js +19 -25
- package/lib/utils/toml.js +13 -16
- package/lib/validate/context.js +24 -43
- package/lib/validate/example.js +20 -27
- package/lib/validate/helpers.js +17 -23
- package/lib/validate/identical.js +8 -12
- package/lib/validate/main.js +83 -127
- package/lib/validate/validations.js +243 -257
- package/package.json +13 -8
package/lib/simplify.js
CHANGED
|
@@ -1,103 +1,77 @@
|
|
|
1
|
-
import isPlainObj from 'is-plain-obj'
|
|
2
|
-
import mapObj from 'map-obj'
|
|
3
|
-
|
|
4
|
-
import { removeFalsy } from './utils/remove_falsy.js'
|
|
5
|
-
|
|
1
|
+
import isPlainObj from 'is-plain-obj';
|
|
2
|
+
import mapObj from 'map-obj';
|
|
3
|
+
import { removeFalsy } from './utils/remove_falsy.js';
|
|
6
4
|
// Removes default values (empty objects and arrays) from the configuration.
|
|
7
|
-
export const simplifyConfig = function ({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
...
|
|
22
|
-
...removeEmptyObject(
|
|
23
|
-
...removeEmptyObject(
|
|
24
|
-
...
|
|
25
|
-
...
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return removeFalsy({
|
|
32
|
-
...config,
|
|
33
|
-
...removeEmptyObject(simplifyFunctions(functions), 'functions'),
|
|
34
|
-
...removeEmptyObject(buildA, 'build'),
|
|
35
|
-
...removeEmptyArray(plugins, 'plugins'),
|
|
36
|
-
...removeEmptyArray(headers, 'headers'),
|
|
37
|
-
...removeEmptyArray(simplifyRedirects(redirects), 'redirects'),
|
|
38
|
-
...removeEmptyObject(simplifyContexts(context), 'context'),
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
|
|
5
|
+
export const simplifyConfig = function ({ build: { environment, processing: { css, html, images, js, ...processing } = {}, services, ...build } = {}, functions, plugins, headers, redirects, context = {}, ...config }) {
|
|
6
|
+
const buildA = {
|
|
7
|
+
...build,
|
|
8
|
+
...simplifyEnvironment(environment),
|
|
9
|
+
...removeEmptyObject({
|
|
10
|
+
...processing,
|
|
11
|
+
...removeEmptyObject(css, 'css'),
|
|
12
|
+
...removeEmptyObject(html, 'html'),
|
|
13
|
+
...removeEmptyObject(images, 'images'),
|
|
14
|
+
...removeEmptyObject(js, 'js'),
|
|
15
|
+
}, 'processing'),
|
|
16
|
+
...removeEmptyObject(services, 'services'),
|
|
17
|
+
};
|
|
18
|
+
return removeFalsy({
|
|
19
|
+
...config,
|
|
20
|
+
...removeEmptyObject(simplifyFunctions(functions), 'functions'),
|
|
21
|
+
...removeEmptyObject(buildA, 'build'),
|
|
22
|
+
...removeEmptyArray(plugins, 'plugins'),
|
|
23
|
+
...removeEmptyArray(headers, 'headers'),
|
|
24
|
+
...removeEmptyArray(simplifyRedirects(redirects), 'redirects'),
|
|
25
|
+
...removeEmptyObject(simplifyContexts(context), 'context'),
|
|
26
|
+
});
|
|
27
|
+
};
|
|
42
28
|
const simplifyEnvironment = function (environment) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
29
|
+
return Array.isArray(environment)
|
|
30
|
+
? removeEmptyArray(environment, 'environment')
|
|
31
|
+
: removeEmptyObject(environment, 'environment');
|
|
32
|
+
};
|
|
48
33
|
const simplifyContexts = function (contextProps) {
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
34
|
+
return mapObj(contextProps, simplifyContextProps);
|
|
35
|
+
};
|
|
52
36
|
const simplifyContextProps = function (context, contextConfig) {
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
37
|
+
return [context, simplifyConfig(contextConfig)];
|
|
38
|
+
};
|
|
56
39
|
const simplifyFunctions = function (functions) {
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
40
|
+
return isPlainObj(functions) ? Object.entries(functions).reduce(simplifyFunction, {}) : functions;
|
|
41
|
+
};
|
|
60
42
|
const simplifyFunction = function (functions, [key, value]) {
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
43
|
+
return { ...functions, ...removeEmptyObject(value, key) };
|
|
44
|
+
};
|
|
64
45
|
const simplifyRedirects = function (redirects) {
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
46
|
+
return Array.isArray(redirects) ? redirects.map(simplifyRedirect) : redirects;
|
|
47
|
+
};
|
|
68
48
|
const simplifyRedirect = function (redirect) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
49
|
+
if (!isPlainObj(redirect)) {
|
|
50
|
+
return redirect;
|
|
51
|
+
}
|
|
52
|
+
const { force, proxy, query, conditions, headers, ...redirectA } = redirect;
|
|
53
|
+
return {
|
|
54
|
+
...redirectA,
|
|
55
|
+
...removeDefaultValue(force, 'force', false),
|
|
56
|
+
...removeDefaultValue(proxy, 'proxy', false),
|
|
57
|
+
...removeEmptyObject(query, 'query'),
|
|
58
|
+
...removeEmptyObject(conditions, 'conditions'),
|
|
59
|
+
...removeEmptyObject(headers, 'headers'),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
84
62
|
const removeDefaultValue = function (value, propName, defaultValue) {
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
63
|
+
return value === defaultValue ? {} : { [propName]: value };
|
|
64
|
+
};
|
|
88
65
|
export const removeEmptyObject = function (object, propName) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
66
|
+
if (!isPlainObj(object)) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
const objectA = removeFalsy(object);
|
|
70
|
+
return Object.keys(objectA).length === 0 ? {} : { [propName]: objectA };
|
|
71
|
+
};
|
|
97
72
|
export const removeEmptyArray = function (array, propName) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
73
|
+
if (!Array.isArray(array)) {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
return array.length === 0 ? {} : { [propName]: array };
|
|
77
|
+
};
|
package/lib/utils/group.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Group objects according to a key attribute.
|
|
2
2
|
// The key must exist in each object and be a string.
|
|
3
3
|
export const groupBy = function (objects, keyName) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
4
|
+
const keys = [...new Set(objects.map((object) => object[keyName]))];
|
|
5
|
+
return keys.map((key) => groupObjects(objects, keyName, key));
|
|
6
|
+
};
|
|
8
7
|
const groupObjects = function (objects, keyName, key) {
|
|
9
|
-
|
|
10
|
-
}
|
|
8
|
+
return objects.filter((object) => object[keyName] === key);
|
|
9
|
+
};
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import filterObj from 'filter-obj'
|
|
2
|
-
|
|
1
|
+
import filterObj from 'filter-obj';
|
|
3
2
|
// Remove falsy values from object
|
|
4
3
|
export const removeFalsy = function (obj) {
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
4
|
+
return filterObj(obj, (key, value) => isTruthy(value));
|
|
5
|
+
};
|
|
8
6
|
export const removeUndefined = function (obj) {
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
7
|
+
return filterObj(obj, (key, value) => isDefined(value));
|
|
8
|
+
};
|
|
12
9
|
export const isTruthy = function (value) {
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
10
|
+
return isDefined(value) && (typeof value !== 'string' || value.trim() !== '');
|
|
11
|
+
};
|
|
16
12
|
export const isDefined = function (value) {
|
|
17
|
-
|
|
18
|
-
}
|
|
13
|
+
return value !== undefined && value !== null;
|
|
14
|
+
};
|
package/lib/utils/set.js
CHANGED
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
import isPlainObj from 'is-plain-obj'
|
|
2
|
-
|
|
1
|
+
import isPlainObj from 'is-plain-obj';
|
|
3
2
|
// Set a property deeply using an array of `keys` which can be either strings
|
|
4
3
|
// (object properties) or integers (array indices).
|
|
5
4
|
// Adds default values when intermediary properties are undefined or have the
|
|
6
5
|
// wrong type. Also extends arrays when they are too small for a given index.
|
|
7
6
|
// Does not mutate.
|
|
8
7
|
export const setProp = function (parent, keys, value) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return setObjectProp(parent, keys, value)
|
|
18
|
-
}
|
|
19
|
-
|
|
8
|
+
if (keys.length === 0) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
if (Number.isInteger(keys[0])) {
|
|
12
|
+
return setArrayProp(parent, keys, value);
|
|
13
|
+
}
|
|
14
|
+
return setObjectProp(parent, keys, value);
|
|
15
|
+
};
|
|
20
16
|
const setArrayProp = function (parent, [index, ...keys], value) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
17
|
+
const arrayParent = Array.isArray(parent) ? parent : [];
|
|
18
|
+
const missingItems = index - arrayParent.length + 1;
|
|
19
|
+
const normalizedParent = missingItems > 0 ? [...arrayParent, ...new Array(missingItems)] : arrayParent;
|
|
20
|
+
const newValue = setProp(normalizedParent[index], keys, value);
|
|
21
|
+
return [...normalizedParent.slice(0, index), newValue, ...normalizedParent.slice(index + 1)];
|
|
22
|
+
};
|
|
29
23
|
const setObjectProp = function (parent, [key, ...keys], value) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
24
|
+
const objectParent = isPlainObj(parent) ? parent : {};
|
|
25
|
+
const newValue = setProp(objectParent[key], keys, value);
|
|
26
|
+
return { ...objectParent, [key]: newValue };
|
|
27
|
+
};
|
package/lib/utils/toml.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import { parse as loadToml } from 'toml'
|
|
2
|
-
import tomlify from 'tomlify-j0.4'
|
|
3
|
-
|
|
1
|
+
import { parse as loadToml } from 'toml';
|
|
2
|
+
import tomlify from 'tomlify-j0.4';
|
|
4
3
|
// Parse from TOML to JavaScript
|
|
5
4
|
export const parseToml = function (configString) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
5
|
+
const config = loadToml(configString);
|
|
6
|
+
// `toml.parse()` returns a object with `null` prototype deeply, which can
|
|
7
|
+
// sometimes create problems with some utilities. We convert it.
|
|
8
|
+
// TOML can return Date instances, but JSON will stringify those, and we
|
|
9
|
+
// don't use Date in netlify.toml, so this should be ok.
|
|
10
|
+
return JSON.parse(JSON.stringify(config));
|
|
11
|
+
};
|
|
14
12
|
// Serialize JavaScript object to TOML
|
|
15
13
|
export const serializeToml = function (object) {
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
14
|
+
return tomlify.toToml(object, { space: 2, replace: replaceTomlValue });
|
|
15
|
+
};
|
|
19
16
|
// `tomlify-j0.4` serializes integers as floats, e.g. `200.0`.
|
|
20
17
|
// This is a problem with `redirects[*].status`.
|
|
21
18
|
const replaceTomlValue = function (key, value) {
|
|
22
|
-
|
|
23
|
-
}
|
|
19
|
+
return Number.isInteger(value) ? String(value) : false;
|
|
20
|
+
};
|
package/lib/validate/context.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { warnContextPluginConfig, throwContextPluginsConfig } from '../log/messages.js'
|
|
2
|
-
import { UI_ORIGIN } from '../origin.js'
|
|
3
|
-
|
|
1
|
+
import { warnContextPluginConfig, throwContextPluginsConfig } from '../log/messages.js';
|
|
2
|
+
import { UI_ORIGIN } from '../origin.js';
|
|
4
3
|
// The only reason to specify both `[[plugins]]` and
|
|
5
4
|
// `[[contexts.{context}.plugins]]` is to configure context-specific plugin
|
|
6
5
|
// inputs.
|
|
@@ -13,45 +12,27 @@ import { UI_ORIGIN } from '../origin.js'
|
|
|
13
12
|
// there are no context-specific `inputs`
|
|
14
13
|
// - The current build is not in `context`
|
|
15
14
|
export const validateContextsPluginsConfig = function ({ contextProps, plugins, contexts, logs }) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
pluginConfig: { package: packageName, inputs = {} },
|
|
35
|
-
plugins = [],
|
|
36
|
-
givenContext,
|
|
37
|
-
contexts,
|
|
38
|
-
logs,
|
|
39
|
-
}) {
|
|
40
|
-
if (!isContextFreePlugin(plugins, packageName)) {
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (isPluginConfigError(contexts, givenContext, inputs)) {
|
|
45
|
-
throwContextPluginsConfig(packageName, givenContext)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
warnContextPluginConfig(logs, packageName, givenContext)
|
|
49
|
-
}
|
|
50
|
-
|
|
15
|
+
Object.entries(contextProps).forEach(([givenContext, givenContextProps]) => {
|
|
16
|
+
validateContextPluginsConfig({ givenContextProps, plugins, givenContext, contexts, logs });
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const validateContextPluginsConfig = function ({ givenContextProps: { plugins: contextPlugins = [] }, plugins, givenContext, contexts, logs, }) {
|
|
20
|
+
contextPlugins.forEach((pluginConfig) => {
|
|
21
|
+
validateContextPluginConfig({ pluginConfig, plugins, givenContext, contexts, logs });
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const validateContextPluginConfig = function ({ pluginConfig: { package: packageName, inputs = {} }, plugins = [], givenContext, contexts, logs, }) {
|
|
25
|
+
if (!isContextFreePlugin(plugins, packageName)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (isPluginConfigError(contexts, givenContext, inputs)) {
|
|
29
|
+
throwContextPluginsConfig(packageName, givenContext);
|
|
30
|
+
}
|
|
31
|
+
warnContextPluginConfig(logs, packageName, givenContext);
|
|
32
|
+
};
|
|
51
33
|
const isContextFreePlugin = function (plugins, packageName) {
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
34
|
+
return plugins.some((plugin) => plugin.package === packageName && plugin.origin === UI_ORIGIN);
|
|
35
|
+
};
|
|
55
36
|
const isPluginConfigError = function (contexts, givenContext, inputs) {
|
|
56
|
-
|
|
57
|
-
}
|
|
37
|
+
return contexts.every((context) => context !== givenContext) && Object.keys(inputs).length === 0;
|
|
38
|
+
};
|
package/lib/validate/example.js
CHANGED
|
@@ -1,37 +1,30 @@
|
|
|
1
|
-
import indentString from 'indent-string'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { serializeToml } from '../utils/toml.js'
|
|
5
|
-
|
|
1
|
+
import indentString from 'indent-string';
|
|
2
|
+
import { THEME } from '../log/theme.js';
|
|
3
|
+
import { serializeToml } from '../utils/toml.js';
|
|
6
4
|
// Print invalid value and example netlify.toml
|
|
7
5
|
export const getExample = function ({ value, key, prevPath, example, formatInvalid }) {
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const exampleA = typeof example === 'function' ? example(value, key, prevPath) : example;
|
|
7
|
+
return `
|
|
10
8
|
${THEME.errorSubHeader('Invalid syntax')}
|
|
11
9
|
|
|
12
10
|
${indentString(getInvalidValue(value, prevPath, formatInvalid), 2)}
|
|
13
11
|
|
|
14
12
|
${THEME.subHeader('Valid syntax')}
|
|
15
13
|
|
|
16
|
-
${indentString(serializeToml(exampleA), 2)}
|
|
17
|
-
}
|
|
18
|
-
|
|
14
|
+
${indentString(serializeToml(exampleA), 2)}`;
|
|
15
|
+
};
|
|
19
16
|
const getInvalidValue = function (value, prevPath, formatInvalid) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return invalidValueA
|
|
29
|
-
}
|
|
30
|
-
|
|
17
|
+
// slice() is temporary, so it does not mutate
|
|
18
|
+
const invalidValue = [...prevPath].reverse().reduce(setInvalidValuePart, value);
|
|
19
|
+
// If `formatInvalid` is supplied, we use it to format the invalid value
|
|
20
|
+
// before serializing it to TOML and printing it.
|
|
21
|
+
const formattedInvalidValue = typeof formatInvalid === 'function' ? formatInvalid(invalidValue) : invalidValue;
|
|
22
|
+
const invalidValueA = serializeToml(formattedInvalidValue);
|
|
23
|
+
return invalidValueA;
|
|
24
|
+
};
|
|
31
25
|
const setInvalidValuePart = function (value, part) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
26
|
+
if (Number.isInteger(part)) {
|
|
27
|
+
return [value];
|
|
28
|
+
}
|
|
29
|
+
return value === undefined ? {} : { [part]: value };
|
|
30
|
+
};
|
package/lib/validate/helpers.js
CHANGED
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
import isPlainObj from 'is-plain-obj'
|
|
2
|
-
|
|
1
|
+
import isPlainObj from 'is-plain-obj';
|
|
3
2
|
export const isArrayOfObjects = function (value) {
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
3
|
+
return Array.isArray(value) && value.every(isPlainObj);
|
|
4
|
+
};
|
|
7
5
|
export const isArrayOfStrings = function (value) {
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
6
|
+
return Array.isArray(value) && value.every(isString);
|
|
7
|
+
};
|
|
11
8
|
export const isString = function (value) {
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
9
|
+
return typeof value === 'string';
|
|
10
|
+
};
|
|
15
11
|
// Check an object valid properties, including legacy ones
|
|
16
12
|
export const validProperties = function (propNames, legacyPropNames) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
return {
|
|
14
|
+
check: (value) => checkValidProperty(value, [...propNames, ...legacyPropNames]),
|
|
15
|
+
message: `has unknown properties. Valid properties are:
|
|
20
16
|
${propNames.map((propName) => ` - ${propName}`).join('\n')}`,
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
17
|
+
};
|
|
18
|
+
};
|
|
24
19
|
const checkValidProperty = function (value, propNames) {
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
20
|
+
return Object.keys(value).every((propName) => propNames.includes(propName));
|
|
21
|
+
};
|
|
28
22
|
export const functionsDirectoryCheck = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
23
|
+
formatInvalid: ({ functionsDirectory } = {}) => ({ functions: { directory: functionsDirectory } }),
|
|
24
|
+
propertyName: 'functions.directory',
|
|
25
|
+
};
|
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import { throwUserError } from '../error.js'
|
|
2
|
-
|
|
1
|
+
import { throwUserError } from '../error.js';
|
|
3
2
|
// Validate that plugin are configured only once per origin
|
|
4
3
|
// (`netlify.toml` or UI).
|
|
5
4
|
// Exception: context-specific configuration since we allow context-specific
|
|
6
5
|
// overrides. This does not validate them since contexts have not been merged
|
|
7
6
|
// yet.
|
|
8
7
|
export const validateIdenticalPlugins = function ({ plugins = [] }) {
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
8
|
+
plugins.filter(hasIdenticalPlugin).forEach(throwIndenticalPlugin);
|
|
9
|
+
};
|
|
12
10
|
const hasIdenticalPlugin = function ({ package: packageName, origin }, index, plugins) {
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
11
|
+
return plugins.slice(index + 1).some((pluginA) => packageName === pluginA.package && origin === pluginA.origin);
|
|
12
|
+
};
|
|
16
13
|
const throwIndenticalPlugin = function ({ package: packageName, origin }) {
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const ORIGINS = { config: 'netlify.toml', ui: 'the app' }
|
|
14
|
+
throwUserError(`Plugin "${packageName}" must not be specified twice in ${ORIGINS[origin]}`);
|
|
15
|
+
};
|
|
16
|
+
const ORIGINS = { config: 'netlify.toml', ui: 'the app' };
|