@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/log/options.js
CHANGED
|
@@ -1,43 +1,29 @@
|
|
|
1
|
-
import { DEFAULT_FEATURE_FLAGS } from '../options/feature_flags.js'
|
|
2
|
-
import { removeEmptyArray } from '../simplify.js'
|
|
3
|
-
import { removeFalsy } from '../utils/remove_falsy.js'
|
|
4
|
-
|
|
1
|
+
import { DEFAULT_FEATURE_FLAGS } from '../options/feature_flags.js';
|
|
2
|
+
import { removeEmptyArray } from '../simplify.js';
|
|
3
|
+
import { removeFalsy } from '../utils/remove_falsy.js';
|
|
5
4
|
// Use an allowlist to prevent printing confidential values.
|
|
6
|
-
export const cleanupConfigOpts = function ({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
cwd,
|
|
22
|
-
context,
|
|
23
|
-
branch,
|
|
24
|
-
mode,
|
|
25
|
-
repositoryRoot,
|
|
26
|
-
siteId,
|
|
27
|
-
baseRelDir,
|
|
28
|
-
...removeEmptyArray(envA, 'env'),
|
|
29
|
-
featureFlags: cleanFeatureFlags(featureFlags),
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
|
|
5
|
+
export const cleanupConfigOpts = function ({ config, cwd, context, branch, mode, repositoryRoot, siteId, baseRelDir, env = {}, featureFlags = {}, }) {
|
|
6
|
+
const envA = Object.keys(env);
|
|
7
|
+
return removeFalsy({
|
|
8
|
+
config,
|
|
9
|
+
cwd,
|
|
10
|
+
context,
|
|
11
|
+
branch,
|
|
12
|
+
mode,
|
|
13
|
+
repositoryRoot,
|
|
14
|
+
siteId,
|
|
15
|
+
baseRelDir,
|
|
16
|
+
...removeEmptyArray(envA, 'env'),
|
|
17
|
+
featureFlags: cleanFeatureFlags(featureFlags),
|
|
18
|
+
});
|
|
19
|
+
};
|
|
33
20
|
// We only show feature flags related to `@netlify/config`.
|
|
34
21
|
// Also, we only print enabled feature flags.
|
|
35
22
|
const cleanFeatureFlags = function (featureFlags) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
23
|
+
return Object.entries(featureFlags)
|
|
24
|
+
.filter(shouldPrintFeatureFlag)
|
|
25
|
+
.map(([featureFlagName]) => featureFlagName);
|
|
26
|
+
};
|
|
41
27
|
const shouldPrintFeatureFlag = function ([featureFlagName, enabled]) {
|
|
42
|
-
|
|
43
|
-
}
|
|
28
|
+
return enabled && featureFlagName in DEFAULT_FEATURE_FLAGS;
|
|
29
|
+
};
|
package/lib/log/serialize.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { dump } from 'js-yaml'
|
|
2
|
-
|
|
1
|
+
import { dump } from 'js-yaml';
|
|
3
2
|
export const serializeObject = function (object) {
|
|
4
|
-
|
|
5
|
-
}
|
|
3
|
+
return dump(object, { noRefs: true, sortKeys: true, lineWidth: Number.POSITIVE_INFINITY }).trimEnd();
|
|
4
|
+
};
|
package/lib/log/theme.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
3
2
|
// Color theme. Please use this instead of requiring chalk directly, to ensure
|
|
4
3
|
// consistent colors.
|
|
5
4
|
export const THEME = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
5
|
+
// Single lines used as subheaders
|
|
6
|
+
subHeader: chalk.cyan.bold,
|
|
7
|
+
// Single lines used as subheaders indicating an error
|
|
8
|
+
errorSubHeader: chalk.red.bold,
|
|
9
|
+
// Same for warnings
|
|
10
|
+
warningLine: chalk.yellowBright,
|
|
11
|
+
// One of several words that should be highlighted inside a line
|
|
12
|
+
highlightWords: chalk.cyan,
|
|
13
|
+
};
|
package/lib/main.js
CHANGED
|
@@ -1,254 +1,183 @@
|
|
|
1
|
-
import { getApiClient } from './api/client.js'
|
|
2
|
-
import { getSiteInfo } from './api/site_info.js'
|
|
3
|
-
import { getInitialBase, getBase, addBase } from './base.js'
|
|
4
|
-
import { getBuildDir } from './build_dir.js'
|
|
5
|
-
import { getCachedConfig } from './cached_config.js'
|
|
6
|
-
import { normalizeContextProps, mergeContext } from './context.js'
|
|
7
|
-
import { parseDefaultConfig } from './default.js'
|
|
8
|
-
import { getEnv } from './env/main.js'
|
|
9
|
-
import { resolveConfigPaths } from './files.js'
|
|
10
|
-
import { getHeadersPath, addHeaders } from './headers.js'
|
|
11
|
-
import { getInlineConfig } from './inline_config.js'
|
|
12
|
-
import { logResult } from './log/main.js'
|
|
13
|
-
import { mergeConfigs } from './merge.js'
|
|
14
|
-
import { normalizeBeforeConfigMerge, normalizeAfterConfigMerge } from './merge_normalize.js'
|
|
15
|
-
import { addDefaultOpts, normalizeOpts } from './options/main.js'
|
|
16
|
-
import { UI_ORIGIN, CONFIG_ORIGIN, INLINE_ORIGIN } from './origin.js'
|
|
17
|
-
import { parseConfig } from './parse.js'
|
|
18
|
-
import { getConfigPath } from './path.js'
|
|
19
|
-
import { getRedirectsPath, addRedirects } from './redirects.js'
|
|
20
|
-
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
// eslint-disable-next-line import/max-dependencies
|
|
24
|
-
export { updateConfig, restoreConfig } from './mutations/update.js'
|
|
25
|
-
|
|
1
|
+
import { getApiClient } from './api/client.js';
|
|
2
|
+
import { getSiteInfo } from './api/site_info.js';
|
|
3
|
+
import { getInitialBase, getBase, addBase } from './base.js';
|
|
4
|
+
import { getBuildDir } from './build_dir.js';
|
|
5
|
+
import { getCachedConfig } from './cached_config.js';
|
|
6
|
+
import { normalizeContextProps, mergeContext } from './context.js';
|
|
7
|
+
import { parseDefaultConfig } from './default.js';
|
|
8
|
+
import { getEnv } from './env/main.js';
|
|
9
|
+
import { resolveConfigPaths } from './files.js';
|
|
10
|
+
import { getHeadersPath, addHeaders } from './headers.js';
|
|
11
|
+
import { getInlineConfig } from './inline_config.js';
|
|
12
|
+
import { logResult } from './log/main.js';
|
|
13
|
+
import { mergeConfigs } from './merge.js';
|
|
14
|
+
import { normalizeBeforeConfigMerge, normalizeAfterConfigMerge } from './merge_normalize.js';
|
|
15
|
+
import { addDefaultOpts, normalizeOpts } from './options/main.js';
|
|
16
|
+
import { UI_ORIGIN, CONFIG_ORIGIN, INLINE_ORIGIN } from './origin.js';
|
|
17
|
+
import { parseConfig } from './parse.js';
|
|
18
|
+
import { getConfigPath } from './path.js';
|
|
19
|
+
import { getRedirectsPath, addRedirects } from './redirects.js';
|
|
20
|
+
export { DEV_EVENTS, EVENTS } from './events.js';
|
|
21
|
+
export { cleanupConfig } from './log/cleanup.js';
|
|
22
|
+
export { updateConfig, restoreConfig } from './mutations/update.js';
|
|
26
23
|
// Load the configuration file.
|
|
27
24
|
// Takes an optional configuration file path as input and return the resolved
|
|
28
25
|
// `config` together with related properties such as the `configPath`.
|
|
29
26
|
export const resolveConfig = async function (opts) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
buildId,
|
|
96
|
-
context,
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
// @todo Remove in the next major version.
|
|
100
|
-
const configA = addLegacyFunctionsDirectory(config)
|
|
101
|
-
|
|
102
|
-
const result = {
|
|
103
|
-
siteInfo,
|
|
104
|
-
accounts,
|
|
105
|
-
addons,
|
|
106
|
-
env,
|
|
107
|
-
configPath,
|
|
108
|
-
redirectsPath,
|
|
109
|
-
headersPath,
|
|
110
|
-
buildDir,
|
|
111
|
-
repositoryRoot,
|
|
112
|
-
config: configA,
|
|
113
|
-
context,
|
|
114
|
-
branch,
|
|
115
|
-
token,
|
|
116
|
-
api,
|
|
117
|
-
logs,
|
|
118
|
-
}
|
|
119
|
-
logResult(result, { logs, debug })
|
|
120
|
-
return result
|
|
121
|
-
}
|
|
122
|
-
|
|
27
|
+
const { cachedConfig, cachedConfigPath, host, scheme, pathPrefix, testOpts, token, offline, ...optsA } = addDefaultOpts(opts);
|
|
28
|
+
// `api` is not JSON-serializable, so we cannot cache it inside `cachedConfig`
|
|
29
|
+
const api = getApiClient({ token, offline, host, scheme, pathPrefix, testOpts });
|
|
30
|
+
const parsedCachedConfig = await getCachedConfig({ cachedConfig, cachedConfigPath, token, api });
|
|
31
|
+
if (parsedCachedConfig !== undefined) {
|
|
32
|
+
return parsedCachedConfig;
|
|
33
|
+
}
|
|
34
|
+
const { config: configOpt, defaultConfig, inlineConfig, configMutations, cwd, context, repositoryRoot, base, branch, siteId, deployId, buildId, baseRelDir, mode, debug, logs, featureFlags, } = await normalizeOpts(optsA);
|
|
35
|
+
const { siteInfo, accounts, addons } = await getSiteInfo({ api, siteId, mode, testOpts });
|
|
36
|
+
const { defaultConfig: defaultConfigA, baseRelDir: baseRelDirA } = parseDefaultConfig({
|
|
37
|
+
defaultConfig,
|
|
38
|
+
base,
|
|
39
|
+
baseRelDir,
|
|
40
|
+
siteInfo,
|
|
41
|
+
logs,
|
|
42
|
+
debug,
|
|
43
|
+
});
|
|
44
|
+
const inlineConfigA = getInlineConfig({ inlineConfig, configMutations, logs, debug });
|
|
45
|
+
const { configPath, config, buildDir, redirectsPath, headersPath } = await loadConfig({
|
|
46
|
+
configOpt,
|
|
47
|
+
cwd,
|
|
48
|
+
context,
|
|
49
|
+
repositoryRoot,
|
|
50
|
+
branch,
|
|
51
|
+
defaultConfig: defaultConfigA,
|
|
52
|
+
inlineConfig: inlineConfigA,
|
|
53
|
+
baseRelDir: baseRelDirA,
|
|
54
|
+
logs,
|
|
55
|
+
featureFlags,
|
|
56
|
+
});
|
|
57
|
+
const env = await getEnv({
|
|
58
|
+
api,
|
|
59
|
+
mode,
|
|
60
|
+
config,
|
|
61
|
+
siteInfo,
|
|
62
|
+
accounts,
|
|
63
|
+
addons,
|
|
64
|
+
buildDir,
|
|
65
|
+
branch,
|
|
66
|
+
deployId,
|
|
67
|
+
buildId,
|
|
68
|
+
context,
|
|
69
|
+
});
|
|
70
|
+
// @todo Remove in the next major version.
|
|
71
|
+
const configA = addLegacyFunctionsDirectory(config);
|
|
72
|
+
const result = {
|
|
73
|
+
siteInfo,
|
|
74
|
+
accounts,
|
|
75
|
+
addons,
|
|
76
|
+
env,
|
|
77
|
+
configPath,
|
|
78
|
+
redirectsPath,
|
|
79
|
+
headersPath,
|
|
80
|
+
buildDir,
|
|
81
|
+
repositoryRoot,
|
|
82
|
+
config: configA,
|
|
83
|
+
context,
|
|
84
|
+
branch,
|
|
85
|
+
token,
|
|
86
|
+
api,
|
|
87
|
+
logs,
|
|
88
|
+
};
|
|
89
|
+
logResult(result, { logs, debug });
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
123
92
|
// Adds a `build.functions` property that mirrors `functionsDirectory`, for
|
|
124
93
|
// backward compatibility.
|
|
125
94
|
const addLegacyFunctionsDirectory = (config) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
95
|
+
if (!config.functionsDirectory) {
|
|
96
|
+
return config;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
...config,
|
|
100
|
+
build: {
|
|
101
|
+
...config.build,
|
|
102
|
+
functions: config.functionsDirectory,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
|
139
106
|
// Try to load the configuration file in two passes.
|
|
140
107
|
// The first pass uses the `defaultConfig`'s `build.base` (if defined).
|
|
141
108
|
// The second pass uses the `build.base` from the first pass (if defined).
|
|
142
|
-
const loadConfig = async function ({
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
context,
|
|
189
|
-
repositoryRoot,
|
|
190
|
-
branch,
|
|
191
|
-
defaultConfig,
|
|
192
|
-
inlineConfig,
|
|
193
|
-
baseRelDir,
|
|
194
|
-
configBase: base,
|
|
195
|
-
base,
|
|
196
|
-
logs,
|
|
197
|
-
featureFlags,
|
|
198
|
-
})
|
|
199
|
-
return {
|
|
200
|
-
configPath: configPathA,
|
|
201
|
-
config: configA,
|
|
202
|
-
buildDir: buildDirA,
|
|
203
|
-
redirectsPath: redirectsPathA,
|
|
204
|
-
headersPath: headersPathA,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
109
|
+
const loadConfig = async function ({ configOpt, cwd, context, repositoryRoot, branch, defaultConfig, inlineConfig, baseRelDir, logs, featureFlags, }) {
|
|
110
|
+
const initialBase = getInitialBase({ repositoryRoot, defaultConfig, inlineConfig });
|
|
111
|
+
const { configPath, config, buildDir, base, redirectsPath, headersPath } = await getFullConfig({
|
|
112
|
+
configOpt,
|
|
113
|
+
cwd,
|
|
114
|
+
context,
|
|
115
|
+
repositoryRoot,
|
|
116
|
+
branch,
|
|
117
|
+
defaultConfig,
|
|
118
|
+
inlineConfig,
|
|
119
|
+
baseRelDir,
|
|
120
|
+
configBase: initialBase,
|
|
121
|
+
logs,
|
|
122
|
+
featureFlags,
|
|
123
|
+
});
|
|
124
|
+
// No second pass needed if:
|
|
125
|
+
// - there is no `build.base` (in which case both `base` and `initialBase`
|
|
126
|
+
// are `undefined`)
|
|
127
|
+
// - `build.base` is the same as the `Base directory` UI setting (already
|
|
128
|
+
// used in the first round)
|
|
129
|
+
// - `baseRelDir` feature flag is not used. This feature flag was introduced
|
|
130
|
+
// to ensure backward compatibility.
|
|
131
|
+
if (!baseRelDir || base === initialBase) {
|
|
132
|
+
return { configPath, config, buildDir, redirectsPath, headersPath };
|
|
133
|
+
}
|
|
134
|
+
const { configPath: configPathA, config: configA, buildDir: buildDirA, redirectsPath: redirectsPathA, headersPath: headersPathA, } = await getFullConfig({
|
|
135
|
+
cwd,
|
|
136
|
+
context,
|
|
137
|
+
repositoryRoot,
|
|
138
|
+
branch,
|
|
139
|
+
defaultConfig,
|
|
140
|
+
inlineConfig,
|
|
141
|
+
baseRelDir,
|
|
142
|
+
configBase: base,
|
|
143
|
+
base,
|
|
144
|
+
logs,
|
|
145
|
+
featureFlags,
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
configPath: configPathA,
|
|
149
|
+
config: configA,
|
|
150
|
+
buildDir: buildDirA,
|
|
151
|
+
redirectsPath: redirectsPathA,
|
|
152
|
+
headersPath: headersPathA,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
208
155
|
// Load configuration file and normalize it, merge contexts, etc.
|
|
209
|
-
const getFullConfig = async function ({
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
})
|
|
235
|
-
const {
|
|
236
|
-
config: configB,
|
|
237
|
-
buildDir,
|
|
238
|
-
base: baseA,
|
|
239
|
-
} = await resolveFiles({ config: configA, repositoryRoot, base, baseRelDir })
|
|
240
|
-
const headersPath = getHeadersPath(configB)
|
|
241
|
-
const configC = await addHeaders({ config: configB, headersPath, logs, featureFlags })
|
|
242
|
-
const redirectsPath = getRedirectsPath(configC)
|
|
243
|
-
const configD = await addRedirects({ config: configC, redirectsPath, logs, featureFlags })
|
|
244
|
-
return { configPath, config: configD, buildDir, base: baseA, redirectsPath, headersPath }
|
|
245
|
-
} catch (error) {
|
|
246
|
-
const configName = configPath === undefined ? '' : ` file ${configPath}`
|
|
247
|
-
error.message = `When resolving config${configName}:\n${error.message}`
|
|
248
|
-
throw error
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
156
|
+
const getFullConfig = async function ({ configOpt, cwd, context, repositoryRoot, branch, defaultConfig, inlineConfig, baseRelDir, configBase, base, logs, featureFlags, }) {
|
|
157
|
+
const configPath = await getConfigPath({ configOpt, cwd, repositoryRoot, configBase });
|
|
158
|
+
try {
|
|
159
|
+
const config = await parseConfig(configPath);
|
|
160
|
+
const configA = mergeAndNormalizeConfig({
|
|
161
|
+
config,
|
|
162
|
+
defaultConfig,
|
|
163
|
+
inlineConfig,
|
|
164
|
+
context,
|
|
165
|
+
branch,
|
|
166
|
+
logs,
|
|
167
|
+
});
|
|
168
|
+
const { config: configB, buildDir, base: baseA, } = await resolveFiles({ config: configA, repositoryRoot, base, baseRelDir });
|
|
169
|
+
const headersPath = getHeadersPath(configB);
|
|
170
|
+
const configC = await addHeaders({ config: configB, headersPath, logs, featureFlags });
|
|
171
|
+
const redirectsPath = getRedirectsPath(configC);
|
|
172
|
+
const configD = await addRedirects({ config: configC, redirectsPath, logs, featureFlags });
|
|
173
|
+
return { configPath, config: configD, buildDir, base: baseA, redirectsPath, headersPath };
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const configName = configPath === undefined ? '' : ` file ${configPath}`;
|
|
177
|
+
error.message = `When resolving config${configName}:\n${error.message}`;
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
252
181
|
// Merge:
|
|
253
182
|
// - `--defaultConfig`: UI build settings and UI-installed plugins
|
|
254
183
|
// - `inlineConfig`: Netlify CLI flags
|
|
@@ -257,29 +186,25 @@ const getFullConfig = async function ({
|
|
|
257
186
|
// Those need to be done at different stages depending on whether they should
|
|
258
187
|
// happen before/after the merges mentioned above.
|
|
259
188
|
const mergeAndNormalizeConfig = function ({ config, defaultConfig, inlineConfig, context, branch, logs }) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return configE
|
|
270
|
-
}
|
|
271
|
-
|
|
189
|
+
const configA = normalizeConfigAndContext(config, CONFIG_ORIGIN);
|
|
190
|
+
const defaultConfigA = normalizeConfigAndContext(defaultConfig, UI_ORIGIN);
|
|
191
|
+
const inlineConfigA = normalizeConfigAndContext(inlineConfig, INLINE_ORIGIN);
|
|
192
|
+
const configB = mergeConfigs([defaultConfigA, configA]);
|
|
193
|
+
const configC = mergeContext({ config: configB, context, branch, logs });
|
|
194
|
+
const configD = mergeConfigs([configC, inlineConfigA]);
|
|
195
|
+
const configE = normalizeAfterConfigMerge(configD);
|
|
196
|
+
return configE;
|
|
197
|
+
};
|
|
272
198
|
const normalizeConfigAndContext = function (config, origin) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
199
|
+
const configA = normalizeBeforeConfigMerge(config, origin);
|
|
200
|
+
const configB = normalizeContextProps({ config: configA, origin });
|
|
201
|
+
return configB;
|
|
202
|
+
};
|
|
278
203
|
// Find base directory, build directory and resolve all paths to absolute paths
|
|
279
204
|
const resolveFiles = async function ({ config, repositoryRoot, base, baseRelDir }) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
205
|
+
const baseA = getBase(base, repositoryRoot, config);
|
|
206
|
+
const buildDir = await getBuildDir(repositoryRoot, baseA);
|
|
207
|
+
const configA = await resolveConfigPaths({ config, repositoryRoot, buildDir, baseRelDir });
|
|
208
|
+
const configB = addBase(configA, baseA);
|
|
209
|
+
return { config: configB, buildDir, base: baseA };
|
|
210
|
+
};
|
package/lib/merge.js
CHANGED
|
@@ -1,53 +1,43 @@
|
|
|
1
|
-
import deepmerge from 'deepmerge'
|
|
2
|
-
import isPlainObj from 'is-plain-obj'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { removeUndefined } from './utils/remove_falsy.js'
|
|
6
|
-
|
|
1
|
+
import deepmerge from 'deepmerge';
|
|
2
|
+
import isPlainObj from 'is-plain-obj';
|
|
3
|
+
import { groupBy } from './utils/group.js';
|
|
4
|
+
import { removeUndefined } from './utils/remove_falsy.js';
|
|
7
5
|
// Merge an array of configuration objects.
|
|
8
6
|
// Last items have higher priority.
|
|
9
7
|
// Configuration objects are deeply merged.
|
|
10
8
|
// - Arrays are overridden, not concatenated.
|
|
11
9
|
export const mergeConfigs = function (configs) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
10
|
+
const cleanedConfigs = configs.map(removeUndefinedProps);
|
|
11
|
+
return deepmerge.all(cleanedConfigs, { arrayMerge });
|
|
12
|
+
};
|
|
16
13
|
const removeUndefinedProps = function ({ build = {}, ...config }) {
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
14
|
+
return removeUndefined({ ...config, build: removeUndefined(build) });
|
|
15
|
+
};
|
|
20
16
|
// By default `deepmerge` concatenates arrays. We use the `arrayMerge` option
|
|
21
17
|
// to remove this behavior. Also, we merge some array properties differently,
|
|
22
18
|
// such as `plugins`.
|
|
23
19
|
const arrayMerge = function (arrayA, arrayB) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
20
|
+
if (isPluginsProperty(arrayA) && isPluginsProperty(arrayB)) {
|
|
21
|
+
return mergePlugins(arrayA, arrayB);
|
|
22
|
+
}
|
|
23
|
+
return arrayB;
|
|
24
|
+
};
|
|
31
25
|
// `deepmerge` does not allow retrieving the name of the array property being
|
|
32
26
|
// merged, so we need to do some heuristics.
|
|
33
27
|
const isPluginsProperty = function (array) {
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
28
|
+
return Array.isArray(array) && array.every(isPluginObject);
|
|
29
|
+
};
|
|
37
30
|
const isPluginObject = function (object) {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
31
|
+
return isPlainObj(object) && typeof object.package === 'string';
|
|
32
|
+
};
|
|
41
33
|
// Merge two `config.plugins`. Merge plugins with the same `plugin.package`.
|
|
42
34
|
const mergePlugins = function (pluginsA, pluginsB) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
35
|
+
const plugins = [...pluginsA, ...pluginsB];
|
|
36
|
+
return groupBy(plugins, 'package').map(mergePluginConfigs);
|
|
37
|
+
};
|
|
47
38
|
const mergePluginConfigs = function (plugins) {
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
39
|
+
return plugins.reduce(mergePluginsPair, {});
|
|
40
|
+
};
|
|
51
41
|
const mergePluginsPair = function (pluginA, pluginB) {
|
|
52
|
-
|
|
53
|
-
}
|
|
42
|
+
return deepmerge(pluginA, pluginB, { arrayMerge });
|
|
43
|
+
};
|