From 7556ce57adb582914cbc6e4a67ac9f6ea669fa45 Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Mon, 10 Jan 2022 13:00:43 -0500 Subject: [PATCH] feat: add isDefault method Add a new method `isDefault(key)` that enables a way to know if the value to be returned by a `config.get(key)` call is coming from the default definitions or any other different source. In case it's coming from the default values this method returns `true`, it returns `false` otherwise. This addition is going to allow for effectively managing different default values in the npm cli on a command-basis, e.g: The `save` config default value in the npm cli is `true`, so that in `npm install` and other commands that value is always going to default to true if no user config is provided. Now let's say we want to use a different value in `npm update`, for example `save=false`. This change enables us to have a conditional check to see if the `save` config value is coming from the default source, thus providing a way to use a different value instead of the default: const save = config.isDefault('save') ? false : config.get('save') Relates to: https://github.com/npm/cli/pull/4223 Relates to: https://github.com/npm/statusboard/issues/324 --- README.md | 23 +++++++++++++++++++++++ lib/index.js | 14 ++++++++++++++ test/index.js | 27 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/README.md b/README.md index fe70e46..f2f59c1 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,29 @@ Note that it's usually enough (and more efficient) to just check `config.valid`, since each data object is marked for re-evaluation on every `config.set()` operation. +### `config.isDefault(key)` + +Returns `true` if the value is coming directly from the source defined +in the default definitions, if the current value for the key config is +coming from any other source, returns `false`. + +Can be useful for avoiding or tweaking default values, e.g: + +> Given a global default definition of foo='foo' it's possible to read that +> value such as: +> +> ```js +> const save = config.get('foo') +> ``` +> +> Now in a different place of your app it's possible to avoid using the `foo` +> default value, by checking to see if the current config value is currently +> one that was defined by the default definitions: +> +> ```js +> const save = config.isDefault('foo') ? 'bar' : config.get('foo') +> ``` + ### `config.save(where)` Save the config file specified by the `where` param. Must be one of diff --git a/lib/index.js b/lib/index.js index e52f7a1..293fad2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -401,6 +401,20 @@ class Config { } } + // Returns true if the value is coming directly from the source defined + // in default definitions, if the current value for the key config is + // coming from any other different source, returns false + isDefault (key) { + const [defaultType, ...types] = [...confTypes] + const defaultData = this.data.get(defaultType).data + + return hasOwnProperty(defaultData, key) + && types.every(type => { + const typeData = this.data.get(type).data + return !hasOwnProperty(typeData, key) + }) + } + invalidHandler (k, val, type, source, where) { this.log.warn( 'invalid config', diff --git a/test/index.js b/test/index.js index 5518096..2e15caf 100644 --- a/test/index.js +++ b/test/index.js @@ -362,6 +362,33 @@ loglevel = yolo ]) t.equal(config.valid, false) logs.length = 0 + + // set a new value that defaults to cli source + config.set('cli-config', 1) + + t.ok(config.isDefault('methane'), + 'should return true if value is retrieved from default definitions') + t.notOk(config.isDefault('cli-config'), + 'should return false for a cli-defined value') + t.notOk(config.isDefault('foo'), + 'should return false for a env-defined value') + t.notOk(config.isDefault('project-config'), + 'should return false for a project-defined value') + t.notOk(config.isDefault('default-user-config-in-home'), + 'should return false for a user-defined value') + t.notOk(config.isDefault('global-config'), + 'should return false for a global-defined value') + t.notOk(config.isDefault('builtin-config'), + 'should return false for a builtin-defined value') + + // make sure isDefault still works as intended after + // setting and deleting values in differente sources + config.set('methane', 'H2O', 'cli') + t.notOk(config.isDefault('methane'), + 'should no longer return true now that a cli value was defined') + config.delete('methane', 'cli') + t.ok(config.isDefault('methane'), + 'should return true once again now that values is retrieved from defaults') }) t.test('do not double-load project/user config', async t => {