From f5e17d425a6fe2b7cfa06369fe81a189a5cfc3d2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Czekajski Date: Thu, 12 Jun 2025 21:55:02 +0900 Subject: [PATCH] feat: support optional env var replacements in .npmrc --- docs/lib/content/configuring-npm/npmrc.md | 5 ++++- workspaces/config/lib/env-replace.js | 8 +++++--- workspaces/config/test/env-replace.js | 6 ++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index cd31ae886f132..b0ee60bcb9686 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -25,11 +25,14 @@ The four relevant files are: * npm builtin config file (`/path/to/npm/npmrc`) All npm config files are an ini-formatted list of `key = value` parameters. -Environment variables can be replaced using `${VARIABLE_NAME}`. For +Environment variables can be replaced using `${VARIABLE_NAME}`. By default +if the variable is not defined, it is left unreplaced. By adding `?` after +variable name they can be forced to evaluate to an empty string instead.For example: ```bash cache = ${HOME}/.npm-packages +node-options = "${NODE_OPTIONS?} --use-system-ca" ``` Each of these files is loaded, and config options are resolved in priority diff --git a/workspaces/config/lib/env-replace.js b/workspaces/config/lib/env-replace.js index c851f6e4d1501..30dbbeefc45ad 100644 --- a/workspaces/config/lib/env-replace.js +++ b/workspaces/config/lib/env-replace.js @@ -1,9 +1,11 @@ // replace any ${ENV} values with the appropriate environ. +// optional "?" modifier can be used like this: ${ENV?} so in case of the variable being not defined, it evaluates into empty string -const envExpr = /(? f.replace(envExpr, (orig, esc, name) => { - const val = env[name] !== undefined ? env[name] : `$\{${name}}` +module.exports = (f, env) => f.replace(envExpr, (orig, esc, name, modifier) => { + const fallback = modifier === '?' ? '' : `$\{${name}}` + const val = env[name] !== undefined ? env[name] : fallback // consume the escape chars that are relevant. if (esc.length % 2) { diff --git a/workspaces/config/test/env-replace.js b/workspaces/config/test/env-replace.js index c2b570364de87..ed27238b5887f 100644 --- a/workspaces/config/test/env-replace.js +++ b/workspaces/config/test/env-replace.js @@ -8,6 +8,12 @@ const env = { t.equal(envReplace('\\${foo}', env), '${foo}') t.equal(envReplace('\\\\${foo}', env), '\\bar') +t.equal(envReplace('\\\\\\${foo}', env), '\\${foo}') t.equal(envReplace('${baz}', env), '${baz}') t.equal(envReplace('\\${baz}', env), '${baz}') t.equal(envReplace('\\\\${baz}', env), '\\${baz}') +t.equal(envReplace('\\${foo?}', env), '${foo?}') +t.equal(envReplace('\\\\${foo?}', env), '\\bar') +t.equal(envReplace('${baz?}', env), '') +t.equal(envReplace('\\${baz?}', env), '${baz?}') +t.equal(envReplace('\\\\${baz?}', env), '\\')