From 46b6f866f4272fbea7e668fd28272452cd9903a2 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:37:27 +0100 Subject: [PATCH 1/4] chore: drop map-obj Drops the map-obj dependency and uses a basic `Object.entries` map instead. --- packages/build/src/core/config.js | 3 +- packages/build/src/core/constants.ts | 5 ++-- packages/build/src/env/changes.js | 5 ++-- packages/build/src/error/api.js | 5 ++-- packages/build/src/plugins/child/status.js | 5 ++-- .../src/plugins_core/frameworks_api/util.ts | 29 ++++++++++--------- .../build/src/plugins_core/functions/zisi.ts | 11 +++---- 7 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/build/src/core/config.js b/packages/build/src/core/config.js index 87e186d8fe..d364442ae2 100644 --- a/packages/build/src/core/config.js +++ b/packages/build/src/core/config.js @@ -1,5 +1,4 @@ import { resolveConfig, restoreConfig, updateConfig } from '@netlify/config' -import mapObj from 'map-obj' import { getChildEnv } from '../env/main.js' import { addApiErrorHandlers } from '../error/api.js' @@ -95,7 +94,7 @@ const tLoadConfig = async function ({ } const apiA = addApiErrorHandlers(api) - const envValues = mapObj(env, (key, { value }) => [key, value]) + const envValues = Object.fromEntries(Object.entries(env).map(([key, { value }]) => [key, value])) const childEnv = getChildEnv({ envOpt, env: envValues }) const [{ packageJson }, userNodeVersion] = await Promise.all([getPackageJson(buildDir), getUserNodeVersion(nodePath)]) return { diff --git a/packages/build/src/core/constants.ts b/packages/build/src/core/constants.ts index d05bbef0d7..1cf29871d0 100644 --- a/packages/build/src/core/constants.ts +++ b/packages/build/src/core/constants.ts @@ -1,7 +1,6 @@ import { relative, normalize, join } from 'path' import { getCacheDir } from '@netlify/cache-utils' -import mapObj from 'map-obj' import { pathExists } from 'path-exists' import { ROOT_PACKAGE_JSON } from '../utils/json.js' @@ -201,7 +200,9 @@ const addDefaultConstant = async function ({ constants, constantName, defaultPat } const normalizeConstantsPaths = function (constants: Partial, buildDir: string) { - return mapObj(constants, (key, path: string) => [key, normalizePath(path, buildDir, key)]) + return Object.fromEntries( + Object.entries(constants).map(([key, path]) => [key, normalizePath(String(path), buildDir, key)]), + ) } // The current directory is `buildDir`. Most constants are inside this `buildDir`. diff --git a/packages/build/src/env/changes.js b/packages/build/src/env/changes.js index 819922c84c..9f7217bb69 100644 --- a/packages/build/src/env/changes.js +++ b/packages/build/src/env/changes.js @@ -1,7 +1,6 @@ import { env } from 'process' import { includeKeys } from 'filter-obj' -import mapObj from 'map-obj' // If plugins modify `process.env`, this is propagated in other plugins and in // `build.command`. Since those are different processes, we figure out when they @@ -15,7 +14,7 @@ export const getNewEnvChanges = function (envBefore, netlifyConfig, netlifyConfi const diffEnv = function (envBefore, envAfter) { const envChanges = includeKeys(envAfter, (name, value) => value !== envBefore[name]) const deletedEnv = includeKeys(envBefore, (name) => envAfter[name] === undefined) - const deletedEnvA = mapObj(deletedEnv, setToNull) + const deletedEnvA = Object.fromEntries(Object.entries(deletedEnv).map(setToNull)) return { ...envChanges, ...deletedEnvA } } @@ -23,7 +22,7 @@ const diffEnv = function (envBefore, envAfter) { // convert it to `null` // Note: `process.env[name] = undefined` actually does // `process.env[name] = 'undefined'` in Node.js. -const setToNull = function (name) { +const setToNull = function ([name]) { return [name, null] } diff --git a/packages/build/src/error/api.js b/packages/build/src/error/api.js index 2df5af43cc..9912732221 100644 --- a/packages/build/src/error/api.js +++ b/packages/build/src/error/api.js @@ -1,5 +1,4 @@ import isPlainObj from 'is-plain-obj' -import mapObj from 'map-obj' import { addErrorInfo } from './info.js' @@ -9,10 +8,10 @@ export const addApiErrorHandlers = function (api) { return } - return mapObj(api, addErrorHandler) + return Object.fromEntries(Object.entries(api).map(addErrorHandler)) } -const addErrorHandler = function (key, value) { +const addErrorHandler = function ([key, value]) { if (typeof value !== 'function') { return [key, value] } diff --git a/packages/build/src/plugins/child/status.js b/packages/build/src/plugins/child/status.js index 5fcc142951..bf3d5764cb 100644 --- a/packages/build/src/plugins/child/status.js +++ b/packages/build/src/plugins/child/status.js @@ -1,5 +1,4 @@ import isPlainObj from 'is-plain-obj' -import mapObj from 'map-obj' import { addErrorInfo } from '../../error/info.js' @@ -62,10 +61,10 @@ const validateShowArgsExtraData = function (extraData) { } const removeEmptyStrings = function (showArgs) { - return mapObj(showArgs, removeEmptyString) + return Object.fromEntries(Object.entries(showArgs).map(removeEmptyString)) } -const removeEmptyString = function (key, value) { +const removeEmptyString = function ([key, value]) { if (typeof value === 'string' && value.trim() === '') { return [key] } diff --git a/packages/build/src/plugins_core/frameworks_api/util.ts b/packages/build/src/plugins_core/frameworks_api/util.ts index 27fb58d0d7..ab82ee3411 100644 --- a/packages/build/src/plugins_core/frameworks_api/util.ts +++ b/packages/build/src/plugins_core/frameworks_api/util.ts @@ -2,7 +2,6 @@ import { promises as fs } from 'fs' import { resolve } from 'path' import isPlainObject from 'is-plain-obj' -import mapObject, { mapObjectSkip } from 'map-obj' import type { NetlifyConfig } from '../../index.js' import { FRAMEWORKS_API_CONFIG_ENDPOINT } from '../../utils/frameworks_api.js' @@ -67,20 +66,24 @@ export const filterConfig = ( allowedProperties: string[][], systemLog: SystemLogger, ): Record => - mapObject(obj, (key, value) => { - const keyPath = [...path, key] + Object.fromEntries( + Object.entries(obj) + .map(([key, value]): [string, unknown] | null => { + const keyPath = [...path, key] - if (!isAllowedProperty(keyPath, allowedProperties)) { - systemLog(`Discarding property that is not supported by the Deploy Configuration API: ${keyPath.join('.')}`) + if (!isAllowedProperty(keyPath, allowedProperties)) { + systemLog(`Discarding property that is not supported by the Deploy Configuration API: ${keyPath.join('.')}`) - return mapObjectSkip - } + return null + } - if (!isPlainObject(value)) { - systemLog(`Loading property from Deploy Configuration API: ${keyPath.join('.')}`) + if (!isPlainObject(value)) { + systemLog(`Loading property from Deploy Configuration API: ${keyPath.join('.')}`) - return [key, value] - } + return [key, value] + } - return [key, filterConfig(value, keyPath, allowedProperties, systemLog)] - }) + return [key, filterConfig(value, keyPath, allowedProperties, systemLog)] + }) + .filter((pair) => pair !== null), + ) diff --git a/packages/build/src/plugins_core/functions/zisi.ts b/packages/build/src/plugins_core/functions/zisi.ts index 8fee5a8a7a..9d4f401e2a 100644 --- a/packages/build/src/plugins_core/functions/zisi.ts +++ b/packages/build/src/plugins_core/functions/zisi.ts @@ -1,7 +1,6 @@ import { join, resolve } from 'path' import { type FunctionConfig, type ZipFunctionsOptions } from '@netlify/zip-it-and-ship-it' -import mapObject from 'map-obj' import semver from 'semver' import type { FeatureFlags } from '../../core/feature_flags.js' @@ -55,10 +54,12 @@ export const getZisiParameters = ({ }: GetZisiParametersType): ZipFunctionsOptions => { const nodeVersion = getLambdaNodeVersion(childEnv, userNodeVersion) const manifest = join(functionsDist, 'manifest.json') - const config = mapObject(functionsConfig, (expression, object) => [ - expression, - normalizeFunctionConfig({ buildDir, functionConfig: object, isRunningLocally, nodeVersion }), - ]) + const config = Object.fromEntries( + Object.entries(functionsConfig).map(([expression, object]) => [ + expression, + normalizeFunctionConfig({ buildDir, functionConfig: object, isRunningLocally, nodeVersion }), + ]), + ) const zisiFeatureFlags = getZisiFeatureFlags(featureFlags) // Only the legacy internal functions directory is allowed to have a JSON From 47bead2934ee2779b4ad06808926a6f2c02a43f6 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:50:09 +0100 Subject: [PATCH 2/4] fix: handle undefined paths --- packages/build/src/core/constants.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/build/src/core/constants.ts b/packages/build/src/core/constants.ts index 1cf29871d0..4e038bd359 100644 --- a/packages/build/src/core/constants.ts +++ b/packages/build/src/core/constants.ts @@ -200,16 +200,14 @@ const addDefaultConstant = async function ({ constants, constantName, defaultPat } const normalizeConstantsPaths = function (constants: Partial, buildDir: string) { - return Object.fromEntries( - Object.entries(constants).map(([key, path]) => [key, normalizePath(String(path), buildDir, key)]), - ) + return Object.fromEntries(Object.entries(constants).map(([key, path]) => [key, normalizePath(path, buildDir, key)])) } // The current directory is `buildDir`. Most constants are inside this `buildDir`. // Instead of passing absolute paths, we pass paths relative to `buildDir`, so // that logs are less verbose. -const normalizePath = function (path: string | undefined, buildDir: string, key: string) { - if (path === undefined || path === '' || !CONSTANT_PATHS.has(key)) { +const normalizePath = function (path: string | undefined | boolean, buildDir: string, key: string) { + if (typeof path !== 'string' || path === '' || !CONSTANT_PATHS.has(key)) { return path } From 8adad3a30c27ef04adb6844026171ea8507ecb6e Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Thu, 31 Jul 2025 09:13:54 +0100 Subject: [PATCH 3/4] chore: drop map-obj --- package-lock.json | 1 - packages/build/package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89f239a60f..753e5fd01d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23900,7 +23900,6 @@ "keep-func-props": "^6.0.0", "locate-path": "^7.0.0", "log-process-errors": "^11.0.0", - "map-obj": "^5.0.0", "memoize-one": "^6.0.0", "minimatch": "^9.0.4", "os-name": "^6.0.0", diff --git a/packages/build/package.json b/packages/build/package.json index 465dabdf95..72278869ce 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -91,7 +91,6 @@ "keep-func-props": "^6.0.0", "locate-path": "^7.0.0", "log-process-errors": "^11.0.0", - "map-obj": "^5.0.0", "memoize-one": "^6.0.0", "minimatch": "^9.0.4", "os-name": "^6.0.0", From 51f869cc0dcedfbe5ce929184955f81aa58cd3a3 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Fri, 1 Aug 2025 11:28:04 +0100 Subject: [PATCH 4/4] chore: split filter and map into two functions --- .../build/src/plugins_core/frameworks_api/util.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/build/src/plugins_core/frameworks_api/util.ts b/packages/build/src/plugins_core/frameworks_api/util.ts index ab82ee3411..860c5d7a7d 100644 --- a/packages/build/src/plugins_core/frameworks_api/util.ts +++ b/packages/build/src/plugins_core/frameworks_api/util.ts @@ -68,15 +68,20 @@ export const filterConfig = ( ): Record => Object.fromEntries( Object.entries(obj) - .map(([key, value]): [string, unknown] | null => { + .filter(([key]) => { const keyPath = [...path, key] if (!isAllowedProperty(keyPath, allowedProperties)) { systemLog(`Discarding property that is not supported by the Deploy Configuration API: ${keyPath.join('.')}`) - return null + return false } + return true + }) + .map(([key, value]) => { + const keyPath = [...path, key] + if (!isPlainObject(value)) { systemLog(`Loading property from Deploy Configuration API: ${keyPath.join('.')}`) @@ -84,6 +89,5 @@ export const filterConfig = ( } return [key, filterConfig(value, keyPath, allowedProperties, systemLog)] - }) - .filter((pair) => pair !== null), + }), )