@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.
Files changed (56) hide show
  1. package/bin.js +5 -0
  2. package/lib/api/build_settings.js +20 -33
  3. package/lib/api/client.js +10 -13
  4. package/lib/api/site_info.js +48 -56
  5. package/lib/base.js +10 -18
  6. package/lib/bin/flags.js +134 -142
  7. package/lib/bin/main.js +49 -63
  8. package/lib/build_dir.js +11 -15
  9. package/lib/cached_config.js +14 -17
  10. package/lib/case.js +16 -35
  11. package/lib/context.js +62 -84
  12. package/lib/default.js +18 -22
  13. package/lib/env/envelope.js +23 -23
  14. package/lib/env/git.js +18 -18
  15. package/lib/env/main.js +127 -179
  16. package/lib/error.js +19 -27
  17. package/lib/events.js +18 -19
  18. package/lib/files.js +63 -87
  19. package/lib/functions_config.js +36 -52
  20. package/lib/headers.js +17 -27
  21. package/lib/inline_config.js +6 -7
  22. package/lib/log/cleanup.js +54 -82
  23. package/lib/log/logger.js +25 -36
  24. package/lib/log/main.js +31 -40
  25. package/lib/log/messages.js +56 -95
  26. package/lib/log/options.js +24 -38
  27. package/lib/log/serialize.js +3 -4
  28. package/lib/log/theme.js +10 -11
  29. package/lib/main.js +188 -263
  30. package/lib/merge.js +25 -35
  31. package/lib/merge_normalize.js +17 -24
  32. package/lib/mutations/apply.js +53 -65
  33. package/lib/mutations/config_prop_name.js +6 -8
  34. package/lib/mutations/update.js +79 -98
  35. package/lib/normalize.js +24 -28
  36. package/lib/options/base.js +39 -51
  37. package/lib/options/branch.js +23 -26
  38. package/lib/options/feature_flags.js +7 -10
  39. package/lib/options/main.js +76 -96
  40. package/lib/options/repository_root.js +11 -16
  41. package/lib/origin.js +22 -29
  42. package/lib/parse.js +42 -55
  43. package/lib/path.js +29 -40
  44. package/lib/redirects.js +16 -26
  45. package/lib/simplify.js +66 -92
  46. package/lib/utils/group.js +5 -6
  47. package/lib/utils/remove_falsy.js +9 -13
  48. package/lib/utils/set.js +19 -25
  49. package/lib/utils/toml.js +13 -16
  50. package/lib/validate/context.js +24 -43
  51. package/lib/validate/example.js +20 -27
  52. package/lib/validate/helpers.js +17 -23
  53. package/lib/validate/identical.js +8 -12
  54. package/lib/validate/main.js +83 -127
  55. package/lib/validate/validations.js +243 -257
  56. 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
