From 316547ed20bb20e42bf91bda65c4de064d00aa50 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Tue, 6 Feb 2024 13:32:45 +0300 Subject: [PATCH 1/8] feat: provide `extends` directive resolution for configs closes #977 --- packages/metro-config/package.json | 1 + .../__snapshots__/loadConfig-test.js.snap | 181 ++++++++++++++++++ .../src/__tests__/loadConfig-test.js | 34 ++++ packages/metro-config/src/loadConfig.js | 102 ++++------ yarn.lock | 5 + 5 files changed, 254 insertions(+), 69 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 93f76611ba..9c8caa0eba 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,6 +13,7 @@ }, "license": "MIT", "dependencies": { + "@topoconfig/extends": "^0.7.2", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/packages/metro-config/src/__tests__/__snapshots__/loadConfig-test.js.snap b/packages/metro-config/src/__tests__/__snapshots__/loadConfig-test.js.snap index a89a9cea08..05507c078b 100644 --- a/packages/metro-config/src/__tests__/__snapshots__/loadConfig-test.js.snap +++ b/packages/metro-config/src/__tests__/__snapshots__/loadConfig-test.js.snap @@ -543,6 +543,187 @@ Object { } `; +exports[`loadConfig can populate \`extends\` references 1`] = ` +Object { + "cacheStores": Array [], + "cacheVersion": "foo", + "maxWorkers": 2, + "projectRoot": "/", + "reporter": null, + "resetCache": false, + "resolver": Object { + "assetExts": Array [ + "bmp", + "gif", + "jpg", + "jpeg", + "png", + "psd", + "svg", + "webp", + "m4v", + "mov", + "mp4", + "mpeg", + "mpg", + "webm", + "aac", + "aiff", + "caf", + "m4a", + "mp3", + "wav", + "html", + "pdf", + "yaml", + "yml", + "otf", + "ttf", + "zip", + ], + "assetResolutions": Array [ + "1", + "1.5", + "2", + "3", + "4", + ], + "blockList": /\\(\\\\/__tests__\\\\/\\.\\*\\)\\$/, + "dependencyExtractor": undefined, + "disableHierarchicalLookup": false, + "emptyModulePath": "metro-runtime/src/modules/empty-module", + "enableGlobalPackages": false, + "extraNodeModules": Object {}, + "hasteImplModulePath": undefined, + "nodeModulesPaths": Array [], + "platforms": Array [ + "ios", + "android", + "windows", + "web", + ], + "requireCycleIgnorePatterns": Array [ + /\\(\\^\\|\\\\/\\|\\\\\\\\\\)node_modules\\(\\$\\|\\\\/\\|\\\\\\\\\\)/, + ], + "resolveRequest": null, + "resolverMainFields": Array [ + "browser", + "main", + ], + "sourceExts": Array [ + "js", + "jsx", + "json", + "ts", + "tsx", + ], + "unstable_conditionNames": Array [ + "require", + "import", + ], + "unstable_conditionsByPlatform": Object { + "web": Array [ + "browser", + ], + }, + "unstable_enablePackageExports": false, + "unstable_enableSymlinks": true, + "useWatchman": true, + }, + "serializer": Object { + "createModuleIdFactory": [Function], + "customSerializer": null, + "experimentalSerializerHook": [Function], + "getModulesRunBeforeMainModule": [Function], + "getPolyfills": [Function], + "getRunModuleStatement": [Function], + "isThirdPartyModule": [Function], + "polyfillModuleNames": Array [], + "processModuleFilter": [Function], + }, + "server": Object { + "enhanceMiddleware": [Function], + "forwardClientLogs": true, + "port": 8081, + "rewriteRequestUrl": [Function], + "unstable_serverRoot": null, + "useGlobalHotkey": true, + "verifyConnections": false, + }, + "stickyWorkers": true, + "symbolicator": Object { + "customizeFrame": [Function], + "customizeStack": [Function], + }, + "transformer": Object { + "allowOptionalDependencies": false, + "assetPlugins": Array [], + "assetRegistryPath": "missing-asset-registry-path", + "asyncRequireModulePath": "metro-runtime/src/modules/asyncRequire", + "babelTransformerPath": "metro-babel-transformer", + "dynamicDepsInPackages": "throwAtRuntime", + "enableBabelRCLookup": true, + "enableBabelRuntime": true, + "getTransformOptions": [Function], + "globalPrefix": "", + "hermesParser": false, + "minifierConfig": Object { + "compress": Object { + "reduce_funcs": false, + }, + "mangle": Object { + "toplevel": false, + }, + "output": Object { + "ascii_only": true, + "quote_style": 3, + "wrap_iife": true, + }, + "sourceMap": Object { + "includeSources": false, + }, + "toplevel": false, + }, + "minifierPath": "metro-minify-terser", + "optimizationSizeLimit": 153600, + "publicPath": "/assets", + "transformVariants": Object { + "default": Object {}, + }, + "unstable_allowRequireContext": false, + "unstable_compactOutput": false, + "unstable_dependencyMapReservedName": null, + "unstable_disableModuleWrapping": false, + "unstable_disableNormalizePseudoGlobals": false, + "unstable_workerThreads": false, + "workerPath": "metro/src/DeltaBundler/Worker", + }, + "transformerPath": "", + "unstable_perfLoggerFactory": [Function], + "watchFolders": Array [ + "/", + ], + "watcher": Object { + "additionalExts": Array [ + "cjs", + "mjs", + ], + "healthCheck": Object { + "enabled": false, + "filePrefix": ".metro-health-check", + "interval": 30000, + "timeout": 5000, + }, + "unstable_workerThreads": false, + "watchman": Object { + "deferStates": Array [ + "hg.update", + ], + }, + }, +} +`; + exports[`loadConfig injects \`metro-cache\` into the \`cacheStores\` callback 1`] = ` Object { "cacheStores": Array [], diff --git a/packages/metro-config/src/__tests__/loadConfig-test.js b/packages/metro-config/src/__tests__/loadConfig-test.js index 247913f8a7..b977a6de2c 100644 --- a/packages/metro-config/src/__tests__/loadConfig-test.js +++ b/packages/metro-config/src/__tests__/loadConfig-test.js @@ -16,6 +16,8 @@ jest.mock('cosmiconfig'); const getDefaultConfig = require('../defaults'); const {loadConfig} = require('../loadConfig'); const cosmiconfig = require('cosmiconfig'); +const fs = require('fs'); +const os = require('os'); const path = require('path'); const prettyFormat = require('pretty-format'); const stripAnsi = require('strip-ansi'); @@ -152,6 +154,38 @@ describe('loadConfig', () => { expect(cosmiconfig.hasLoadBeenCalled()).toBeTruthy(); }); + it('can populate `extends` references', async () => { + const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-')); + await fs.promises.writeFile( + path.resolve(temp, 'config.json'), + '{"extends": "./base.json"}', + 'utf8', + ); + await fs.promises.writeFile( + path.resolve(temp, 'base.json'), + '{"cacheVersion": "foo"}', + 'utf8', + ); + + const config: any = { + reporter: null, + maxWorkers: 2, + cacheStores: [], + transformerPath: '', + resolver: { + emptyModulePath: 'metro-runtime/src/modules/empty-module', + }, + extends: path.resolve(temp, 'config.json'), + }; + + cosmiconfig.setResolvedConfig(config); + + const result = await loadConfig({}); + + expect(result).toMatchSnapshot(); + expect(result.cacheVersion).toBe('foo'); + }); + it('can load the config with no config present', async () => { cosmiconfig.setReturnNull(true); diff --git a/packages/metro-config/src/loadConfig.js b/packages/metro-config/src/loadConfig.js index d2c65b0438..aa74de8adf 100644 --- a/packages/metro-config/src/loadConfig.js +++ b/packages/metro-config/src/loadConfig.js @@ -15,6 +15,7 @@ import type {ConfigT, InputConfigT, YargArguments} from './configTypes.flow'; const getDefaultConfig = require('./defaults'); const validConfig = require('./defaults/validConfig'); +const xtends = require('@topoconfig/extends'); const cosmiconfig = require('cosmiconfig'); const fs = require('fs'); const {validate} = require('jest-validate'); @@ -102,84 +103,47 @@ async function resolveConfig( return result; } +const resolveExtra = (base: any = {}, key: string, resolver) => { + const value = base[key]; + return value != null ? {[key]: resolver(value)} : {}; +}; + function mergeConfig>( defaultConfig: T, ...configs: Array ): T { // If the file is a plain object we merge the file with the default config, // for the function we don't do this since that's the responsibility of the user - return configs.reduce( - (totalConfig, nextConfig) => ({ - ...totalConfig, - ...nextConfig, - - cacheStores: - nextConfig.cacheStores != null - ? typeof nextConfig.cacheStores === 'function' - ? nextConfig.cacheStores(MetroCache) - : nextConfig.cacheStores - : totalConfig.cacheStores, - - resolver: { - ...totalConfig.resolver, - // $FlowFixMe[exponential-spread] - ...(nextConfig.resolver || {}), - dependencyExtractor: - nextConfig.resolver && nextConfig.resolver.dependencyExtractor != null - ? resolve(nextConfig.resolver.dependencyExtractor) - : // $FlowFixMe[incompatible-use] - totalConfig.resolver.dependencyExtractor, - hasteImplModulePath: - nextConfig.resolver && nextConfig.resolver.hasteImplModulePath != null - ? resolve(nextConfig.resolver.hasteImplModulePath) - : // $FlowFixMe[incompatible-use] - totalConfig.resolver.hasteImplModulePath, - }, - serializer: { - ...totalConfig.serializer, - // $FlowFixMe[exponential-spread] - ...(nextConfig.serializer || {}), - }, - transformer: { - ...totalConfig.transformer, - // $FlowFixMe[exponential-spread] - ...(nextConfig.transformer || {}), - babelTransformerPath: - nextConfig.transformer && - nextConfig.transformer.babelTransformerPath != null - ? resolve(nextConfig.transformer.babelTransformerPath) - : // $FlowFixMe[incompatible-use] - totalConfig.transformer.babelTransformerPath, - }, - server: { - ...totalConfig.server, - // $FlowFixMe[exponential-spread] - ...(nextConfig.server || {}), - }, - symbolicator: { - ...totalConfig.symbolicator, - // $FlowFixMe[exponential-spread] - ...(nextConfig.symbolicator || {}), - }, - watcher: { - ...totalConfig.watcher, - // $FlowFixMe[exponential-spread] - ...nextConfig.watcher, - watchman: { - // $FlowFixMe[exponential-spread] - ...totalConfig.watcher?.watchman, - ...nextConfig.watcher?.watchman, + return xtends.populateSync(defaultConfig, { + extends: configs.map(c => { + return { + ...c, + transformer: { + ...(c.transformer || {}), + ...resolveExtra(c.transformer, 'babelTransformerPath', resolve), }, - healthCheck: { - // $FlowFixMe[exponential-spread] - ...totalConfig.watcher?.healthCheck, - // $FlowFixMe: Spreading shapes creates an explosion of union types - ...nextConfig.watcher?.healthCheck, + resolver: { + ...(c.resolver || {}), + ...resolveExtra(c.resolver, 'dependencyExtractor', resolve), + ...resolveExtra(c.resolver, 'hasteImplModulePath', resolve), }, - }, + ...resolveExtra(c, 'cacheStores', stores => { + return typeof stores === 'function' ? stores(MetroCache) : stores; + }), + }; }), - defaultConfig, - ); + rules: { + '*': 'override', + resolver: 'merge', + serializer: 'merge', + server: 'merge', + symbolicator: 'merge', + transformer: 'merge', + watcher: 'merge', + 'watcher.watchman': 'merge', + 'watcher.healthCheck': 'merge', + }, + }); } async function loadMetroConfigFromDisk( diff --git a/yarn.lock b/yarn.lock index 123800e909..992b25e003 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,6 +1726,11 @@ dependencies: "@sinonjs/commons" "^3.0.0" +"@topoconfig/extends@^0.7.2": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.7.2.tgz#a58772603b0c791da535d6183c45b3225dc85948" + integrity sha512-UNa+GsWOL3dlQdeqYaglM6Pr8sbMYSQIw+hvchik/149EbIYj5dLaM11j4fsu/O1fSokDz/4GANYB8XT7urKag== + "@tsconfig/node18@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-1.0.1.tgz#ea5b375a9ead6b09ccbd70c3894ea069829ea1bb" From 03fd87bf78273c7eb7e34b88fe887f1f38b894f1 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Tue, 6 Feb 2024 17:24:44 +0300 Subject: [PATCH 2/8] fix(config): add hook for mergeConfig to pass cwd for internal `extends` processor --- packages/metro-config/src/loadConfig.js | 50 ++++++++++++++++++------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/packages/metro-config/src/loadConfig.js b/packages/metro-config/src/loadConfig.js index aa74de8adf..e96285651a 100644 --- a/packages/metro-config/src/loadConfig.js +++ b/packages/metro-config/src/loadConfig.js @@ -103,7 +103,7 @@ async function resolveConfig( return result; } -const resolveExtra = (base: any = {}, key: string, resolver) => { +const resolveExtra = (base: any = {}, key: string, resolver: Function) => { const value = base[key]; return value != null ? {[key]: resolver(value)} : {}; }; @@ -115,17 +115,25 @@ function mergeConfig>( // If the file is a plain object we merge the file with the default config, // for the function we don't do this since that's the responsibility of the user return xtends.populateSync(defaultConfig, { + // $FlowFixMe[prop-missing] + cwd: mergeConfig.cwd, extends: configs.map(c => { return { ...c, transformer: { ...(c.transformer || {}), - ...resolveExtra(c.transformer, 'babelTransformerPath', resolve), + ...(resolveExtra(c.transformer, 'babelTransformerPath', resolve): { + babelTransformerPath?: string, + }), }, resolver: { ...(c.resolver || {}), - ...resolveExtra(c.resolver, 'dependencyExtractor', resolve), - ...resolveExtra(c.resolver, 'hasteImplModulePath', resolve), + ...(resolveExtra(c.resolver, 'dependencyExtractor', resolve): { + dependencyExtractor?: string, + }), + ...(resolveExtra(c.resolver, 'hasteImplModulePath', resolve): { + hasteImplModulePath?: string, + }), }, ...resolveExtra(c, 'cacheStores', stores => { return typeof stores === 'function' ? stores(MetroCache) : stores; @@ -146,6 +154,24 @@ function mergeConfig>( }); } +// mergeConfig is public, we should try to keep its API stable +// This trick is necessary to pass proper cwd to `populateSync` +const mergeConfigHooked = >( + cwd: string, + base: T, + extra: ConfigT | InputConfigT, +): T => { + // $FlowFixMe[prop-missing] + mergeConfig.cwd = cwd; + + // $FlowFixMe[incompatible-variance] + // $FlowFixMe[incompatible-call] + const config = mergeConfig(base, extra); + // $FlowFixMe[prop-missing] + mergeConfig.cwd = undefined; + return config; +}; + async function loadMetroConfigFromDisk( path?: string, cwd?: string, @@ -160,23 +186,21 @@ async function loadMetroConfigFromDisk( const rootPath = dirname(filepath); const defaults = await getDefaultConfig(rootPath); - // $FlowFixMe[incompatible-variance] - // $FlowFixMe[incompatible-call] - const defaultConfig: ConfigT = mergeConfig(defaults, defaultConfigOverrides); + const defaultConfig: ConfigT = mergeConfigHooked( + rootPath, + defaults, + defaultConfigOverrides, + ); if (typeof configModule === 'function') { // Get a default configuration based on what we know, which we in turn can pass // to the function. const resultedConfig = await configModule(defaultConfig); - // $FlowFixMe[incompatible-call] - // $FlowFixMe[incompatible-variance] - return mergeConfig(defaultConfig, resultedConfig); + return mergeConfigHooked(rootPath, defaultConfig, resultedConfig); } - // $FlowFixMe[incompatible-variance] - // $FlowFixMe[incompatible-call] - return mergeConfig(defaultConfig, configModule); + return mergeConfigHooked(rootPath, defaultConfig, configModule); } function overrideConfigWithArguments( From bc5941dcb565d4b14d89e743ef9bbc70c4f3db75 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Tue, 6 Feb 2024 20:39:48 +0300 Subject: [PATCH 3/8] chore(config): rename mergeConfigHooked to mergeConfigWithCwd --- packages/metro-config/src/loadConfig.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/metro-config/src/loadConfig.js b/packages/metro-config/src/loadConfig.js index e96285651a..08e6a2c0f8 100644 --- a/packages/metro-config/src/loadConfig.js +++ b/packages/metro-config/src/loadConfig.js @@ -154,9 +154,9 @@ function mergeConfig>( }); } -// mergeConfig is public, we should try to keep its API stable -// This trick is necessary to pass proper cwd to `populateSync` -const mergeConfigHooked = >( +// `mergeConfig` is public, so we should try to keep its API stable +// This trick is necessary to pass the proper cwd to the internal `populateSync` call +const mergeConfigWithCwd = >( cwd: string, base: T, extra: ConfigT | InputConfigT, @@ -186,7 +186,7 @@ async function loadMetroConfigFromDisk( const rootPath = dirname(filepath); const defaults = await getDefaultConfig(rootPath); - const defaultConfig: ConfigT = mergeConfigHooked( + const defaultConfig: ConfigT = mergeConfigWithCwd( rootPath, defaults, defaultConfigOverrides, @@ -197,10 +197,10 @@ async function loadMetroConfigFromDisk( // to the function. const resultedConfig = await configModule(defaultConfig); - return mergeConfigHooked(rootPath, defaultConfig, resultedConfig); + return mergeConfigWithCwd(rootPath, defaultConfig, resultedConfig); } - return mergeConfigHooked(rootPath, defaultConfig, configModule); + return mergeConfigWithCwd(rootPath, defaultConfig, configModule); } function overrideConfigWithArguments( From 6b4e1c4e08002c6c4838526a2f007d75ee11c526 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Wed, 7 Feb 2024 13:17:03 +0300 Subject: [PATCH 4/8] chore(config): update @topoconfig/extends to v0.7.3 to handle bom issues --- packages/metro-config/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 9c8caa0eba..f7a1617a6a 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,7 +13,7 @@ }, "license": "MIT", "dependencies": { - "@topoconfig/extends": "^0.7.2", + "@topoconfig/extends": "^0.7.3", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/yarn.lock b/yarn.lock index 6fb9393048..b1617e581f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,10 +1726,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@topoconfig/extends@^0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.7.2.tgz#a58772603b0c791da535d6183c45b3225dc85948" - integrity sha512-UNa+GsWOL3dlQdeqYaglM6Pr8sbMYSQIw+hvchik/149EbIYj5dLaM11j4fsu/O1fSokDz/4GANYB8XT7urKag== +"@topoconfig/extends@^0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.7.3.tgz#5572fbcb00ff74d7479b0c8f2b510aff18c12838" + integrity sha512-DXuLBtnF6Yf8ifPMa0n6LWbvdAX3kJnJM3mDOEvvuJAqMNzak4K1YnXYXEFeGOFLwHazqKYQuF1hL4ObXAZrQw== "@tsconfig/node18@1.0.1": version "1.0.1" From 37e69b26586d855ce68c49dc9d0b82a5f8b70797 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Sat, 10 Feb 2024 09:56:06 +0300 Subject: [PATCH 5/8] fix(config): update @topoconfig/extends to 0.8.0 to fix import path resolution on windows --- packages/metro-config/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index f7a1617a6a..c215a13749 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,7 +13,7 @@ }, "license": "MIT", "dependencies": { - "@topoconfig/extends": "^0.7.3", + "@topoconfig/extends": "^0.8.0", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/yarn.lock b/yarn.lock index 300e1871be..9099aa8d47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,10 +1726,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@topoconfig/extends@^0.7.3": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.7.3.tgz#5572fbcb00ff74d7479b0c8f2b510aff18c12838" - integrity sha512-DXuLBtnF6Yf8ifPMa0n6LWbvdAX3kJnJM3mDOEvvuJAqMNzak4K1YnXYXEFeGOFLwHazqKYQuF1hL4ObXAZrQw== +"@topoconfig/extends@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.8.0.tgz#961bba0ac61c7fe8b6ded9d0a7f8d2d051c37ca9" + integrity sha512-sCvlrrvhbe2M6nTwF6htc4TG0DbE5gl1zrDn3+yKShTiopHAZF4uzGlIzQYq4EofMVgX3kGJIquIMwfryobc8g== "@tsconfig/node18@1.0.1": version "1.0.1" From c97ceb715dc0e7884c243fc5752fd5940010c825 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Sat, 10 Feb 2024 10:53:30 +0300 Subject: [PATCH 6/8] fix(config): update @topoconfig/extends to 0.9.0 to accept file urls as extends input --- packages/metro-config/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index c215a13749..1ab8db8188 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,7 +13,7 @@ }, "license": "MIT", "dependencies": { - "@topoconfig/extends": "^0.8.0", + "@topoconfig/extends": "^0.9.0", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/yarn.lock b/yarn.lock index 9099aa8d47..921ed813a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,10 +1726,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@topoconfig/extends@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.8.0.tgz#961bba0ac61c7fe8b6ded9d0a7f8d2d051c37ca9" - integrity sha512-sCvlrrvhbe2M6nTwF6htc4TG0DbE5gl1zrDn3+yKShTiopHAZF4uzGlIzQYq4EofMVgX3kGJIquIMwfryobc8g== +"@topoconfig/extends@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.9.0.tgz#db57aec72c91d24d3bd8bd731540953f6cc99fed" + integrity sha512-7BZwZ7t1zdUlZSHtBaDggqkrxpWDp+Wixk4LS90wxbp095Y39Jh3Rhl8Te+j8W60L83hA+RdWy1iE/qRs+H0kA== "@tsconfig/node18@1.0.1": version "1.0.1" From 4ff0c113ac3f7a3ac0cce3cdf8ae874b0f4e6e03 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Sat, 10 Feb 2024 23:07:57 +0300 Subject: [PATCH 7/8] fix: update @topoconfig/extends to v0.11.0 to handle merge precedence --- packages/metro-config/package.json | 2 +- packages/metro-config/src/loadConfig.js | 38 +++++++++++++++---------- yarn.lock | 8 +++--- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 1ab8db8188..81592671ba 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,7 +13,7 @@ }, "license": "MIT", "dependencies": { - "@topoconfig/extends": "^0.9.0", + "@topoconfig/extends": "^0.11.0", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/packages/metro-config/src/loadConfig.js b/packages/metro-config/src/loadConfig.js index 08e6a2c0f8..79667e0f2e 100644 --- a/packages/metro-config/src/loadConfig.js +++ b/packages/metro-config/src/loadConfig.js @@ -114,10 +114,9 @@ function mergeConfig>( ): T { // If the file is a plain object we merge the file with the default config, // for the function we don't do this since that's the responsibility of the user - return xtends.populateSync(defaultConfig, { - // $FlowFixMe[prop-missing] - cwd: mergeConfig.cwd, - extends: configs.map(c => { + const extras = [ + defaultConfig, + ...configs.map(c => { return { ...c, transformer: { @@ -140,18 +139,27 @@ function mergeConfig>( }), }; }), - rules: { - '*': 'override', - resolver: 'merge', - serializer: 'merge', - server: 'merge', - symbolicator: 'merge', - transformer: 'merge', - watcher: 'merge', - 'watcher.watchman': 'merge', - 'watcher.healthCheck': 'merge', + ]; + + return xtends.populateSync( + {}, + { + // $FlowFixMe[prop-missing] + cwd: mergeConfig.cwd, + extends: extras, + rules: { + '*': 'override', + resolver: 'merge', + serializer: 'merge', + server: 'merge', + symbolicator: 'merge', + transformer: 'merge', + watcher: 'merge', + 'watcher.watchman': 'merge', + 'watcher.healthCheck': 'merge', + }, }, - }); + ); } // `mergeConfig` is public, so we should try to keep its API stable diff --git a/yarn.lock b/yarn.lock index 921ed813a1..27ce2d90ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,10 +1726,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@topoconfig/extends@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.9.0.tgz#db57aec72c91d24d3bd8bd731540953f6cc99fed" - integrity sha512-7BZwZ7t1zdUlZSHtBaDggqkrxpWDp+Wixk4LS90wxbp095Y39Jh3Rhl8Te+j8W60L83hA+RdWy1iE/qRs+H0kA== +"@topoconfig/extends@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.11.0.tgz#c24014ed408ec817d6b7e7eabfb02d6bae3a3982" + integrity sha512-l7dX7ofnymgVt5y98whD0XQcr4JeNaU8cCDAI2yFtQ3FHEPW20e5SLJR3LizB0nCKDMhIuEEB8Q6ko7jPavc1A== "@tsconfig/node18@1.0.1": version "1.0.1" From f987e107f3c65ee5e35e8de922471287e0411d09 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Mon, 12 Feb 2024 11:21:30 +0300 Subject: [PATCH 8/8] fix: update @topoconfig/extends to v0.12.0 to follow nested `extends` of external (shared) configs --- packages/metro-config/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index 81592671ba..e1267be5b9 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -13,7 +13,7 @@ }, "license": "MIT", "dependencies": { - "@topoconfig/extends": "^0.11.0", + "@topoconfig/extends": "^0.12.0", "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", diff --git a/yarn.lock b/yarn.lock index 27ce2d90ec..345c7d6703 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,10 +1726,10 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@topoconfig/extends@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.11.0.tgz#c24014ed408ec817d6b7e7eabfb02d6bae3a3982" - integrity sha512-l7dX7ofnymgVt5y98whD0XQcr4JeNaU8cCDAI2yFtQ3FHEPW20e5SLJR3LizB0nCKDMhIuEEB8Q6ko7jPavc1A== +"@topoconfig/extends@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@topoconfig/extends/-/extends-0.12.0.tgz#82ed9196df8477f95b7822a77f53efcc8b765d00" + integrity sha512-+6NJxJsvUtJADzrp9h5O19Cqvw1xob4ZhQstNeQIr+hvkPn8zkI65vT3CvtaqsJQ3VDnVvzy+UOkqZ0zO6/viw== "@tsconfig/node18@1.0.1": version "1.0.1"