@james-pre/config 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,15 @@
1
1
  # @james-pre/config
2
2
 
3
3
  A small library for managing configuration files.
4
+
5
+ ## CLI
6
+
7
+ `@james-pre/config/cli` adds a `config` command to a [Commander](https://github.com/tj/commander.js) program, with `dump`, `get`, `set`, `list`, and `schema`:
8
+
9
+ ```ts
10
+ import { configCommand } from '@james-pre/config/cli';
11
+
12
+ configCommand(program, configManager);
13
+ ```
14
+
15
+ Commander is an optional peer dependency, needed only for the CLI.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { Command } from 'commander';
2
+ import * as z from 'zod';
3
+ import type { FileType, Manager } from './manager.js';
4
+ export interface ConfigCommandOptions {
5
+ /** @default 'config' */
6
+ name?: string;
7
+ /**
8
+ * Keys whose values `--redact` hides, wherever they are.
9
+ * @default ['password', 'secret']
10
+ */
11
+ sensitive?: readonly string[];
12
+ /** The kind of file `set` writes to without `--type`, otherwise the most recently loaded one. */
13
+ defaultType?: FileType;
14
+ }
15
+ /**
16
+ * Add a command for reading and changing a manager's configuration to `parent`.
17
+ * @returns the new command, for adding more subcommands
18
+ */
19
+ export declare function configCommand<C extends Command>(parent: C, manager: Manager<z.ZodObject>, options?: ConfigCommandOptions): Command;
package/dist/cli.js ADDED
@@ -0,0 +1,79 @@
1
+ import { getByString, setByString } from 'utilium';
2
+ import * as z from 'zod';
3
+ const fileTypes = ['system', 'user', 'local'];
4
+ function redact(value, keys) {
5
+ if (Array.isArray(value))
6
+ return value.map(item => redact(item, keys));
7
+ if (typeof value != 'object' || value === null)
8
+ return value;
9
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, keys.includes(key) ? '[redacted]' : redact(child, keys)]));
10
+ }
11
+ /**
12
+ * Add a command for reading and changing a manager's configuration to `parent`.
13
+ * @returns the new command, for adding more subcommands
14
+ */
15
+ export function configCommand(parent, manager, options = {}) {
16
+ const { sensitive = ['password', 'secret'] } = options;
17
+ const command = parent
18
+ .command(options.name ?? 'config')
19
+ .description('Manage the configuration')
20
+ .option('-j, --json', 'read and write values as JSON', false)
21
+ .option('-r, --redact', 'hide sensitive values', false);
22
+ function output(value) {
23
+ const { json, redact: hide } = command.opts();
24
+ if (hide)
25
+ value = redact(value, sensitive);
26
+ console.log(json ? JSON.stringify(value, null, 4) : value);
27
+ }
28
+ command
29
+ .command('dump')
30
+ .description('Output the entire current configuration')
31
+ .action(() => output(manager.data));
32
+ command
33
+ .command('get')
34
+ .description('Get a config value')
35
+ .argument('<key>', 'the key to get')
36
+ .action(key => output(getByString(manager.data, key)));
37
+ command
38
+ .command('set')
39
+ .description('Set a config value, which must be JSON for anything but a string')
40
+ .argument('<key>', 'the key to set')
41
+ .argument('<value>', 'the value')
42
+ .addOption(command.createOption('-t, --type <type>', 'the kind of file to write to').choices(fileTypes))
43
+ .addOption(command.createOption('-g, --global', 'write to the system file, like --type system').conflicts('type'))
44
+ .action(function (key, value, opts) {
45
+ let parsed = value;
46
+ if (command.opts().json) {
47
+ try {
48
+ parsed = JSON.parse(value);
49
+ }
50
+ catch {
51
+ this.error('error: value is not valid JSON');
52
+ }
53
+ }
54
+ const update = {};
55
+ setByString(update, key, parsed);
56
+ try {
57
+ manager.update(update, opts.global ? 'system' : (opts.type ?? options.defaultType));
58
+ }
59
+ catch (error) {
60
+ if (!(error instanceof z.ZodError))
61
+ throw error;
62
+ this.error('error: invalid value\n' + z.prettifyError(error));
63
+ }
64
+ });
65
+ command
66
+ .command('list')
67
+ .alias('ls')
68
+ .alias('files')
69
+ .description('List loaded config files')
70
+ .action(() => {
71
+ for (const path of manager.filePaths)
72
+ console.log(path);
73
+ });
74
+ command
75
+ .command('schema')
76
+ .description('Get the JSON schema for config files')
77
+ .action(() => output(z.toJSONSchema(manager.fileSchema, { io: 'input' })));
78
+ return command;
79
+ }
package/package.json CHANGED
@@ -1,14 +1,25 @@
1
1
  {
2
2
  "name": "@james-pre/config",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Manage configuration files",
5
+ "author": "James Prevett <jp@jamespre.dev> (https://jamespre.dev)",
6
+ "license": "LGPL-3.0-or-later",
5
7
  "funding": {
6
8
  "type": "individual",
7
9
  "url": "https://github.com/sponsors/james-pre"
8
10
  },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/james-pre/common.git",
14
+ "directory": "packages/config"
15
+ },
16
+ "homepage": "https://github.com/james-pre/common/tree/main/packages/config#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/james-pre/common/issues"
19
+ },
20
+ "type": "module",
9
21
  "main": "dist/index.js",
10
22
  "types": "dist/index.d.ts",
11
- "type": "module",
12
23
  "exports": {
13
24
  ".": "./dist/index.js",
14
25
  "./*": "./dist/*.js"
@@ -18,51 +29,24 @@
18
29
  "README.md"
19
30
  ],
20
31
  "scripts": {
21
- "format:check": "prettier --check .",
22
- "format": "prettier --write .",
23
- "build": "tsc -b",
24
- "lint": "tsc -b --noEmit && eslint src",
25
- "prepublishOnly": "npx tsc"
32
+ "build": "tsc"
26
33
  },
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/james-pre/config"
30
- },
31
- "author": "James Prevett <jp@jamespre.dev> (https://jamespre.dev)",
32
- "license": "LGPL-3.0-or-later",
33
- "bugs": {
34
- "url": "https://github.com/james-pre/config/issues"
35
- },
36
- "homepage": "https://github.com/james-pre/config#readme",
37
34
  "engines": {
38
35
  "node": ">=22.0.0"
39
36
  },
40
37
  "peerDependencies": {
38
+ "commander": "^15.0.0",
41
39
  "utilium": "^3.7.0",
42
40
  "zod": "^4.5.0"
43
41
  },
42
+ "peerDependenciesMeta": {
43
+ "commander": {
44
+ "optional": true
45
+ }
46
+ },
44
47
  "publishConfig": {
45
48
  "provenance": true,
46
49
  "access": "public"
47
50
  },
48
- "devDependencies": {
49
- "@eslint/js": "^10.0.1",
50
- "@types/node": "^24.7.0",
51
- "eslint": "^10.1.0",
52
- "globals": "^17.4.0",
53
- "prettier": "^3.2.5",
54
- "typedoc": "^0.28.18",
55
- "typescript": "^6.0.2",
56
- "typescript-eslint": "^8.58.0"
57
- },
58
- "prettier": {
59
- "singleQuote": true,
60
- "useTabs": true,
61
- "trailingComma": "es5",
62
- "tabWidth": 4,
63
- "printWidth": 120,
64
- "arrowParens": "avoid",
65
- "experimentalOperatorPosition": "start"
66
- },
67
51
  "sideEffects": false
68
52
  }