@npmcli/config
Advanced tools
Comparing version 0.0.0 to 1.0.0
@@ -94,6 +94,4 @@ // TODO: set the scope config from package.json or explicit cli config | ||
this.shorthands = shorthands | ||
this.defaults = defaults | ||
this.log = log | ||
this.argv = argv | ||
@@ -114,8 +112,7 @@ this.env = env | ||
const wheres = [...confTypes] | ||
this.data = new Map(wheres.map(type => [type, { | ||
data: Object.create(null), | ||
source: null, | ||
loadError: null, | ||
raw: null, | ||
}])) | ||
this.data = new Map() | ||
let parent = null | ||
for (const where of wheres) { | ||
this.data.set(where, parent = new ConfigData(parent)) | ||
} | ||
@@ -129,8 +126,2 @@ this.data.set = () => { | ||
for (let i = 1; i < wheres.length; i++) { | ||
const { data } = this.data.get(wheres[i]) | ||
const { data: parent } = this.data.get(wheres[i - 1]) | ||
Object.setPrototypeOf(data, parent) | ||
} | ||
this.sources = new Map([]) | ||
@@ -323,3 +314,4 @@ | ||
loadCLI () { | ||
nopt.invalidHandler = (k, val, type) => this.invalidHandler(k, val, type) | ||
nopt.invalidHandler = (k, val, type) => | ||
this.invalidHandler(k, val, type, 'cli options') | ||
const conf = nopt(this.types, this.shorthands, this.argv) | ||
@@ -333,3 +325,2 @@ nopt.invalidHandler = null | ||
validate () { | ||
nopt.invalidHandler = (k, val, type) => this.invalidHandler(k, val, type) | ||
for (const [where, obj] of this.data.entries()) { | ||
@@ -341,2 +332,5 @@ // no need to validate our defaults, we know they're fine | ||
nopt.invalidHandler = (k, val, type) => | ||
this.invalidHandler(k, val, type, this.data.get(where).source) | ||
nopt.clean(obj.data, this.types, this.typeDefs) | ||
@@ -347,4 +341,8 @@ } | ||
invalidHandler (k, val, type) { | ||
this.log.warn('invalid config', k + '=' + JSON.stringify(val)) | ||
invalidHandler (k, val, type, source) { | ||
this.log.warn( | ||
'invalid config', | ||
k + '=' + JSON.stringify(val), | ||
`set in ${source}` | ||
) | ||
@@ -399,3 +397,2 @@ if (Array.isArray(type)) { | ||
// XXX: move out of class | ||
// Parse a field, coercing it to the best type available. | ||
@@ -478,4 +475,4 @@ parseField (f, key, listElement = false) { | ||
const conf = this.data.get(where) | ||
conf.raw = { ...conf.data } | ||
conf.loadError = null | ||
conf[_raw] = { ...conf.data } | ||
conf[_loadError] = null | ||
const iniData = ini.stringify(conf.data) | ||
@@ -670,2 +667,40 @@ if (!iniData.trim()) { | ||
const _data = Symbol('data') | ||
const _raw = Symbol('raw') | ||
const _loadError = Symbol('loadError') | ||
const _source = Symbol('source') | ||
class ConfigData { | ||
constructor (parent) { | ||
this[_data] = Object.create(parent && parent.data) | ||
this[_source] = null | ||
this[_loadError] = null | ||
this[_raw] = null | ||
} | ||
get data () { | ||
return this[_data] | ||
} | ||
set source (s) { | ||
if (this[_source]) | ||
throw new Error('cannot set ConfigData source more than once') | ||
this[_source] = s | ||
} | ||
get source () { return this[_source] } | ||
set loadError (e) { | ||
if (this[_loadError] || this[_raw]) | ||
throw new Error('cannot set ConfigData loadError after load') | ||
this[_loadError] = e | ||
} | ||
get loadError () { return this[_loadError] } | ||
set raw (r) { | ||
if (this[_raw] || this[_loadError]) | ||
throw new Error('cannot set ConfigData raw after load') | ||
this[_raw] = r | ||
} | ||
get raw () { return this[_raw] } | ||
} | ||
module.exports = Config |
{ | ||
"name": "@npmcli/config", | ||
"version": "0.0.0", | ||
"version": "1.0.0", | ||
"files": [ | ||
@@ -5,0 +5,0 @@ "lib" |
153
README.md
@@ -11,3 +11,3 @@ # `@npmcli/config` | ||
importantly, does _not_ define all the configuration defaults or types, as | ||
those parts make more sense to live within npm itself. | ||
those parts make more sense to live within the npm CLI itself. | ||
@@ -33,11 +33,22 @@ The only exceptions: | ||
- CLI switches. eg `--some-key=some-value` on the command line. | ||
- CLI switches. eg `--some-key=some-value` on the command line. These are | ||
parsed by [`nopt`](http://npm.im/nopt), which is not a great choice, but | ||
it's the one that npm has used forever, and changing it will be | ||
difficult. | ||
- Environment variables. eg `npm_config_some_key=some_value` in the | ||
environment. | ||
- INI-formatted project configs. eg `some-key = some-value` in `./.npmrc` | ||
- INI-formatted userconfig file. eg `some-key = some-value` in `~/.npmrc` | ||
environment. There is no way at this time to modify this prefix. | ||
- INI-formatted project configs. eg `some-key = some-value` in the | ||
`localPrefix` folder (ie, the `cwd`, or its nearest parent that contains | ||
either a `node_modules` folder or `package.json` file.) | ||
- INI-formatted userconfig file. eg `some-key = some-value` in `~/.npmrc`. | ||
The `userconfig` config value can be overridden by the `cli`, `env`, or | ||
`project` configs to change this value. | ||
- INI-formatted globalconfig file. eg `some-key = some-value` in | ||
`/usr/local/etc/npmrc` | ||
the `globalPrefix` folder, which is inferred by looking at the location | ||
of the node executable, or the `prefix` setting in the `cli`, `env`, | ||
`project`, or `userconfig`. The `globalconfig` value at any of those | ||
levels can override this. | ||
- INI-formatted builtin config file. eg `some-key = some-value` in | ||
`/usr/local/lib/node_modules/npm/npmrc`. | ||
`/usr/local/lib/node_modules/npm/npmrc`. This is not configurable, and | ||
is determined by looking in the `npmPath` folder. | ||
- Default values (passed in by npm when it loads this module). | ||
@@ -51,13 +62,11 @@ | ||
const types = require('./config/types.js') | ||
// nopt type config definitions | ||
const typeDefs = require('./config/type-defs.js') | ||
// default values for all the configs we know about | ||
const defaults = require('./config/defaults.js') | ||
// if you want -c to be short for --call, define it here | ||
// if you want -c to be short for --call and so on, define it here | ||
const shorthands = require('./config/shorthands.js') | ||
const conf = new Config({ | ||
// path to the npm module being run | ||
npmPath: resolve(__dirname, '..'), | ||
types, | ||
typeDefs, | ||
shorthands, | ||
@@ -76,5 +85,8 @@ defaults, | ||
// optional, defaults to emitting 'log' events on process object | ||
// only silly, verbose, warn, and error are logged by this module | ||
log: require('npmlog') | ||
}) | ||
// returns a promise that fails if config loading fails, and | ||
// resolves when the config object is ready for action | ||
conf.load().then(() => { | ||
@@ -86,1 +98,120 @@ console.log('loaded ok! some-key = ' + conf.get('some-key')) | ||
``` | ||
## API | ||
The `Config` class is the sole export. | ||
```js | ||
const Config = require('@npmcli/config') | ||
``` | ||
### static `Config.typeDefs` | ||
The type definitions passed to `nopt` for CLI option parsing and known | ||
configuration validation. | ||
### constructor `new Config(options)` | ||
Options: | ||
- `types` Types of all known config values. Note that some are effectively | ||
given semantic value in the config loading process itself. | ||
- `shorthands` An object mapping a shorthand value to an array of CLI | ||
arguments that replace it. | ||
- `defaults` Default values for each of the known configuration keys. | ||
These should be defined for all configs given a type, and must be valid. | ||
- `npmPath` The path to the `npm` module, for loading the `builtin` config | ||
file. | ||
- `cwd` Optional, defaults to `process.cwd()`, used for inferring the | ||
`localPrefix` and loading the `project` config. | ||
- `platform` Optional, defaults to `process.platform`. Used when inferring | ||
the `globalPrefix` from the `execPath`, since this is done diferently on | ||
Windows. | ||
- `execPath` Optional, defaults to `process.execPath`. Used to infer the | ||
`globalPrefix`. | ||
- `log` Optional, the object used to log debug messages, warnings, and | ||
errors. Defaults to emitting on the `process` object. | ||
- `env` Optional, defaults to `process.env`. Source of the environment | ||
variables for configuration. | ||
- `argv` Optional, defaults to `process.argv`. Source of the CLI options | ||
used for configuration. | ||
Returns a `config` object, which is not yet loaded. | ||
Fields: | ||
- `config.globalPrefix` The prefix for `global` operations. Set by the | ||
`prefix` config value, or defaults based on the location of the | ||
`execPath` option. | ||
- `config.localPrefix` The prefix for `local` operations. Set by the | ||
`prefix` config value on the CLI only, or defaults to either the `cwd` or | ||
its nearest ancestor containing a `node_modules` folder or `package.json` | ||
file. | ||
- `config.sources` A read-only `Map` of the file (or a comment, if no file | ||
found, or relevant) to the config level loaded from that source. | ||
- `config.data` A `Map` of config level to `ConfigData` objects. These | ||
objects should not be modified directly under any circumstances. | ||
- `source` The source where this data was loaded from. | ||
- `raw` The raw data used to generate this config data, as it was parsed | ||
initially from the environment, config file, or CLI options. | ||
- `data` The data object reflecting the inheritance of configs up to this | ||
point in the chain. | ||
- `loadError` Any errors encountered that prevented the loading of this | ||
config data. | ||
- `config.list` A list sorted in priority of all the config data objects in | ||
the prototype chain. `config.list[0]` is the `cli` level, | ||
`config.list[1]` is the `env` level, and so on. | ||
- `cwd` The `cwd` param | ||
- `env` The `env` param | ||
- `argv` The `argv` param | ||
- `execPath` The `execPath` param | ||
- `platform` The `platform` param | ||
- `log` The `log` param | ||
- `defaults` The `defaults` param | ||
- `shorthands` The `shorthands` param | ||
- `types` The `types` param | ||
- `npmPath` The `npmPath` param | ||
- `globalPrefix` The effective `globalPrefix` | ||
- `localPrefix` The effective `localPrefix` | ||
- `prefix` If `config.get('global')` is true, then `globalPrefix`, | ||
otherwise `localPrefix` | ||
- `home` The user's home directory, found by looking at `env.HOME` or | ||
calling `os.homedir()`. | ||
- `loaded` A boolean indicating whether or not configs are loaded | ||
### `config.load()` | ||
Load configuration from the various sources of information. | ||
Returns a `Promise` that resolves when configuration is loaded, and fails | ||
if a fatal error is encountered. | ||
### `config.find(key)` | ||
Find the effective place in the configuration levels a given key is set. | ||
Returns one of: `cli`, `env`, `project`, `user`, `global`, `builtin`, or | ||
`default`. | ||
Returns `null` if the key is not set. | ||
### `config.get(key, where = 'cli')` | ||
Load the given key from the config stack. | ||
### `config.set(key, value, where = 'cli')` | ||
Set the key to the specified value, at the specified level in the config | ||
stack. | ||
### `config.delete(key, where = 'cli')` | ||
Delete the configuration key from the specified level in the config stack. | ||
### `config.validate()` | ||
Verify that all known configuration options are set to valid values. | ||
### `config.save(where)` | ||
Save the config file specified by the `where` param. Must be one of | ||
`project`, `user`, `global`, `builtin`. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
39967
867
1
213