@vltpkg/config 1.0.0-rc.23 → 1.0.0-rc.24

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.
@@ -0,0 +1,6 @@
1
+ import type { LoadedConfig } from '@vltpkg/cli-sdk/config';
2
+ export declare const list: (conf: LoadedConfig) => import("@vltpkg/cli-sdk/config").RecordPairs;
3
+ export declare const del: (conf: LoadedConfig) => Promise<void>;
4
+ export declare const get: (conf: LoadedConfig) => Promise<string | number | boolean | string[] | import("@vltpkg/cli-sdk/config").RecordString | undefined>;
5
+ export declare const edit: (conf: LoadedConfig) => Promise<void>;
6
+ export declare const set: (conf: LoadedConfig) => Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,187 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import * as dotProp from '@vltpkg/dot-prop';
3
+ import { error } from '@vltpkg/error-cause';
4
+ import { asRootError } from '@vltpkg/output/error';
5
+ import { isObject } from '@vltpkg/types';
6
+ import { getSortedKeys } from '@vltpkg/cli-sdk/definition';
7
+ import { isRecordField, pairsToRecords, recordsToPairs, } from '@vltpkg/cli-sdk/config';
8
+ export const list = (conf) => {
9
+ return recordsToPairs(conf.options);
10
+ };
11
+ export const del = async (conf) => {
12
+ const fields = conf.positionals.slice(1);
13
+ if (!fields.length) {
14
+ throw error('At least one key is required', {
15
+ code: 'EUSAGE',
16
+ });
17
+ }
18
+ const configOption = conf.get('config');
19
+ const whichConfig = configOption === 'all' ? 'project' : configOption;
20
+ await conf.deleteConfigKeys(whichConfig, fields);
21
+ };
22
+ export const get = async (conf) => {
23
+ const keys = conf.positionals.slice(1);
24
+ const k = keys[0];
25
+ if (!k || keys.length > 1) {
26
+ throw error('Exactly one key is required', {
27
+ code: 'EUSAGE',
28
+ });
29
+ }
30
+ // check if this is a dot-prop path into a record field, in which case
31
+ // we need to get the record first and then use dot-prop to get the value
32
+ if (k.includes('.')) {
33
+ const [field, ...rest] = k.split('.');
34
+ const subKey = rest.join('.');
35
+ if (!field || !subKey) {
36
+ throw error('Could not read property', {
37
+ found: k,
38
+ });
39
+ }
40
+ // we'd need a type assertion helper from jackspeak definition
41
+ // options in order to cast the field to a known name type
42
+ // @ts-expect-error @typescript-eslint/no-unsafe-argument
43
+ const record = conf.getRecord(field);
44
+ return dotProp.get(record, subKey);
45
+ }
46
+ // otherwise just get the value directly from the config getter
47
+ return isRecordField(k) ?
48
+ conf.getRecord(k)
49
+ : conf.get(k);
50
+ };
51
+ export const edit = async (conf) => {
52
+ const [command, ...args] = conf.get('editor').split(' ');
53
+ if (!command) {
54
+ throw error(`editor is empty`);
55
+ }
56
+ const configOption = conf.get('config');
57
+ const whichConfig = configOption === 'all' ? 'project' : configOption;
58
+ await conf.editConfigFile(whichConfig, file => {
59
+ args.push(file);
60
+ const res = spawnSync(command, args, {
61
+ stdio: 'inherit',
62
+ });
63
+ if (res.status !== 0) {
64
+ throw error(`${command} command failed`, {
65
+ ...res,
66
+ command,
67
+ args,
68
+ });
69
+ }
70
+ });
71
+ };
72
+ export const set = async (conf) => {
73
+ const pairs = conf.positionals.slice(1);
74
+ if (!pairs.length) {
75
+ // Create an empty config file
76
+ const configOption = conf.get('config');
77
+ const whichConfig = configOption === 'all' ? 'project' : configOption;
78
+ await conf.addConfigToFile(whichConfig, {});
79
+ return;
80
+ }
81
+ const configOption = conf.get('config');
82
+ const which = configOption === 'all' ? 'project' : configOption;
83
+ // separate dot-prop paths from simple keys for different handling
84
+ // any keys that include a dot (.) will be treated as dotPropPairs
85
+ // other keys/value pairs are handled as simplePairs
86
+ const dotPropPairs = [];
87
+ const simplePairs = [];
88
+ for (const pair of pairs) {
89
+ const eq = pair.indexOf('=');
90
+ if (eq === -1) {
91
+ throw error('Set arguments must contain `=`', {
92
+ code: 'EUSAGE',
93
+ });
94
+ }
95
+ const key = pair.substring(0, eq);
96
+ const value = pair.substring(eq + 1);
97
+ if (key.includes('.')) {
98
+ const [field, ...rest] = key.split('.');
99
+ const subKey = rest.join('.');
100
+ if (field && subKey) {
101
+ dotPropPairs.push({ key, field, subKey, value });
102
+ }
103
+ else {
104
+ throw error('Could not read property', {
105
+ found: pair,
106
+ });
107
+ }
108
+ }
109
+ else {
110
+ simplePairs.push(pair);
111
+ }
112
+ }
113
+ // Handle keys that consists of a single name (e.g., `--foo`)
114
+ // so that it doesn't need the dot-prop logic to handle values
115
+ if (simplePairs.length > 0) {
116
+ try {
117
+ const parsed = conf.jack.parseRaw(simplePairs.map(kv => `--${kv}`)).values;
118
+ await conf.addConfigToFile(which, pairsToRecords(parsed));
119
+ }
120
+ catch (err) {
121
+ handleSetError(simplePairs, err);
122
+ }
123
+ }
124
+ // Handle dot-prop paths for record fields and nested properties
125
+ if (dotPropPairs.length > 0) {
126
+ // Separate record fields from nested properties
127
+ const recordPairs = [];
128
+ const nestedProps = [];
129
+ for (const { key, field, subKey, value } of dotPropPairs) {
130
+ if (isRecordField(field)) {
131
+ recordPairs.push({ field, subKey, value });
132
+ }
133
+ else {
134
+ nestedProps.push({ key, value });
135
+ }
136
+ }
137
+ // Handle record fields
138
+ for (const { field, subKey, value } of recordPairs) {
139
+ // For record fields, we add entries in the format field=key=value
140
+ const recordPair = `${field}=${subKey}=${value}`;
141
+ try {
142
+ const parsed = conf.jack.parseRaw([`--${recordPair}`]).values;
143
+ await conf.addConfigToFile(which, pairsToRecords(parsed));
144
+ /* c8 ignore start */
145
+ }
146
+ catch (err) {
147
+ handleSetError([recordPair], err);
148
+ }
149
+ /* c8 ignore end */
150
+ }
151
+ // Handle nested properties using dot-prop
152
+ if (nestedProps.length > 0) {
153
+ const nested = {};
154
+ for (const { key, value } of nestedProps) {
155
+ dotProp.set(nested, key, value);
156
+ }
157
+ await conf.addConfigToFile(which, nested);
158
+ }
159
+ }
160
+ };
161
+ const handleSetError = (simplePairs, err) => {
162
+ const { name, found, validOptions } = asRootError(err).cause;
163
+ // when a boolean gets a value, it throw a parse error
164
+ if (isObject(found) &&
165
+ typeof found.name === 'string' &&
166
+ typeof found.value === 'string') {
167
+ const { name, value } = found;
168
+ throw error(`Boolean flag must be "${name}" or "no-${name}", not a value`, {
169
+ code: 'ECONFIG',
170
+ name,
171
+ found: `${name}=${value}`,
172
+ });
173
+ }
174
+ if (Array.isArray(validOptions)) {
175
+ throw error(`Invalid value provided for ${name}`, {
176
+ code: 'ECONFIG',
177
+ found,
178
+ validOptions,
179
+ });
180
+ }
181
+ // an unknown property
182
+ throw error('Invalid config keys', {
183
+ code: 'ECONFIG',
184
+ found: simplePairs.map(kv => kv.split('=')[0]),
185
+ validOptions: getSortedKeys(),
186
+ });
187
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/config",
3
3
  "description": "Project config logic for vltpkg",
4
- "version": "1.0.0-rc.23",
4
+ "version": "1.0.0-rc.24",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -12,12 +12,12 @@
12
12
  "email": "support@vlt.sh"
13
13
  },
14
14
  "dependencies": {
15
- "@vltpkg/cli-sdk": "1.0.0-rc.23",
16
- "@vltpkg/dot-prop": "1.0.0-rc.23",
17
- "@vltpkg/error-cause": "1.0.0-rc.23",
18
- "@vltpkg/output": "1.0.0-rc.23",
19
- "@vltpkg/package-json": "1.0.0-rc.23",
20
- "@vltpkg/types": "1.0.0-rc.23",
15
+ "@vltpkg/cli-sdk": "1.0.0-rc.24",
16
+ "@vltpkg/dot-prop": "1.0.0-rc.24",
17
+ "@vltpkg/error-cause": "1.0.0-rc.24",
18
+ "@vltpkg/output": "1.0.0-rc.24",
19
+ "@vltpkg/package-json": "1.0.0-rc.24",
20
+ "@vltpkg/types": "1.0.0-rc.24",
21
21
  "path-scurry": "^2.0.1"
22
22
  },
23
23
  "devDependencies": {