@wordpress/env 6.0.0 → 8.0.0
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/README.md +130 -66
- package/lib/build-docker-compose-config.js +67 -96
- package/lib/cache.js +1 -0
- package/lib/cli.js +39 -10
- package/lib/commands/clean.js +13 -1
- package/lib/commands/destroy.js +21 -42
- package/lib/commands/index.js +1 -0
- package/lib/commands/install-path.js +1 -0
- package/lib/commands/logs.js +1 -0
- package/lib/commands/run.js +45 -21
- package/lib/commands/start.js +29 -8
- package/lib/commands/stop.js +1 -0
- package/lib/config/add-or-replace-port.js +12 -3
- package/lib/config/db-env.js +1 -0
- package/lib/config/detect-directory-type.js +1 -1
- package/lib/config/get-cache-directory.js +39 -0
- package/lib/config/get-config-from-environment-vars.js +106 -0
- package/lib/config/index.js +7 -5
- package/lib/config/load-config.js +92 -0
- package/lib/config/merge-configs.js +105 -0
- package/lib/config/parse-config.js +501 -157
- package/lib/config/parse-source-string.js +164 -0
- package/lib/config/post-process-config.js +202 -0
- package/lib/config/read-raw-config-file.js +7 -33
- package/lib/config/test/__snapshots__/config-integration.js.snap +295 -0
- package/lib/config/test/add-or-replace-port.js +29 -1
- package/lib/config/test/config-integration.js +164 -0
- package/lib/config/test/get-cache-directory.js +57 -0
- package/lib/config/test/merge-configs.js +121 -0
- package/lib/config/test/parse-config.js +393 -0
- package/lib/config/test/parse-source-string.js +154 -0
- package/lib/config/test/post-process-config.js +299 -0
- package/lib/config/test/read-raw-config-file.js +19 -63
- package/lib/config/test/validate-config.js +363 -0
- package/lib/config/validate-config.js +119 -54
- package/lib/env.js +2 -0
- package/lib/execute-lifecycle-script.js +86 -0
- package/lib/get-host-user.js +27 -0
- package/lib/init-config.js +186 -63
- package/lib/md5.js +1 -0
- package/lib/parse-xdebug-mode.js +1 -0
- package/lib/retry.js +1 -0
- package/lib/test/__snapshots__/md5.js.snap +9 -0
- package/lib/test/build-docker-compose-config.js +134 -0
- package/lib/test/cache.js +154 -0
- package/lib/test/cli.js +149 -0
- package/lib/test/execute-lifecycle-script.js +59 -0
- package/lib/test/md5.js +35 -0
- package/lib/test/parse-xdebug-mode.js +41 -0
- package/lib/validate-run-container.js +41 -0
- package/lib/wordpress.js +4 -19
- package/package.json +2 -2
- package/lib/config/config.js +0 -353
- package/lib/config/test/__snapshots__/config.js.snap +0 -83
- package/lib/config/test/config.js +0 -1241
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* External dependencies
|
|
4
|
+
*/
|
|
5
|
+
const path = require( 'path' );
|
|
6
|
+
const os = require( 'os' );
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
const { ValidationError } = require( './validate-config' );
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A WordPress installation, plugin or theme to be loaded into the environment.
|
|
15
|
+
*
|
|
16
|
+
* @typedef WPSource
|
|
17
|
+
* @property {'local'|'git'|'zip'} type The source type.
|
|
18
|
+
* @property {string} path The path to the WordPress installation, plugin or theme.
|
|
19
|
+
* @property {?string} url The URL to the source download if the source type is not local.
|
|
20
|
+
* @property {?string} ref The git ref for the source if the source type is 'git'.
|
|
21
|
+
* @property {string} basename Name that identifies the WordPress installation, plugin or theme.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The string at the beginning of a source path that points to a home-relative
|
|
26
|
+
* directory. Will be '~/' on unix environments and '~\' on Windows.
|
|
27
|
+
*/
|
|
28
|
+
const HOME_PATH_PREFIX = `~${ path.sep }`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parses a source string into a source object.
|
|
32
|
+
*
|
|
33
|
+
* @param {?string} sourceString The source string. See README.md for documentation on valid source string patterns.
|
|
34
|
+
* @param {Object} options
|
|
35
|
+
* @param {string} options.cacheDirectoryPath Path to the work directory located in ~/.wp-env.
|
|
36
|
+
*
|
|
37
|
+
* @return {?WPSource} A source object.
|
|
38
|
+
*/
|
|
39
|
+
function parseSourceString( sourceString, { cacheDirectoryPath } ) {
|
|
40
|
+
if ( sourceString === null ) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
sourceString.startsWith( '.' ) ||
|
|
46
|
+
sourceString.startsWith( HOME_PATH_PREFIX ) ||
|
|
47
|
+
path.isAbsolute( sourceString )
|
|
48
|
+
) {
|
|
49
|
+
let sourcePath;
|
|
50
|
+
if ( sourceString.startsWith( HOME_PATH_PREFIX ) ) {
|
|
51
|
+
sourcePath = path.resolve(
|
|
52
|
+
os.homedir(),
|
|
53
|
+
sourceString.slice( HOME_PATH_PREFIX.length )
|
|
54
|
+
);
|
|
55
|
+
} else {
|
|
56
|
+
sourcePath = path.resolve( sourceString );
|
|
57
|
+
}
|
|
58
|
+
const basename = path.basename( sourcePath );
|
|
59
|
+
return {
|
|
60
|
+
type: 'local',
|
|
61
|
+
path: sourcePath,
|
|
62
|
+
basename,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const zipFields = sourceString.match(
|
|
67
|
+
/^https?:\/\/([^\s$.?#].[^\s]*)\.zip(\?.+)?$/
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
if ( zipFields ) {
|
|
71
|
+
const wpOrgFields = sourceString.match(
|
|
72
|
+
/^https?:\/\/downloads\.wordpress\.org\/(?:plugin|theme)\/([^\s\.]*)([^\s]*)?\.zip$/
|
|
73
|
+
);
|
|
74
|
+
const basename = wpOrgFields
|
|
75
|
+
? encodeURIComponent( wpOrgFields[ 1 ] )
|
|
76
|
+
: encodeURIComponent( path.basename( zipFields[ 1 ] ) );
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
type: 'zip',
|
|
80
|
+
url: sourceString,
|
|
81
|
+
path: path.resolve( cacheDirectoryPath, basename ),
|
|
82
|
+
basename,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// SSH URLs (git)
|
|
87
|
+
const supportedProtocols = [ 'ssh:', 'git+ssh:' ];
|
|
88
|
+
try {
|
|
89
|
+
const sshUrl = new URL( sourceString );
|
|
90
|
+
if ( supportedProtocols.includes( sshUrl.protocol ) ) {
|
|
91
|
+
const pathElements = sshUrl.pathname
|
|
92
|
+
.split( '/' )
|
|
93
|
+
.filter( ( e ) => !! e );
|
|
94
|
+
const basename = pathElements
|
|
95
|
+
.slice( -1 )[ 0 ]
|
|
96
|
+
.replace( /\.git/, '' );
|
|
97
|
+
const workingPath = path.resolve(
|
|
98
|
+
cacheDirectoryPath,
|
|
99
|
+
...pathElements.slice( 0, -1 ),
|
|
100
|
+
basename
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
type: 'git',
|
|
104
|
+
url: sshUrl.href.split( '#' )[ 0 ],
|
|
105
|
+
ref: sshUrl.hash.slice( 1 ) || undefined,
|
|
106
|
+
path: workingPath,
|
|
107
|
+
clonePath: workingPath,
|
|
108
|
+
basename,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
} catch ( err ) {}
|
|
112
|
+
|
|
113
|
+
const gitHubFields = sourceString.match(
|
|
114
|
+
/^([^\/]+)\/([^#\/]+)(\/([^#]+))?(?:#(.+))?$/
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if ( gitHubFields ) {
|
|
118
|
+
return {
|
|
119
|
+
type: 'git',
|
|
120
|
+
url: `https://github.com/${ gitHubFields[ 1 ] }/${ gitHubFields[ 2 ] }.git`,
|
|
121
|
+
ref: gitHubFields[ 5 ],
|
|
122
|
+
path: path.resolve(
|
|
123
|
+
cacheDirectoryPath,
|
|
124
|
+
gitHubFields[ 2 ],
|
|
125
|
+
gitHubFields[ 4 ] || '.'
|
|
126
|
+
),
|
|
127
|
+
clonePath: path.resolve( cacheDirectoryPath, gitHubFields[ 2 ] ),
|
|
128
|
+
basename: gitHubFields[ 4 ] || gitHubFields[ 2 ],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
throw new ValidationError(
|
|
133
|
+
`Invalid or unrecognized source: "${ sourceString }".`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Given a source object, returns a new source object with the testsPath
|
|
139
|
+
* property set correctly. Only the 'core' source requires a testsPath.
|
|
140
|
+
*
|
|
141
|
+
* @param {?WPSource} source A source object.
|
|
142
|
+
* @param {Object} options
|
|
143
|
+
* @param {string} options.cacheDirectoryPath Path to the work directory located in ~/.wp-env.
|
|
144
|
+
*
|
|
145
|
+
* @return {?WPSource} A source object.
|
|
146
|
+
*/
|
|
147
|
+
function includeTestsPath( source, { cacheDirectoryPath } ) {
|
|
148
|
+
if ( source === null ) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
...source,
|
|
154
|
+
testsPath: path.resolve(
|
|
155
|
+
cacheDirectoryPath,
|
|
156
|
+
'tests-' + path.basename( source.path )
|
|
157
|
+
),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
parseSourceString,
|
|
163
|
+
includeTestsPath,
|
|
164
|
+
};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* Internal dependencies
|
|
4
|
+
*/
|
|
5
|
+
const mergeConfigs = require( './merge-configs' );
|
|
6
|
+
const addOrReplacePort = require( './add-or-replace-port' );
|
|
7
|
+
const { ValidationError } = require( './validate-config' );
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('./parse-config').WPRootConfig} WPRootConfig
|
|
11
|
+
* @typedef {import('./parse-config').WPEnvironmentConfig} WPEnvironmentConfig
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Performs any additional post-processing on the config object.
|
|
16
|
+
*
|
|
17
|
+
* @param {WPEnvironmentConfig} config The config to process.
|
|
18
|
+
*
|
|
19
|
+
* @return {WPEnvironmentConfig} The config after post-processing.
|
|
20
|
+
*/
|
|
21
|
+
module.exports = function postProcessConfig( config ) {
|
|
22
|
+
// Make sure that we're operating on a config object that has
|
|
23
|
+
// complete environment configs for convenience.
|
|
24
|
+
config = mergeRootToEnvironments( config );
|
|
25
|
+
|
|
26
|
+
config = appendPortToWPConfigs( config );
|
|
27
|
+
|
|
28
|
+
validate( config );
|
|
29
|
+
return config;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Merges the root config and each environment together in order to make sure each environment has
|
|
34
|
+
* a full config object to work with internally. This makes it easier than having to try and
|
|
35
|
+
* resolve the full config options every time we want to use them for something.
|
|
36
|
+
*
|
|
37
|
+
* @param {WPEnvironmentConfig} config The config to process.
|
|
38
|
+
*
|
|
39
|
+
* @return {WPRootConfig} The config object with the root options merged together with the environment-specific options.
|
|
40
|
+
*/
|
|
41
|
+
function mergeRootToEnvironments( config ) {
|
|
42
|
+
// Some root-level options need to be handled early because they have a special
|
|
43
|
+
// cascade behavior that would break the normal merge. After merging we then
|
|
44
|
+
// delete them to avoid that breakage and add them back before we return.
|
|
45
|
+
const removedRootOptions = {};
|
|
46
|
+
if (
|
|
47
|
+
config.port !== undefined &&
|
|
48
|
+
config.env.development.port === undefined
|
|
49
|
+
) {
|
|
50
|
+
removedRootOptions.port = config.port;
|
|
51
|
+
config.env.development.port = config.port;
|
|
52
|
+
delete config.port;
|
|
53
|
+
}
|
|
54
|
+
if (
|
|
55
|
+
config.testsPort !== undefined &&
|
|
56
|
+
config.env.tests.port === undefined
|
|
57
|
+
) {
|
|
58
|
+
removedRootOptions.testsPort = config.testsPort;
|
|
59
|
+
config.env.tests.port = config.testsPort;
|
|
60
|
+
delete config.testsPort;
|
|
61
|
+
}
|
|
62
|
+
if ( config.lifecycleScripts !== undefined ) {
|
|
63
|
+
removedRootOptions.lifecycleScripts = config.lifecycleScripts;
|
|
64
|
+
delete config.lifecycleScripts;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Merge the root config and the environment configs together so that
|
|
68
|
+
// we can ignore the root config and have full environment configs.
|
|
69
|
+
for ( const env in config.env ) {
|
|
70
|
+
config.env[ env ] = mergeConfigs(
|
|
71
|
+
deepCopyRootOptions( config ),
|
|
72
|
+
config.env[ env ]
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Set any root-level options we reset back.
|
|
77
|
+
for ( const option in removedRootOptions ) {
|
|
78
|
+
config[ option ] = removedRootOptions[ option ];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return config;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Appends the configured port to certain wp-config options.
|
|
86
|
+
*
|
|
87
|
+
* @param {WPRootConfig} config The config to process.
|
|
88
|
+
*
|
|
89
|
+
* @return {WPRootConfig} The config after post-processing.
|
|
90
|
+
*/
|
|
91
|
+
function appendPortToWPConfigs( config ) {
|
|
92
|
+
const options = [ 'WP_TESTS_DOMAIN', 'WP_SITEURL', 'WP_HOME' ];
|
|
93
|
+
|
|
94
|
+
// We are only interested in editing the config options for environment-specific configs.
|
|
95
|
+
// If we made this change to the root config it would cause problems since they would
|
|
96
|
+
// be mapped to all environments even though the ports will be different.
|
|
97
|
+
for ( const env in config.env ) {
|
|
98
|
+
// There's nothing to do without any wp-config options set.
|
|
99
|
+
if ( config.env[ env ].config === undefined ) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if ( config.env[ env ].port === undefined ) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Make sure that the port is on the option if it's present.
|
|
108
|
+
for ( const option of options ) {
|
|
109
|
+
if ( config.env[ env ].config[ option ] === undefined ) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
config.env[ env ].config[ option ] = addOrReplacePort(
|
|
114
|
+
config.env[ env ].config[ option ],
|
|
115
|
+
config.env[ env ].port,
|
|
116
|
+
// Don't replace the port if one is already set on WP_HOME.
|
|
117
|
+
option !== 'WP_HOME'
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return config;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Examines the config to make sure that none of the environments share the same port.
|
|
127
|
+
*
|
|
128
|
+
* @param {WPRootConfig} config The config to process.
|
|
129
|
+
*/
|
|
130
|
+
function validatePortUniqueness( config ) {
|
|
131
|
+
// We're going to build a map of the environments and their port
|
|
132
|
+
// so we can accomodate root-level config options more easily.
|
|
133
|
+
const environmentPorts = {};
|
|
134
|
+
|
|
135
|
+
// Add all of the environments to the map. This will
|
|
136
|
+
// overwrite any root-level options if necessary.
|
|
137
|
+
for ( const env in config.env ) {
|
|
138
|
+
if ( config.env[ env ].port === undefined ) {
|
|
139
|
+
throw new ValidationError(
|
|
140
|
+
`The "${ env }" environment has an invalid port.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
environmentPorts[ env ] = config.env[ env ].port;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// This search isn't very performant, but, we won't ever be
|
|
148
|
+
// checking more than a few entries so it doesn't matter.
|
|
149
|
+
for ( const env in environmentPorts ) {
|
|
150
|
+
for ( const check in environmentPorts ) {
|
|
151
|
+
if ( env === check ) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ( environmentPorts[ env ] === environmentPorts[ check ] ) {
|
|
156
|
+
throw new ValidationError(
|
|
157
|
+
`The "${ env }" and "${ check }" environments may not have the same port.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Perform any validation that can only happen after post-processing has occurred.
|
|
166
|
+
*
|
|
167
|
+
* @param {WPRootConfig} config The config to validate.
|
|
168
|
+
*/
|
|
169
|
+
function validate( config ) {
|
|
170
|
+
validatePortUniqueness( config );
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Creates a deep copy of the root options in the config object that we can use to avoid
|
|
175
|
+
* accidentally sharing object state between different environments.
|
|
176
|
+
*
|
|
177
|
+
* @param {WPRootConfig} config The root config object to copy.
|
|
178
|
+
*
|
|
179
|
+
* @return {WPRootConfig} A deep copy of the root config object.
|
|
180
|
+
*/
|
|
181
|
+
function deepCopyRootOptions( config ) {
|
|
182
|
+
// Create a shallow clone of the object first so we can operate on it safetly.
|
|
183
|
+
const rootConfig = Object.assign( {}, config );
|
|
184
|
+
|
|
185
|
+
// Since we're only dealing with the root options we don't want the environments.
|
|
186
|
+
delete rootConfig.env;
|
|
187
|
+
|
|
188
|
+
if ( rootConfig.config !== undefined ) {
|
|
189
|
+
rootConfig.config = Object.assign( {}, rootConfig.config );
|
|
190
|
+
}
|
|
191
|
+
if ( rootConfig.mappings !== undefined ) {
|
|
192
|
+
rootConfig.mappings = Object.assign( {}, rootConfig.mappings );
|
|
193
|
+
}
|
|
194
|
+
if ( rootConfig.pluginSources !== undefined ) {
|
|
195
|
+
rootConfig.pluginSources = [ ...rootConfig.pluginSources ];
|
|
196
|
+
}
|
|
197
|
+
if ( rootConfig.themeSources !== undefined ) {
|
|
198
|
+
rootConfig.themeSources = [ ...rootConfig.themeSources ];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return rootConfig;
|
|
202
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const fs = require( 'fs' ).promises;
|
|
6
6
|
|
|
7
|
+
const path = require( 'path' );
|
|
7
8
|
/**
|
|
8
9
|
* Internal dependencies
|
|
9
10
|
*/
|
|
@@ -13,53 +14,26 @@ const { ValidationError } = require( './validate-config' );
|
|
|
13
14
|
* Reads the config JSON from the filesystem and returns it as a JS object
|
|
14
15
|
* compatible with the env package.
|
|
15
16
|
*
|
|
16
|
-
* @param {string} name The name of the file for error messages.
|
|
17
17
|
* @param {string} configPath The path to the JSON file to read.
|
|
18
18
|
*
|
|
19
19
|
* @return {Object} the raw config data.
|
|
20
20
|
*/
|
|
21
|
-
module.exports = async function readRawConfigFile(
|
|
21
|
+
module.exports = async function readRawConfigFile( configPath ) {
|
|
22
22
|
try {
|
|
23
|
-
return
|
|
24
|
-
JSON.parse( await fs.readFile( configPath, 'utf8' ) )
|
|
25
|
-
);
|
|
23
|
+
return JSON.parse( await fs.readFile( configPath, 'utf8' ) );
|
|
26
24
|
} catch ( error ) {
|
|
25
|
+
const fileName = path.basename( configPath );
|
|
26
|
+
|
|
27
27
|
if ( error.code === 'ENOENT' ) {
|
|
28
28
|
return null;
|
|
29
29
|
} else if ( error instanceof SyntaxError ) {
|
|
30
30
|
throw new ValidationError(
|
|
31
|
-
`Invalid ${
|
|
31
|
+
`Invalid ${ fileName }: ${ error.message }`
|
|
32
32
|
);
|
|
33
33
|
} else {
|
|
34
34
|
throw new ValidationError(
|
|
35
|
-
`Could not read ${
|
|
35
|
+
`Could not read ${ fileName }: ${ error.message }`
|
|
36
36
|
);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Used to maintain back compatibility with older versions of the .wp-env.json
|
|
43
|
-
* file. Returns an object in the shape of the currently expected .wp-env.json
|
|
44
|
-
* version.
|
|
45
|
-
*
|
|
46
|
-
* @param {Object} rawConfig config right after being read from a file.
|
|
47
|
-
* @return {Object} Same config with any old-format values converted into the
|
|
48
|
-
* shape of the currently expected format.
|
|
49
|
-
*/
|
|
50
|
-
function withBackCompat( rawConfig ) {
|
|
51
|
-
// Convert testsPort into new env.tests format.
|
|
52
|
-
if ( rawConfig.testsPort !== undefined ) {
|
|
53
|
-
rawConfig.env = {
|
|
54
|
-
...( rawConfig.env || {} ),
|
|
55
|
-
tests: {
|
|
56
|
-
port: rawConfig.testsPort,
|
|
57
|
-
...( rawConfig.env && rawConfig.env.tests
|
|
58
|
-
? rawConfig.env.tests
|
|
59
|
-
: {} ),
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
delete rawConfig.testsPort;
|
|
64
|
-
return rawConfig;
|
|
65
|
-
}
|