- build: { environment, processing: { css, html, images, js, ...processing } = {}, services, ...build } = {},
9
- functions,
10
- plugins,
11
- headers,
12
- redirects,
13
- context = {},
14
- ...config
15
- }) {
16
- const buildA = {
17
- ...build,
18
- ...simplifyEnvironment(environment),
19
- ...removeEmptyObject(
20
- {
21
- ...processing,
22
- ...removeEmptyObject(css, 'css'),
23
- ...removeEmptyObject(html, 'html'),
24
- ...removeEmptyObject(images, 'images'),
25
- ...removeEmptyObject(js, 'js'),
26
- },
27
- 'processing',
28
- ),
29
- ...removeEmptyObject(services, 'services'),
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
- return Array.isArray(environment)
44
- ? removeEmptyArray(environment, 'environment')
45
- : removeEmptyObject(environment, 'environment')
46
- }
47
-
29
+ return Array.isArray(environment)
30
+ ? removeEmptyArray(environment, 'environment')
31
+ : removeEmptyObject(environment, 'environment');
32
+ };
48
33
  const simplifyContexts = function (contextProps) {
49
- return mapObj(contextProps, simplifyContextProps)
50
- }
51
-
34
+ return mapObj(contextProps, simplifyContextProps);
35
+ };
52
36
  const simplifyContextProps = function (context, contextConfig) {
53
- return [context, simplifyConfig(contextConfig)]
54
- }
55
-
37
+ return [context, simplifyConfig(contextConfig)];
38
+ };
56
39
  const simplifyFunctions = function (functions) {
57
- return isPlainObj(functions) ? Object.entries(functions).reduce(simplifyFunction, {}) : functions
58
- }
59
-
40
+ return isPlainObj(functions) ? Object.entries(functions).reduce(simplifyFunction, {}) : functions;
41
+ };
60
42
  const simplifyFunction = function (functions, [key, value]) {
61
- return { ...functions, ...removeEmptyObject(value, key) }
62
- }
63
-
43
+ return { ...functions, ...removeEmptyObject(value, key) };
44
+ };
64
45
  const simplifyRedirects = function (redirects) {
65
- return Array.isArray(redirects) ? redirects.map(simplifyRedirect) : redirects
66
- }
67
-
46
+ return Array.isArray(redirects) ? redirects.map(simplifyRedirect) : redirects;
47
+ };
68
48
  const simplifyRedirect = function (redirect) {
69
- if (!isPlainObj(redirect)) {
70
- return redirect
71
- }
72
-
73
- const { force, proxy, query, conditions, headers, ...redirectA } = redirect
74
- return {
75
- ...redirectA,
76
- ...removeDefaultValue(force, 'force', false),
77
- ...removeDefaultValue(proxy, 'proxy', false),
78
- ...removeEmptyObject(query, 'query'),
79
- ...removeEmptyObject(conditions, 'conditions'),
80
- ...removeEmptyObject(headers, 'headers'),
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
- return value === defaultValue ? {} : { [propName]: value }
86
- }
87
-
63
+ return value === defaultValue ? {} : { [propName]: value };
64
+ };
88
65
  export const removeEmptyObject = function (object, propName) {
89
- if (!isPlainObj(object)) {
90
- return {}
91
- }
92
-
93
- const objectA = removeFalsy(object)
94
- return Object.keys(objectA).length === 0 ? {} : { [propName]: objectA }
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
- if (!Array.isArray(array)) {
99
- return {}
100
- }
101
-
102
- return array.length === 0 ? {} : { [propName]: array }
103
- }
73
+ if (!Array.isArray(array)) {
74
+ return {};
75
+ }
76
+ return array.length === 0 ? {} : { [propName]: array };
77
+ };
@@ -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
- const keys = [...new Set(objects.map((object) => object[keyName]))]
5
- return keys.map((key) => groupObjects(objects, keyName, key))
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
- return objects.filter((object) => object[keyName] === key)
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
- return filterObj(obj, (key, value) => isTruthy(value))
6
- }
7
-
4
+ return filterObj(obj, (key, value) => isTruthy(value));
5
+ };
8
6
  export const removeUndefined = function (obj) {
9
- return filterObj(obj, (key, value) => isDefined(value))
10
- }
11
-
7
+ return filterObj(obj, (key, value) => isDefined(value));
8
+ };
12
9
  export const isTruthy = function (value) {
13
- return isDefined(value) && (typeof value !== 'string' || value.trim() !== '')
14
- }
15
-
10
+ return isDefined(value) && (typeof value !== 'string' || value.trim() !== '');
11
+ };
16
12
  export const isDefined = function (value) {
17
- return value !== undefined && value !== null
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
- if (keys.length === 0) {
10
- return value
11
- }
12
-
13
- if (Number.isInteger(keys[0])) {
14
- return setArrayProp(parent, keys, value)
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
- const arrayParent = Array.isArray(parent) ? parent : []
22
- const missingItems = index - arrayParent.length + 1
23
- // eslint-disable-next-line unicorn/no-new-array
24
- const normalizedParent = missingItems > 0 ? [...arrayParent, ...new Array(missingItems)] : arrayParent
25
- const newValue = setProp(normalizedParent[index], keys, value)
26
- return [...normalizedParent.slice(0, index), newValue, ...normalizedParent.slice(index + 1)]
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
- const objectParent = isPlainObj(parent) ? parent : {}
31
- const newValue = setProp(objectParent[key], keys, value)
32
- return { ...objectParent, [key]: newValue }
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
- const config = loadToml(configString)
7
- // `toml.parse()` returns a object with `null` prototype deeply, which can
8
- // sometimes create problems with some utilities. We convert it.
9
- // TOML can return Date instances, but JSON will stringify those, and we
10
- // don't use Date in netlify.toml, so this should be ok.
11
- return JSON.parse(JSON.stringify(config))
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
- return tomlify.toToml(object, { space: 2, replace: replaceTomlValue })
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
- return Number.isInteger(value) ? String(value) : false
23
- }
19
+ return Number.isInteger(value) ? String(value) : false;
20
+ };
@@ -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
- Object.entries(contextProps).forEach(([givenContext, givenContextProps]) => {
17
- validateContextPluginsConfig({ givenContextProps, plugins, givenContext, contexts, logs })
18
- })
19
- }
20
-
21
- const validateContextPluginsConfig = function ({
22
- givenContextProps: { plugins: contextPlugins = [] },
23
- plugins,
24
- givenContext,
25
- contexts,
26
- logs,
27
- }) {
28
- contextPlugins.forEach((pluginConfig) => {
29
- validateContextPluginConfig({ pluginConfig, plugins, givenContext, contexts, logs })
30
- })
31
- }
32
-
33
- const validateContextPluginConfig = function ({
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
- return plugins.some((plugin) => plugin.package === packageName && plugin.origin === UI_ORIGIN)
53
- }
54
-
34
+ return plugins.some((plugin) => plugin.package === packageName && plugin.origin === UI_ORIGIN);
35
+ };
55
36
  const isPluginConfigError = function (contexts, givenContext, inputs) {
56
- return contexts.every((context) => context !== givenContext) && Object.keys(inputs).length === 0
57
- }
37
+ return contexts.every((context) => context !== givenContext) && Object.keys(inputs).length === 0;
38
+ };
@@ -1,37 +1,30 @@
1
- import indentString from 'indent-string'
2
-
3
- import { THEME } from '../log/theme.js'
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
- const exampleA = typeof example === 'function' ? example(value, key, prevPath) : example
9
- return `
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
- // slice() is temporary, so it does not mutate
21
- // eslint-disable-next-line fp/no-mutating-methods
22
- const invalidValue = [...prevPath].reverse().reduce(setInvalidValuePart, value)
23
-
24
- // If `formatInvalid` is supplied, we use it to format the invalid value
25
- // before serializing it to TOML and printing it.
26
- const formattedInvalidValue = typeof formatInvalid === 'function' ? formatInvalid(invalidValue) : invalidValue
27
- const invalidValueA = serializeToml(formattedInvalidValue)
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
- if (Number.isInteger(part)) {
33
- return [value]
34
- }
35
-
36
- return value === undefined ? {} : { [part]: value }
37
- }
26
+ if (Number.isInteger(part)) {
27
+ return [value];
28
+ }
29
+ return value === undefined ? {} : { [part]: value };
30
+ };
@@ -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
- return Array.isArray(value) && value.every(isPlainObj)
5
- }
6
-
3
+ return Array.isArray(value) && value.every(isPlainObj);
4
+ };
7
5
  export const isArrayOfStrings = function (value) {
8
- return Array.isArray(value) && value.every(isString)
9
- }
10
-
6
+ return Array.isArray(value) && value.every(isString);
7
+ };
11
8
  export const isString = function (value) {
12
- return typeof value === 'string'
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
- return {
18
- check: (value) => checkValidProperty(value, [...propNames, ...legacyPropNames]),
19
- message: `has unknown properties. Valid properties are:
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
- return Object.keys(value).every((propName) => propNames.includes(propName))
26
- }
27
-
20
+ return Object.keys(value).every((propName) => propNames.includes(propName));
21
+ };
28
22
  export const functionsDirectoryCheck = {
29
- formatInvalid: ({ functionsDirectory } = {}) => ({ functions: { directory: functionsDirectory } }),
30
- propertyName: 'functions.directory',
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
- plugins.filter(hasIdenticalPlugin).forEach(throwIndenticalPlugin)
10
- }
11
-
8
+ plugins.filter(hasIdenticalPlugin).forEach(throwIndenticalPlugin);
9
+ };
12
10
  const hasIdenticalPlugin = function ({ package: packageName, origin }, index, plugins) {
13
- return plugins.slice(index + 1).some((pluginA) => packageName === pluginA.package && origin === pluginA.origin)
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
- throwUserError(`Plugin "${packageName}" must not be specified twice in ${ORIGINS[origin]}`)
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' };