@netlify/config 18.2.6-rc-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.
- 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 -55
- 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 +16 -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 -262
- 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 +77 -98
- package/lib/normalize.js +24 -28
- package/lib/options/base.js +39 -51
- package/lib/options/branch.js +21 -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 +20 -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 +9 -3
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,184 @@
|
|
|
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 { cleanupConfig } from './log/cleanup.js'
|
|
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';
|
|
23
22
|
// eslint-disable-next-line import/max-dependencies
|
|
24
|
-
export { updateConfig, restoreConfig } from './mutations/update.js'
|
|
25
|
-
|
|
23
|
+
export { updateConfig, restoreConfig } from './mutations/update.js';
|
|
26
24
|
// Load the configuration file.
|
|
27
25
|
// Takes an optional configuration file path as input and return the resolved
|
|
28
26
|
// `config` together with related properties such as the `configPath`.
|
|
29
27
|
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
|
-
|
|
28
|
+
const { cachedConfig, cachedConfigPath, host, scheme, pathPrefix, testOpts, token, offline, ...optsA } = addDefaultOpts(opts);
|
|
29
|
+
// `api` is not JSON-serializable, so we cannot cache it inside `cachedConfig`
|
|
30
|
+
const api = getApiClient({ token, offline, host, scheme, pathPrefix, testOpts });
|
|
31
|
+
const parsedCachedConfig = await getCachedConfig({ cachedConfig, cachedConfigPath, token, api });
|
|
32
|
+
if (parsedCachedConfig !== undefined) {
|
|
33
|
+
return parsedCachedConfig;
|
|
34
|
+
}
|
|
35
|
+
const { config: configOpt, defaultConfig, inlineConfig, configMutations, cwd, context, repositoryRoot, base, branch, siteId, deployId, buildId, baseRelDir, mode, debug, logs, featureFlags, } = await normalizeOpts(optsA);
|
|
36
|
+
const { siteInfo, accounts, addons } = await getSiteInfo({ api, siteId, mode, testOpts });
|
|
37
|
+
const { defaultConfig: defaultConfigA, baseRelDir: baseRelDirA } = parseDefaultConfig({
|
|
38
|
+
defaultConfig,
|
|
39
|
+
base,
|
|
40
|
+
baseRelDir,
|
|
41
|
+
siteInfo,
|
|
42
|
+
logs,
|
|
43
|
+
debug,
|
|
44
|
+
});
|
|
45
|
+
const inlineConfigA = getInlineConfig({ inlineConfig, configMutations, logs, debug });
|
|
46
|
+
const { configPath, config, buildDir, redirectsPath, headersPath } = await loadConfig({
|
|
47
|
+
configOpt,
|
|
48
|
+
cwd,
|
|
49
|
+
context,
|
|
50
|
+
repositoryRoot,
|
|
51
|
+
branch,
|
|
52
|
+
defaultConfig: defaultConfigA,
|
|
53
|
+
inlineConfig: inlineConfigA,
|
|
54
|
+
baseRelDir: baseRelDirA,
|
|
55
|
+
logs,
|
|
56
|
+
featureFlags,
|
|
57
|
+
});
|
|
58
|
+
const env = await getEnv({
|
|
59
|
+
api,
|
|
60
|
+
mode,
|
|
61
|
+
config,
|
|
62
|
+
siteInfo,
|
|
63
|
+
accounts,
|
|
64
|
+
addons,
|
|
65
|
+
buildDir,
|
|
66
|
+
branch,
|
|
67
|
+
deployId,
|
|
68
|
+
buildId,
|
|
69
|
+
context,
|
|
70
|
+
});
|
|
71
|
+
// @todo Remove in the next major version.
|
|
72
|
+
const configA = addLegacyFunctionsDirectory(config);
|
|
73
|
+
const result = {
|
|
74
|
+
siteInfo,
|
|
75
|
+
accounts,
|
|
76
|
+
addons,
|
|
77
|
+
env,
|
|
78
|
+
configPath,
|
|
79
|
+
redirectsPath,
|
|
80
|
+
headersPath,
|
|
81
|
+
buildDir,
|
|
82
|
+
repositoryRoot,
|
|
83
|
+
config: configA,
|
|
84
|
+
context,
|
|
85
|
+
branch,
|
|
86
|
+
token,
|
|
87
|
+
api,
|
|
88
|
+
logs,
|
|
89
|
+
};
|
|
90
|
+
logResult(result, { logs, debug });
|
|
91
|
+
return result;
|
|
92
|
+
};
|
|
123
93
|
// Adds a `build.functions` property that mirrors `functionsDirectory`, for
|
|
124
94
|
// backward compatibility.
|
|
125
95
|
const addLegacyFunctionsDirectory = (config) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
96
|
+
if (!config.functionsDirectory) {
|
|
97
|
+
return config;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
...config,
|
|
101
|
+
build: {
|
|
102
|
+
...config.build,
|
|
103
|
+
functions: config.functionsDirectory,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
};
|
|
139
107
|
// Try to load the configuration file in two passes.
|
|
140
108
|
// The first pass uses the `defaultConfig`'s `build.base` (if defined).
|
|
141
109
|
// 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
|
-
|
|
110
|
+
const loadConfig = async function ({ configOpt, cwd, context, repositoryRoot, branch, defaultConfig, inlineConfig, baseRelDir, logs, featureFlags, }) {
|
|
111
|
+
const initialBase = getInitialBase({ repositoryRoot, defaultConfig, inlineConfig });
|
|
112
|
+
const { configPath, config, buildDir, base, redirectsPath, headersPath } = await getFullConfig({
|
|
113
|
+
configOpt,
|
|
114
|
+
cwd,
|
|
115
|
+
context,
|
|
116
|
+
repositoryRoot,
|
|
117
|
+
branch,
|
|
118
|
+
defaultConfig,
|
|
119
|
+
inlineConfig,
|
|
120
|
+
baseRelDir,
|
|
121
|
+
configBase: initialBase,
|
|
122
|
+
logs,
|
|
123
|
+
featureFlags,
|
|
124
|
+
});
|
|
125
|
+
// No second pass needed if:
|
|
126
|
+
// - there is no `build.base` (in which case both `base` and `initialBase`
|
|
127
|
+
// are `undefined`)
|
|
128
|
+
// - `build.base` is the same as the `Base directory` UI setting (already
|
|
129
|
+
// used in the first round)
|
|
130
|
+
// - `baseRelDir` feature flag is not used. This feature flag was introduced
|
|
131
|
+
// to ensure backward compatibility.
|
|
132
|
+
if (!baseRelDir || base === initialBase) {
|
|
133
|
+
return { configPath, config, buildDir, redirectsPath, headersPath };
|
|
134
|
+
}
|
|
135
|
+
const { configPath: configPathA, config: configA, buildDir: buildDirA, redirectsPath: redirectsPathA, headersPath: headersPathA, } = await getFullConfig({
|
|
136
|
+
cwd,
|
|
137
|
+
context,
|
|
138
|
+
repositoryRoot,
|
|
139
|
+
branch,
|
|
140
|
+
defaultConfig,
|
|
141
|
+
inlineConfig,
|
|
142
|
+
baseRelDir,
|
|
143
|
+
configBase: base,
|
|
144
|
+
base,
|
|
145
|
+
logs,
|
|
146
|
+
featureFlags,
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
configPath: configPathA,
|
|
150
|
+
config: configA,
|
|
151
|
+
buildDir: buildDirA,
|
|
152
|
+
redirectsPath: redirectsPathA,
|
|
153
|
+
headersPath: headersPathA,
|
|
154
|
+
};
|
|
155
|
+
};
|
|
208
156
|
// 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
|
-
|
|
157
|
+
const getFullConfig = async function ({ configOpt, cwd, context, repositoryRoot, branch, defaultConfig, inlineConfig, baseRelDir, configBase, base, logs, featureFlags, }) {
|
|
158
|
+
const configPath = await getConfigPath({ configOpt, cwd, repositoryRoot, configBase });
|
|
159
|
+
try {
|
|
160
|
+
const config = await parseConfig(configPath);
|
|
161
|
+
const configA = mergeAndNormalizeConfig({
|
|
162
|
+
config,
|
|
163
|
+
defaultConfig,
|
|
164
|
+
inlineConfig,
|
|
165
|
+
context,
|
|
166
|
+
branch,
|
|
167
|
+
logs,
|
|
168
|
+
});
|
|
169
|
+
const { config: configB, buildDir, base: baseA, } = await resolveFiles({ config: configA, repositoryRoot, base, baseRelDir });
|
|
170
|
+
const headersPath = getHeadersPath(configB);
|
|
171
|
+
const configC = await addHeaders({ config: configB, headersPath, logs, featureFlags });
|
|
172
|
+
const redirectsPath = getRedirectsPath(configC);
|
|
173
|
+
const configD = await addRedirects({ config: configC, redirectsPath, logs, featureFlags });
|
|
174
|
+
return { configPath, config: configD, buildDir, base: baseA, redirectsPath, headersPath };
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
const configName = configPath === undefined ? '' : ` file ${configPath}`;
|
|
178
|
+
error.message = `When resolving config${configName}:\n${error.message}`;
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
252
182
|
// Merge:
|
|
253
183
|
// - `--defaultConfig`: UI build settings and UI-installed plugins
|
|
254
184
|
// - `inlineConfig`: Netlify CLI flags
|
|
@@ -257,29 +187,25 @@ const getFullConfig = async function ({
|
|
|
257
187
|
// Those need to be done at different stages depending on whether they should
|
|
258
188
|
// happen before/after the merges mentioned above.
|
|
259
189
|
const mergeAndNormalizeConfig = function ({ config, defaultConfig, inlineConfig, context, branch, logs }) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return configE
|
|
270
|
-
}
|
|
271
|
-
|
|
190
|
+
const configA = normalizeConfigAndContext(config, CONFIG_ORIGIN);
|
|
191
|
+
const defaultConfigA = normalizeConfigAndContext(defaultConfig, UI_ORIGIN);
|
|
192
|
+
const inlineConfigA = normalizeConfigAndContext(inlineConfig, INLINE_ORIGIN);
|
|
193
|
+
const configB = mergeConfigs([defaultConfigA, configA]);
|
|
194
|
+
const configC = mergeContext({ config: configB, context, branch, logs });
|
|
195
|
+
const configD = mergeConfigs([configC, inlineConfigA]);
|
|
196
|
+
const configE = normalizeAfterConfigMerge(configD);
|
|
197
|
+
return configE;
|
|
198
|
+
};
|
|
272
199
|
const normalizeConfigAndContext = function (config, origin) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
200
|
+
const configA = normalizeBeforeConfigMerge(config, origin);
|
|
201
|
+
const configB = normalizeContextProps({ config: configA, origin });
|
|
202
|
+
return configB;
|
|
203
|
+
};
|
|
278
204
|
// Find base directory, build directory and resolve all paths to absolute paths
|
|
279
205
|
const resolveFiles = async function ({ config, repositoryRoot, base, baseRelDir }) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
206
|
+
const baseA = getBase(base, repositoryRoot, config);
|
|
207
|
+
const buildDir = await getBuildDir(repositoryRoot, baseA);
|
|
208
|
+
const configA = await resolveConfigPaths({ config, repositoryRoot, buildDir, baseRelDir });
|
|
209
|
+
const configB = addBase(configA, baseA);
|
|
210
|
+
return { config: configB, buildDir, base: baseA };
|
|
211
|
+
};
|
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
|
+
};
|