@netlify/config 18.2.2 → 18.2.4-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/package.json +8 -7
- package/src/api/build_settings.js +0 -41
- package/src/api/client.js +0 -15
- package/src/api/site_info.js +0 -67
- package/src/base.js +0 -34
- package/src/bin/flags.js +0 -181
- package/src/bin/main.js +0 -73
- package/src/build_dir.js +0 -26
- package/src/cached_config.js +0 -29
- package/src/case.js +0 -37
- package/src/context.js +0 -108
- package/src/default.js +0 -31
- package/src/env/envelope.js +0 -24
- package/src/env/git.js +0 -23
- package/src/env/main.js +0 -202
- package/src/error.js +0 -36
- package/src/events.js +0 -22
- package/src/files.js +0 -107
- package/src/functions_config.js +0 -83
- package/src/headers.js +0 -30
- package/src/inline_config.js +0 -9
- package/src/log/cleanup.js +0 -92
- package/src/log/logger.js +0 -47
- package/src/log/main.js +0 -48
- package/src/log/messages.js +0 -126
- package/src/log/options.js +0 -43
- package/src/log/serialize.js +0 -5
- package/src/log/theme.js +0 -14
- package/src/main.js +0 -285
- package/src/merge.js +0 -53
- package/src/merge_normalize.js +0 -31
- package/src/mutations/apply.js +0 -78
- package/src/mutations/config_prop_name.js +0 -16
- package/src/mutations/update.js +0 -117
- package/src/normalize.js +0 -36
- package/src/options/base.js +0 -66
- package/src/options/branch.js +0 -34
- package/src/options/feature_flags.js +0 -15
- package/src/options/main.js +0 -111
- package/src/options/repository_root.js +0 -21
- package/src/origin.js +0 -38
- package/src/parse.js +0 -69
- package/src/path.js +0 -52
- package/src/redirects.js +0 -29
- package/src/simplify.js +0 -103
- package/src/utils/group.js +0 -10
- package/src/utils/remove_falsy.js +0 -18
- package/src/utils/set.js +0 -33
- package/src/utils/toml.js +0 -23
- package/src/validate/context.js +0 -57
- package/src/validate/example.js +0 -37
- package/src/validate/helpers.js +0 -31
- package/src/validate/identical.js +0 -20
- package/src/validate/main.js +0 -143
- package/src/validate/validations.js +0 -289
package/src/log/main.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { cleanupConfig, cleanupEnvironment } from './cleanup.js'
|
|
2
|
-
import { logObject, logSubHeader } from './logger.js'
|
|
3
|
-
import { cleanupConfigOpts } from './options.js'
|
|
4
|
-
|
|
5
|
-
// Log options in debug mode.
|
|
6
|
-
export const logOpts = function (opts, { logs, debug, cachedConfig, cachedConfigPath }) {
|
|
7
|
-
// In production, print those in the first call to `@netlify/config`, not the
|
|
8
|
-
// second one done inside `@netlify/build`
|
|
9
|
-
if (!debug || cachedConfig !== undefined || cachedConfigPath !== undefined) {
|
|
10
|
-
return
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
logSubHeader(logs, 'Initial build environment')
|
|
14
|
-
logObject(logs, cleanupConfigOpts(opts))
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Log `defaultConfig` option in debug mode
|
|
18
|
-
export const logDefaultConfig = function (defaultConfig, { logs, debug, baseRelDir }) {
|
|
19
|
-
if (!debug || defaultConfig === undefined) {
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
logSubHeader(logs, 'UI build settings')
|
|
24
|
-
logObject(logs, cleanupConfig({ ...defaultConfig, baseRelDir }))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Log `inlineConfig` option in debug mode
|
|
28
|
-
export const logInlineConfig = function (initialConfig, { logs, debug }) {
|
|
29
|
-
if (!debug || Object.keys(initialConfig).length === 0) {
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
logSubHeader(logs, 'Configuration override')
|
|
34
|
-
logObject(logs, cleanupConfig(initialConfig))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Log return value of `@netlify/config` in debug mode
|
|
38
|
-
export const logResult = function ({ configPath, buildDir, config, context, branch, env }, { logs, debug }) {
|
|
39
|
-
if (!debug) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
logSubHeader(logs, 'Resolved build environment')
|
|
44
|
-
logObject(logs, { configPath, buildDir, context, branch, env: cleanupEnvironment(env) })
|
|
45
|
-
|
|
46
|
-
logSubHeader(logs, 'Resolved config')
|
|
47
|
-
logObject(logs, cleanupConfig(config))
|
|
48
|
-
}
|
package/src/log/messages.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { throwUserError } from '../error.js'
|
|
2
|
-
|
|
3
|
-
import { logWarning } from './logger.js'
|
|
4
|
-
|
|
5
|
-
export const ERROR_CALL_TO_ACTION = `Double-check your login status with 'netlify status' or contact support with details of your error.`
|
|
6
|
-
|
|
7
|
-
export const throwOnInvalidTomlSequence = function (invalidSequence) {
|
|
8
|
-
throwUserError(
|
|
9
|
-
`In netlify.toml, the following backslash should be escaped: ${invalidSequence}
|
|
10
|
-
The following should be used instead: \\${invalidSequence}`,
|
|
11
|
-
)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const warnLegacyFunctionsDirectory = ({ config = {}, logs }) => {
|
|
15
|
-
const { functionsDirectory, functionsDirectoryOrigin } = config
|
|
16
|
-
|
|
17
|
-
if (functionsDirectoryOrigin !== 'config-v1') {
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
logWarning(
|
|
22
|
-
logs,
|
|
23
|
-
`
|
|
24
|
-
Detected functions directory configuration in netlify.toml under [build] settings.
|
|
25
|
-
We recommend updating netlify.toml to set the functions directory under [functions] settings using the directory property. For example,
|
|
26
|
-
|
|
27
|
-
[functions]
|
|
28
|
-
directory = "${functionsDirectory}"`,
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const warnContextPluginConfig = function (logs, packageName, context) {
|
|
33
|
-
logWarning(
|
|
34
|
-
logs,
|
|
35
|
-
`
|
|
36
|
-
"${packageName}" is installed in the UI, which means that it runs in all deploy contexts, regardless of file-based configuration.
|
|
37
|
-
To run "${packageName}" in the ${context} context only, uninstall the plugin from the site plugins list.`,
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const throwContextPluginsConfig = function (packageName, context) {
|
|
42
|
-
throwUserError(
|
|
43
|
-
`
|
|
44
|
-
"${packageName}" is installed in the UI, which means that it runs in all deploy contexts, regardless of file-based configuration.
|
|
45
|
-
To run "${packageName}" in the ${context} context only, uninstall the plugin from the site plugins list.
|
|
46
|
-
To run "${packageName}" in all contexts, please remove the following section from "netlify.toml".
|
|
47
|
-
|
|
48
|
-
[[context.${context}.plugins]]
|
|
49
|
-
package = "${packageName}"
|
|
50
|
-
`,
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const warnHeadersParsing = function (logs, errors) {
|
|
55
|
-
if (errors.length === 0) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const errorMessage = errors.map(getErrorMessage).join('\n\n')
|
|
60
|
-
logWarning(
|
|
61
|
-
logs,
|
|
62
|
-
`
|
|
63
|
-
Warning: some headers have syntax errors:
|
|
64
|
-
|
|
65
|
-
${errorMessage}`,
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Headers with different cases are not currently the way users probably
|
|
70
|
-
// intend them to be, so we print a warning message.
|
|
71
|
-
// See issue at https://github.com/netlify/build/issues/2290
|
|
72
|
-
export const warnHeadersCaseSensitivity = function (logs, headers) {
|
|
73
|
-
const headersA = headers.flatMap(getHeaderNames).filter(isNotDuplicateHeaderName).map(addHeaderLowerCase)
|
|
74
|
-
const differentCaseHeader = headersA.find(hasHeaderCaseDuplicate)
|
|
75
|
-
if (differentCaseHeader === undefined) {
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const { forPath, headerName } = headersA.find((header) => isHeaderCaseDuplicate(header, differentCaseHeader))
|
|
80
|
-
const sameForPath = forPath === differentCaseHeader.forPath ? ` for "${forPath}"` : ''
|
|
81
|
-
logWarning(
|
|
82
|
-
logs,
|
|
83
|
-
`
|
|
84
|
-
Warning: the same header is set twice with different cases${sameForPath}: "${headerName}" and "${differentCaseHeader.headerName}"`,
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const getHeaderNames = function ({ for: forPath, values = {} }) {
|
|
89
|
-
return Object.keys(values).map((headerName) => ({ forPath, headerName }))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const isNotDuplicateHeaderName = function ({ headerName }, index, headers) {
|
|
93
|
-
return headers.slice(index + 1).every((header) => header.headerName !== headerName)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const addHeaderLowerCase = function ({ forPath, headerName }) {
|
|
97
|
-
const lowerHeaderName = headerName.toLowerCase()
|
|
98
|
-
return { forPath, headerName, lowerHeaderName }
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const hasHeaderCaseDuplicate = function ({ lowerHeaderName }, index, headers) {
|
|
102
|
-
return headers.slice(index + 1).some((header) => header.lowerHeaderName === lowerHeaderName)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const isHeaderCaseDuplicate = function ({ headerName, lowerHeaderName }, differentCaseHeader) {
|
|
106
|
-
return differentCaseHeader.headerName !== headerName && differentCaseHeader.lowerHeaderName === lowerHeaderName
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export const warnRedirectsParsing = function (logs, errors) {
|
|
110
|
-
if (errors.length === 0) {
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const errorMessage = errors.map(getErrorMessage).join('\n\n')
|
|
115
|
-
logWarning(
|
|
116
|
-
logs,
|
|
117
|
-
`
|
|
118
|
-
Warning: some redirects have syntax errors:
|
|
119
|
-
|
|
120
|
-
${errorMessage}`,
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const getErrorMessage = function ({ message }) {
|
|
125
|
-
return message
|
|
126
|
-
}
|
package/src/log/options.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
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
|
-
|
|
5
|
-
// Use an allowlist to prevent printing confidential values.
|
|
6
|
-
export const cleanupConfigOpts = function ({
|
|
7
|
-
config,
|
|
8
|
-
cwd,
|
|
9
|
-
context,
|
|
10
|
-
branch,
|
|
11
|
-
mode,
|
|
12
|
-
repositoryRoot,
|
|
13
|
-
siteId,
|
|
14
|
-
baseRelDir,
|
|
15
|
-
env = {},
|
|
16
|
-
featureFlags = {},
|
|
17
|
-
}) {
|
|
18
|
-
const envA = Object.keys(env)
|
|
19
|
-
return removeFalsy({
|
|
20
|
-
config,
|
|
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
|
-
|
|
33
|
-
// We only show feature flags related to `@netlify/config`.
|
|
34
|
-
// Also, we only print enabled feature flags.
|
|
35
|
-
const cleanFeatureFlags = function (featureFlags) {
|
|
36
|
-
return Object.entries(featureFlags)
|
|
37
|
-
.filter(shouldPrintFeatureFlag)
|
|
38
|
-
.map(([featureFlagName]) => featureFlagName)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const shouldPrintFeatureFlag = function ([featureFlagName, enabled]) {
|
|
42
|
-
return enabled && featureFlagName in DEFAULT_FEATURE_FLAGS
|
|
43
|
-
}
|
package/src/log/serialize.js
DELETED
package/src/log/theme.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk'
|
|
2
|
-
|
|
3
|
-
// Color theme. Please use this instead of requiring chalk directly, to ensure
|
|
4
|
-
// consistent colors.
|
|
5
|
-
export const THEME = {
|
|
6
|
-
// Single lines used as subheaders
|
|
7
|
-
subHeader: chalk.cyan.bold,
|
|
8
|
-
// Single lines used as subheaders indicating an error
|
|
9
|
-
errorSubHeader: chalk.red.bold,
|
|
10
|
-
// Same for warnings
|
|
11
|
-
warningLine: chalk.yellowBright,
|
|
12
|
-
// One of several words that should be highlighted inside a line
|
|
13
|
-
highlightWords: chalk.cyan,
|
|
14
|
-
}
|
package/src/main.js
DELETED
|
@@ -1,285 +0,0 @@
|
|
|
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 { DEV_EVENTS, EVENTS } from './events.js'
|
|
22
|
-
export { cleanupConfig } from './log/cleanup.js'
|
|
23
|
-
// eslint-disable-next-line import/max-dependencies
|
|
24
|
-
export { updateConfig, restoreConfig } from './mutations/update.js'
|
|
25
|
-
|
|
26
|
-
// Load the configuration file.
|
|
27
|
-
// Takes an optional configuration file path as input and return the resolved
|
|
28
|
-
// `config` together with related properties such as the `configPath`.
|
|
29
|
-
export const resolveConfig = async function (opts) {
|
|
30
|
-
const { cachedConfig, cachedConfigPath, host, scheme, pathPrefix, testOpts, token, offline, ...optsA } =
|
|
31
|
-
addDefaultOpts(opts)
|
|
32
|
-
// `api` is not JSON-serializable, so we cannot cache it inside `cachedConfig`
|
|
33
|
-
const api = getApiClient({ token, offline, host, scheme, pathPrefix, testOpts })
|
|
34
|
-
|
|
35
|
-
const parsedCachedConfig = await getCachedConfig({ cachedConfig, cachedConfigPath, token, api })
|
|
36
|
-
if (parsedCachedConfig !== undefined) {
|
|
37
|
-
return parsedCachedConfig
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const {
|
|
41
|
-
config: configOpt,
|
|
42
|
-
defaultConfig,
|
|
43
|
-
inlineConfig,
|
|
44
|
-
configMutations,
|
|
45
|
-
cwd,
|
|
46
|
-
context,
|
|
47
|
-
repositoryRoot,
|
|
48
|
-
base,
|
|
49
|
-
branch,
|
|
50
|
-
siteId,
|
|
51
|
-
deployId,
|
|
52
|
-
buildId,
|
|
53
|
-
baseRelDir,
|
|
54
|
-
mode,
|
|
55
|
-
debug,
|
|
56
|
-
logs,
|
|
57
|
-
featureFlags,
|
|
58
|
-
} = await normalizeOpts(optsA)
|
|
59
|
-
|
|
60
|
-
const { siteInfo, accounts, addons } = await getSiteInfo({ api, siteId, mode, testOpts })
|
|
61
|
-
|
|
62
|
-
const { defaultConfig: defaultConfigA, baseRelDir: baseRelDirA } = parseDefaultConfig({
|
|
63
|
-
defaultConfig,
|
|
64
|
-
base,
|
|
65
|
-
baseRelDir,
|
|
66
|
-
siteInfo,
|
|
67
|
-
logs,
|
|
68
|
-
debug,
|
|
69
|
-
})
|
|
70
|
-
const inlineConfigA = getInlineConfig({ inlineConfig, configMutations, logs, debug })
|
|
71
|
-
|
|
72
|
-
const { configPath, config, buildDir, redirectsPath, headersPath } = await loadConfig({
|
|
73
|
-
configOpt,
|
|
74
|
-
cwd,
|
|
75
|
-
context,
|
|
76
|
-
repositoryRoot,
|
|
77
|
-
branch,
|
|
78
|
-
defaultConfig: defaultConfigA,
|
|
79
|
-
inlineConfig: inlineConfigA,
|
|
80
|
-
baseRelDir: baseRelDirA,
|
|
81
|
-
logs,
|
|
82
|
-
featureFlags,
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
const env = await getEnv({
|
|
86
|
-
api,
|
|
87
|
-
mode,
|
|
88
|
-
config,
|
|
89
|
-
siteInfo,
|
|
90
|
-
accounts,
|
|
91
|
-
addons,
|
|
92
|
-
buildDir,
|
|
93
|
-
branch,
|
|
94
|
-
deployId,
|
|
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
|
-
|
|
123
|
-
// Adds a `build.functions` property that mirrors `functionsDirectory`, for
|
|
124
|
-
// backward compatibility.
|
|
125
|
-
const addLegacyFunctionsDirectory = (config) => {
|
|
126
|
-
if (!config.functionsDirectory) {
|
|
127
|
-
return config
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
...config,
|
|
132
|
-
build: {
|
|
133
|
-
...config.build,
|
|
134
|
-
functions: config.functionsDirectory,
|
|
135
|
-
},
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Try to load the configuration file in two passes.
|
|
140
|
-
// The first pass uses the `defaultConfig`'s `build.base` (if defined).
|
|
141
|
-
// The second pass uses the `build.base` from the first pass (if defined).
|
|
142
|
-
const loadConfig = async function ({
|
|
143
|
-
configOpt,
|
|
144
|
-
cwd,
|
|
145
|
-
context,
|
|
146
|
-
repositoryRoot,
|
|
147
|
-
branch,
|
|
148
|
-
defaultConfig,
|
|
149
|
-
inlineConfig,
|
|
150
|
-
baseRelDir,
|
|
151
|
-
logs,
|
|
152
|
-
featureFlags,
|
|
153
|
-
}) {
|
|
154
|
-
const initialBase = getInitialBase({ repositoryRoot, defaultConfig, inlineConfig })
|
|
155
|
-
const { configPath, config, buildDir, base, redirectsPath, headersPath } = await getFullConfig({
|
|
156
|
-
configOpt,
|
|
157
|
-
cwd,
|
|
158
|
-
context,
|
|
159
|
-
repositoryRoot,
|
|
160
|
-
branch,
|
|
161
|
-
defaultConfig,
|
|
162
|
-
inlineConfig,
|
|
163
|
-
baseRelDir,
|
|
164
|
-
configBase: initialBase,
|
|
165
|
-
logs,
|
|
166
|
-
featureFlags,
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
// No second pass needed if:
|
|
170
|
-
// - there is no `build.base` (in which case both `base` and `initialBase`
|
|
171
|
-
// are `undefined`)
|
|
172
|
-
// - `build.base` is the same as the `Base directory` UI setting (already
|
|
173
|
-
// used in the first round)
|
|
174
|
-
// - `baseRelDir` feature flag is not used. This feature flag was introduced
|
|
175
|
-
// to ensure backward compatibility.
|
|
176
|
-
if (!baseRelDir || base === initialBase) {
|
|
177
|
-
return { configPath, config, buildDir, redirectsPath, headersPath }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const {
|
|
181
|
-
configPath: configPathA,
|
|
182
|
-
config: configA,
|
|
183
|
-
buildDir: buildDirA,
|
|
184
|
-
redirectsPath: redirectsPathA,
|
|
185
|
-
headersPath: headersPathA,
|
|
186
|
-
} = await getFullConfig({
|
|
187
|
-
cwd,
|
|
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
|
-
|
|
208
|
-
// Load configuration file and normalize it, merge contexts, etc.
|
|
209
|
-
const getFullConfig = async function ({
|
|
210
|
-
configOpt,
|
|
211
|
-
cwd,
|
|
212
|
-
context,
|
|
213
|
-
repositoryRoot,
|
|
214
|
-
branch,
|
|
215
|
-
defaultConfig,
|
|
216
|
-
inlineConfig,
|
|
217
|
-
baseRelDir,
|
|
218
|
-
configBase,
|
|
219
|
-
base,
|
|
220
|
-
logs,
|
|
221
|
-
featureFlags,
|
|
222
|
-
}) {
|
|
223
|
-
const configPath = await getConfigPath({ configOpt, cwd, repositoryRoot, configBase })
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const config = await parseConfig(configPath)
|
|
227
|
-
const configA = mergeAndNormalizeConfig({
|
|
228
|
-
config,
|
|
229
|
-
defaultConfig,
|
|
230
|
-
inlineConfig,
|
|
231
|
-
context,
|
|
232
|
-
branch,
|
|
233
|
-
logs,
|
|
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
|
-
|
|
252
|
-
// Merge:
|
|
253
|
-
// - `--defaultConfig`: UI build settings and UI-installed plugins
|
|
254
|
-
// - `inlineConfig`: Netlify CLI flags
|
|
255
|
-
// Then merge context-specific configuration.
|
|
256
|
-
// Before and after those steps, also performs validation and normalization.
|
|
257
|
-
// Those need to be done at different stages depending on whether they should
|
|
258
|
-
// happen before/after the merges mentioned above.
|
|
259
|
-
const mergeAndNormalizeConfig = function ({ config, defaultConfig, inlineConfig, context, branch, logs }) {
|
|
260
|
-
const configA = normalizeConfigAndContext(config, CONFIG_ORIGIN)
|
|
261
|
-
const defaultConfigA = normalizeConfigAndContext(defaultConfig, UI_ORIGIN)
|
|
262
|
-
const inlineConfigA = normalizeConfigAndContext(inlineConfig, INLINE_ORIGIN)
|
|
263
|
-
|
|
264
|
-
const configB = mergeConfigs([defaultConfigA, configA])
|
|
265
|
-
const configC = mergeContext({ config: configB, context, branch, logs })
|
|
266
|
-
const configD = mergeConfigs([configC, inlineConfigA])
|
|
267
|
-
|
|
268
|
-
const configE = normalizeAfterConfigMerge(configD)
|
|
269
|
-
return configE
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const normalizeConfigAndContext = function (config, origin) {
|
|
273
|
-
const configA = normalizeBeforeConfigMerge(config, origin)
|
|
274
|
-
const configB = normalizeContextProps({ config: configA, origin })
|
|
275
|
-
return configB
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Find base directory, build directory and resolve all paths to absolute paths
|
|
279
|
-
const resolveFiles = async function ({ config, repositoryRoot, base, baseRelDir }) {
|
|
280
|
-
const baseA = getBase(base, repositoryRoot, config)
|
|
281
|
-
const buildDir = await getBuildDir(repositoryRoot, baseA)
|
|
282
|
-
const configA = await resolveConfigPaths({ config, repositoryRoot, buildDir, baseRelDir })
|
|
283
|
-
const configB = addBase(configA, baseA)
|
|
284
|
-
return { config: configB, buildDir, base: baseA }
|
|
285
|
-
}
|
package/src/merge.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import deepmerge from 'deepmerge'
|
|
2
|
-
import isPlainObj from 'is-plain-obj'
|
|
3
|
-
|
|
4
|
-
import { groupBy } from './utils/group.js'
|
|
5
|
-
import { removeUndefined } from './utils/remove_falsy.js'
|
|
6
|
-
|
|
7
|
-
// Merge an array of configuration objects.
|
|
8
|
-
// Last items have higher priority.
|
|
9
|
-
// Configuration objects are deeply merged.
|
|
10
|
-
// - Arrays are overridden, not concatenated.
|
|
11
|
-
export const mergeConfigs = function (configs) {
|
|
12
|
-
const cleanedConfigs = configs.map(removeUndefinedProps)
|
|
13
|
-
return deepmerge.all(cleanedConfigs, { arrayMerge })
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const removeUndefinedProps = function ({ build = {}, ...config }) {
|
|
17
|
-
return removeUndefined({ ...config, build: removeUndefined(build) })
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// By default `deepmerge` concatenates arrays. We use the `arrayMerge` option
|
|
21
|
-
// to remove this behavior. Also, we merge some array properties differently,
|
|
22
|
-
// such as `plugins`.
|
|
23
|
-
const arrayMerge = function (arrayA, arrayB) {
|
|
24
|
-
if (isPluginsProperty(arrayA) && isPluginsProperty(arrayB)) {
|
|
25
|
-
return mergePlugins(arrayA, arrayB)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return arrayB
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// `deepmerge` does not allow retrieving the name of the array property being
|
|
32
|
-
// merged, so we need to do some heuristics.
|
|
33
|
-
const isPluginsProperty = function (array) {
|
|
34
|
-
return Array.isArray(array) && array.every(isPluginObject)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const isPluginObject = function (object) {
|
|
38
|
-
return isPlainObj(object) && typeof object.package === 'string'
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Merge two `config.plugins`. Merge plugins with the same `plugin.package`.
|
|
42
|
-
const mergePlugins = function (pluginsA, pluginsB) {
|
|
43
|
-
const plugins = [...pluginsA, ...pluginsB]
|
|
44
|
-
return groupBy(plugins, 'package').map(mergePluginConfigs)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const mergePluginConfigs = function (plugins) {
|
|
48
|
-
return plugins.reduce(mergePluginsPair, {})
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const mergePluginsPair = function (pluginA, pluginB) {
|
|
52
|
-
return deepmerge(pluginA, pluginB, { arrayMerge })
|
|
53
|
-
}
|
package/src/merge_normalize.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { normalizeConfigCase } from './case.js'
|
|
2
|
-
import { normalizeConfig } from './normalize.js'
|
|
3
|
-
import { addOrigins } from './origin.js'
|
|
4
|
-
import { validateIdenticalPlugins } from './validate/identical.js'
|
|
5
|
-
import {
|
|
6
|
-
validatePreCaseNormalize,
|
|
7
|
-
validatePreMergeConfig,
|
|
8
|
-
validatePreNormalizeConfig,
|
|
9
|
-
validatePostNormalizeConfig,
|
|
10
|
-
} from './validate/main.js'
|
|
11
|
-
|
|
12
|
-
// Perform validation and normalization logic to apply to all of:
|
|
13
|
-
// - config, defaultConfig, inlineConfig
|
|
14
|
-
// - context-specific configs
|
|
15
|
-
// Therefore, this is performing before merging those together.
|
|
16
|
-
export const normalizeBeforeConfigMerge = function (config, origin) {
|
|
17
|
-
validatePreCaseNormalize(config)
|
|
18
|
-
const configA = normalizeConfigCase(config)
|
|
19
|
-
validatePreMergeConfig(configA)
|
|
20
|
-
const configB = addOrigins(configA, origin)
|
|
21
|
-
validateIdenticalPlugins(configB)
|
|
22
|
-
return configB
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Validation and normalization logic performed after merging
|
|
26
|
-
export const normalizeAfterConfigMerge = function (config) {
|
|
27
|
-
validatePreNormalizeConfig(config)
|
|
28
|
-
const configA = normalizeConfig(config)
|
|
29
|
-
validatePostNormalizeConfig(configA)
|
|
30
|
-
return configA
|
|
31
|
-
}
|
package/src/mutations/apply.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { throwUserError } from '../error.js'
|
|
2
|
-
import { EVENTS } from '../events.js'
|
|
3
|
-
import { WILDCARD_ALL, FUNCTION_CONFIG_PROPERTIES } from '../functions_config.js'
|
|
4
|
-
import { setProp } from '../utils/set.js'
|
|
5
|
-
|
|
6
|
-
import { getPropName } from './config_prop_name.js'
|
|
7
|
-
|
|
8
|
-
// Apply a series of mutations to `inlineConfig`.
|
|
9
|
-
// Meant to be used to apply configuration changes at build time.
|
|
10
|
-
// Those are applied on the `inlineConfig` object after `@netlify/config`
|
|
11
|
-
// normalization. Therefore, this function also denormalizes (reverts that
|
|
12
|
-
// normalization) so that the final `config` object can be serialized back to
|
|
13
|
-
// a `netlify.toml`.
|
|
14
|
-
export const applyMutations = function (inlineConfig, configMutations) {
|
|
15
|
-
return configMutations.reduce(applyMutation, inlineConfig)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const applyMutation = function (inlineConfig, { keys, value, event }) {
|
|
19
|
-
const propName = getPropName(keys)
|
|
20
|
-
if (!(propName in MUTABLE_PROPS)) {
|
|
21
|
-
throwUserError(`"netlifyConfig.${propName}" is read-only.`)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const { lastEvent, denormalize } = MUTABLE_PROPS[propName]
|
|
25
|
-
validateEvent(lastEvent, event, propName)
|
|
26
|
-
|
|
27
|
-
return denormalize === undefined ? setProp(inlineConfig, keys, value) : denormalize(inlineConfig, value, keys)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const validateEvent = function (lastEvent, event, propName) {
|
|
31
|
-
if (EVENTS.indexOf(lastEvent) < EVENTS.indexOf(event)) {
|
|
32
|
-
throwUserError(`"netlifyConfig.${propName}" cannot be modified after "${lastEvent}".`)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// `functions['*'].*` has higher priority than `functions.*` so we convert the
|
|
37
|
-
// latter to the former.
|
|
38
|
-
const denormalizeFunctionsTopProps = function (
|
|
39
|
-
{ functions, functions: { [WILDCARD_ALL]: wildcardProps } = {}, ...inlineConfig },
|
|
40
|
-
value,
|
|
41
|
-
[, key],
|
|
42
|
-
) {
|
|
43
|
-
return FUNCTION_CONFIG_PROPERTIES.has(key)
|
|
44
|
-
? {
|
|
45
|
-
...inlineConfig,
|
|
46
|
-
functions: { ...functions, [WILDCARD_ALL]: { ...wildcardProps, [key]: value } },
|
|
47
|
-
}
|
|
48
|
-
: { ...inlineConfig, functions: { ...functions, [key]: value } }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// List of properties that are not read-only.
|
|
52
|
-
const MUTABLE_PROPS = {
|
|
53
|
-
'build.command': { lastEvent: 'onPreBuild' },
|
|
54
|
-
'build.edge_functions': { lastEvent: 'onPostBuild' },
|
|
55
|
-
'build.environment': { lastEvent: 'onPostBuild' },
|
|
56
|
-
'build.environment.*': { lastEvent: 'onPostBuild' },
|
|
57
|
-
'build.functions': { lastEvent: 'onBuild' },
|
|
58
|
-
'build.processing': { lastEvent: 'onPostBuild' },
|
|
59
|
-
'build.processing.css': { lastEvent: 'onPostBuild' },
|
|
60
|
-
'build.processing.css.bundle': { lastEvent: 'onPostBuild' },
|
|
61
|
-
'build.processing.css.minify': { lastEvent: 'onPostBuild' },
|
|
62
|
-
'build.processing.html': { lastEvent: 'onPostBuild' },
|
|
63
|
-
'build.processing.html.pretty_urls': { lastEvent: 'onPostBuild' },
|
|
64
|
-
'build.processing.images': { lastEvent: 'onPostBuild' },
|
|
65
|
-
'build.processing.images.compress': { lastEvent: 'onPostBuild' },
|
|
66
|
-
'build.processing.js': { lastEvent: 'onPostBuild' },
|
|
67
|
-
'build.processing.js.bundle': { lastEvent: 'onPostBuild' },
|
|
68
|
-
'build.processing.js.minify': { lastEvent: 'onPostBuild' },
|
|
69
|
-
'build.processing.skip_processing': { lastEvent: 'onPostBuild' },
|
|
70
|
-
'build.publish': { lastEvent: 'onPostBuild' },
|
|
71
|
-
'build.services': { lastEvent: 'onPostBuild' },
|
|
72
|
-
'build.services.*': { lastEvent: 'onPostBuild' },
|
|
73
|
-
edge_functions: { lastEvent: 'onPostBuild' },
|
|
74
|
-
'functions.*': { lastEvent: 'onBuild', denormalize: denormalizeFunctionsTopProps },
|
|
75
|
-
'functions.*.*': { lastEvent: 'onBuild' },
|
|
76
|
-
headers: { lastEvent: 'onPostBuild' },
|
|
77
|
-
redirects: { lastEvent: 'onPostBuild' },
|
|
78
|
-
}
|