@abw/badger 1.0.0 → 1.0.1
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 +30 -3
- package/dist/badger.cjs.js +2 -913
- package/dist/badger.cjs.js.map +1 -0
- package/dist/badger.esm.js +2 -874
- package/dist/badger.esm.js.map +1 -0
- package/package.json +6 -4
package/dist/badger.cjs.js
CHANGED
|
@@ -1,913 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
-
|
|
7
|
-
var process = _interopDefault(require('node:process'));
|
|
8
|
-
var path = _interopDefault(require('node:path'));
|
|
9
|
-
var promises = require('node:fs/promises');
|
|
10
|
-
var yaml = _interopDefault(require('js-yaml'));
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Determines if a value is a string
|
|
14
|
-
* @param {String} value - value to test
|
|
15
|
-
* @return {Boolean} true if `value` is a string or false if not
|
|
16
|
-
*/
|
|
17
|
-
function isString(value) {
|
|
18
|
-
return typeof value === 'string';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Determines if a value is an array
|
|
23
|
-
* @param {Array} value - value to test
|
|
24
|
-
* @return {Boolean} true if `value` is an Array or false if not
|
|
25
|
-
*/
|
|
26
|
-
function isArray(value) {
|
|
27
|
-
return Array.isArray(value);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Determines if a value is a Function
|
|
32
|
-
* @param {Function} value - value to test
|
|
33
|
-
* @return {Boolean} true if `value` is a Function or false if not
|
|
34
|
-
*/
|
|
35
|
-
function isFunction(value) {
|
|
36
|
-
return typeof value === 'function'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Determines if a value is an Object (but not an Array)
|
|
41
|
-
* @param {Object} value - value to test
|
|
42
|
-
* @return {Boolean} true if `value` is an Object or false if not
|
|
43
|
-
*/
|
|
44
|
-
function isObject(value) {
|
|
45
|
-
return typeof value === "object"
|
|
46
|
-
&& ! isArray(value)
|
|
47
|
-
&& ! isNull(value);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Determines if a value is `undefined`
|
|
52
|
-
* @param {any} value - value to test
|
|
53
|
-
* @return {Boolean} true if `value` is `undefined` or false if not
|
|
54
|
-
*/
|
|
55
|
-
function isUndefined(value) {
|
|
56
|
-
return typeof value === 'undefined';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Determines if a value is `null`
|
|
61
|
-
* @param {any} value - value to test
|
|
62
|
-
* @return {Boolean} true if `value` is `null` or false if not
|
|
63
|
-
*/
|
|
64
|
-
function isNull(value) {
|
|
65
|
-
return value === null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Determines if a value is defined and not null
|
|
70
|
-
* @param {any} value - value to test
|
|
71
|
-
* @return {Boolean} true if `value` is not `undefined` or `null`
|
|
72
|
-
*/
|
|
73
|
-
function hasValue(value) {
|
|
74
|
-
return ! (isUndefined(value) || isNull(value));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Determines if all values are defined and not null
|
|
79
|
-
* @param {any[]} values - values to test
|
|
80
|
-
* @return {Boolean} true if all values are not `undefined` or `null`
|
|
81
|
-
*/
|
|
82
|
-
function haveValue(...values) {
|
|
83
|
-
return values.every( value => hasValue(value) );
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Determines if a value is undefined or null
|
|
88
|
-
* @param {any} value - value to test
|
|
89
|
-
* @return {Boolean} true if `value` is `undefined` or `null`
|
|
90
|
-
*/
|
|
91
|
-
function noValue(value) {
|
|
92
|
-
return ! hasValue(value);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Throws a new Error object
|
|
97
|
-
* @param {String[]} message - error message string(s)
|
|
98
|
-
* @throws {Error}
|
|
99
|
-
*/
|
|
100
|
-
function fail(...message) {
|
|
101
|
-
throw new Error(message.join(''));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Re-throw an existing Error object
|
|
106
|
-
* @param {Error} error - error object
|
|
107
|
-
* @throws {Error}
|
|
108
|
-
*/
|
|
109
|
-
function rethrow(error) {
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Do nothing. Nothing at all.
|
|
115
|
-
*/
|
|
116
|
-
function doNothing() {
|
|
117
|
-
// speak again Cordelia
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const ANSIStart = '\u001B[';
|
|
121
|
-
const ANSIEnd = 'm';
|
|
122
|
-
const ANSIColors = {
|
|
123
|
-
reset: 0,
|
|
124
|
-
bold: 1,
|
|
125
|
-
bright: 1,
|
|
126
|
-
dark: 2,
|
|
127
|
-
black: 0,
|
|
128
|
-
red: 1,
|
|
129
|
-
green: 2,
|
|
130
|
-
yellow: 3,
|
|
131
|
-
blue: 4,
|
|
132
|
-
magenta: 5,
|
|
133
|
-
cyan: 6,
|
|
134
|
-
grey: 7,
|
|
135
|
-
white: 8,
|
|
136
|
-
fg: 30,
|
|
137
|
-
bg: 40,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const escapeCode = (str, base=0) => {
|
|
141
|
-
let codes = [ ];
|
|
142
|
-
let pair = str.split(/ /, 2);
|
|
143
|
-
const hue = pair.pop();
|
|
144
|
-
const code = (base ? ANSIColors[base] : 0) + ANSIColors[hue];
|
|
145
|
-
codes.push(code);
|
|
146
|
-
if (pair.length) {
|
|
147
|
-
const shade = pair.length ? pair.shift() : 'dark';
|
|
148
|
-
codes.push(ANSIColors[shade]);
|
|
149
|
-
}
|
|
150
|
-
return ANSIStart + codes.join(';') + ANSIEnd;
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const escape = (c={}) => {
|
|
154
|
-
// color c can be specified as a string (e.g. 'red') which is shorthand
|
|
155
|
-
// for an object containing 'fg' (e.g. { fg: 'red' }) and/or 'bg' for
|
|
156
|
-
// foreground and background colors respectively
|
|
157
|
-
const col = isObject(c) ? c : { fg: c };
|
|
158
|
-
let escapes = [ ];
|
|
159
|
-
if (col.bg) {
|
|
160
|
-
escapes.push(escapeCode(col.bg, 'bg'));
|
|
161
|
-
}
|
|
162
|
-
if (col.fg) {
|
|
163
|
-
escapes.push(escapeCode(col.fg, 'fg'));
|
|
164
|
-
}
|
|
165
|
-
return escapes.join('');
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const reset = () => escapeCode('reset');
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Returns a debugging function which is enabled by the first `enabled` argument.
|
|
172
|
-
* If this is `false` then it returns a function which does nothing. If it is
|
|
173
|
-
* true then it returns a function that forwards all arguments to `console.log`.
|
|
174
|
-
* An optional `prefix` be be specified to prefix each debugging line. The
|
|
175
|
-
* optional third argument `color` can be used to specify a color for the prefix.
|
|
176
|
-
* @param {Boolean} enabled - is debugging enabled?
|
|
177
|
-
* @param {String} [prefix] - optional prefix for debugging messages
|
|
178
|
-
* @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})
|
|
179
|
-
* @param {String} [color.fg] - foreground color
|
|
180
|
-
* @param {String} [color.bg] - background color
|
|
181
|
-
* @return {Function} a debugging function
|
|
182
|
-
* @example
|
|
183
|
-
* const debug = Debugger(true)
|
|
184
|
-
* @example
|
|
185
|
-
* const debug = Debugger(true, 'Debug > ')
|
|
186
|
-
* @example
|
|
187
|
-
* const debug = Debugger(true, 'Debug > ', 'blue')
|
|
188
|
-
* @example
|
|
189
|
-
* const debug = Debugger(true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })
|
|
190
|
-
*/
|
|
191
|
-
function Debugger(enabled, prefix='', color) {
|
|
192
|
-
return enabled
|
|
193
|
-
? prefix
|
|
194
|
-
? (format, ...args) =>
|
|
195
|
-
console.log(
|
|
196
|
-
'%s' + prefix + '%s' + format,
|
|
197
|
-
color ? escape(color) : '',
|
|
198
|
-
reset(),
|
|
199
|
-
...args,
|
|
200
|
-
)
|
|
201
|
-
: console.log.bind(console)
|
|
202
|
-
: doNothing;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Creates a debugging function via {@link Debugger} and attaches it to the object
|
|
207
|
-
* passed as the first argument as the `debug` function.
|
|
208
|
-
* @param {Object} obj - the object to receive the `debug` function
|
|
209
|
-
* @param {Boolean} enabled - is debugging enabled?
|
|
210
|
-
* @param {String} [prefix] - optional prefix for debugging messages
|
|
211
|
-
* @param {String|Object} [color] - a color name or object (see {@link Badger/Utils/Color})
|
|
212
|
-
* @param {String} [color.fg] - foreground color
|
|
213
|
-
* @param {String} [color.bg] - background color
|
|
214
|
-
* @example
|
|
215
|
-
* const debug = addDebug(myObject, true)
|
|
216
|
-
* @example
|
|
217
|
-
* const debug = addDebug(myObject, true, 'Debug > ')
|
|
218
|
-
* @example
|
|
219
|
-
* const debug = addDebug(myObject, true, 'Debug > ', 'blue')
|
|
220
|
-
* @example
|
|
221
|
-
* const debug = addDebug(myObject, true, 'Debug > ', { bg: 'blue', fg: 'bright yellow' })
|
|
222
|
-
*/
|
|
223
|
-
function addDebug(obj, enabled, prefix='', color) {
|
|
224
|
-
obj.debug = Debugger(enabled, prefix, color);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const defaultOptions = {
|
|
228
|
-
encoding: 'utf8'
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
class Path {
|
|
232
|
-
constructor(path, options={}) {
|
|
233
|
-
// allow path/file/directory to be constructed from an existing object
|
|
234
|
-
if (path instanceof Path) {
|
|
235
|
-
path = path.path();
|
|
236
|
-
}
|
|
237
|
-
this.state = { path, options: { ...defaultOptions, ...options } };
|
|
238
|
-
addDebug(this, options.debug, options.debugPrefix || 'Path', options.debugColor);
|
|
239
|
-
}
|
|
240
|
-
path() {
|
|
241
|
-
return this.state.path;
|
|
242
|
-
}
|
|
243
|
-
relativePath(...parts) {
|
|
244
|
-
return path.join(this.state.path, ...parts);
|
|
245
|
-
}
|
|
246
|
-
options(options={}) {
|
|
247
|
-
return { ...this.state.options, ...options };
|
|
248
|
-
}
|
|
249
|
-
async exists() {
|
|
250
|
-
try {
|
|
251
|
-
await this.stat();
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
catch (error) {
|
|
255
|
-
return error.code === 'ENOENT'
|
|
256
|
-
? false
|
|
257
|
-
: rethrow(error);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
async stat() {
|
|
261
|
-
const stats = await promises.stat(this.state.path);
|
|
262
|
-
return this.state.stats = stats;
|
|
263
|
-
}
|
|
264
|
-
unstat() {
|
|
265
|
-
this.state.stats = undefined;
|
|
266
|
-
console.log('XXX unstat: ', this.state.stats);
|
|
267
|
-
return this;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Function to encode JSON
|
|
273
|
-
* @param {Object} data - The data to encode as JSON text
|
|
274
|
-
* @return {String} a JSON encoded string
|
|
275
|
-
* @example
|
|
276
|
-
* encode({ message: 'Hello World' })
|
|
277
|
-
*/
|
|
278
|
-
const encode = data => JSON.stringify(data);
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Function to decode JSON
|
|
282
|
-
* @param {String} text - The JSON text to decode
|
|
283
|
-
* @return {Object|Array} the decoded object or array
|
|
284
|
-
* @example
|
|
285
|
-
* decode("{ message: 'Hello World' }")
|
|
286
|
-
*/
|
|
287
|
-
const decode = text => JSON.parse(text);
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* An object containing the JSON `encode` and `decode` functions
|
|
291
|
-
*/
|
|
292
|
-
const codec = { encode, decode };
|
|
293
|
-
|
|
294
|
-
// simple wrapper around JSON load/dump
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Function to encode YAML
|
|
298
|
-
* @param {Object} data - The data to encode as YAML text
|
|
299
|
-
* @return {String} a YAML encoded string
|
|
300
|
-
* @example
|
|
301
|
-
* encode({ message: 'Hello World' })
|
|
302
|
-
*/
|
|
303
|
-
const encode$1 = data => yaml.dump(data);
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Function to decode YAML
|
|
307
|
-
* @param {String} text - The YAML text to decode
|
|
308
|
-
* @return {Object|Array} the decoded object or array
|
|
309
|
-
* @example
|
|
310
|
-
* decode("message: Hello World")
|
|
311
|
-
*/
|
|
312
|
-
const decode$1 = text => yaml.load(text);
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* An object containing the YAML `encode` and `decode` functions
|
|
316
|
-
*/
|
|
317
|
-
const codec$1 = { encode: encode$1, decode: decode$1 };
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Codecs provide a consistent encode()/decode() interface for serialising
|
|
321
|
-
* and de-serialising data. This standard naming convention makes it possible
|
|
322
|
-
* for the ../Filesystem/File.js module to support a "codec" option for
|
|
323
|
-
* files. When this option is set the file.read() and file.write() methods
|
|
324
|
-
* automatically handle the translation to and from the serialised format
|
|
325
|
-
* using a codec object returned by the codec() function below. The codec
|
|
326
|
-
* name can be specified in any case, e.g. "Yaml", "YAML", "yaml", "YaML",
|
|
327
|
-
* etc., and it will be converted to lower case.
|
|
328
|
-
*/
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Lookup table for codecs
|
|
332
|
-
*/
|
|
333
|
-
const codecs = {
|
|
334
|
-
json: codec, yaml: codec$1
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Function to fetch a codec
|
|
339
|
-
* @param {string} name - The title of the code, in any case, e.g. "yaml", "YAML", "Yaml"
|
|
340
|
-
*/
|
|
341
|
-
const codec$2 = name => codecs[
|
|
342
|
-
name.toLowerCase()
|
|
343
|
-
];
|
|
344
|
-
|
|
345
|
-
class File extends Path {
|
|
346
|
-
/**
|
|
347
|
-
* Returns a new {@link Directory} object for the parent directory of the file
|
|
348
|
-
* @param {Object} [options] - directory configuration options
|
|
349
|
-
* @param {Boolean} [options.codec] - codec for encoding/decoding file data
|
|
350
|
-
* @return {Object} a {@link Directory} object for the parent
|
|
351
|
-
*/
|
|
352
|
-
directory(options) {
|
|
353
|
-
return dir(path.dirname(this.state.path), options);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* An alias for the {@link directory} method for lazy people
|
|
358
|
-
* @return {Object} the parent {@link Directory} object
|
|
359
|
-
*/
|
|
360
|
-
dir(...args) {
|
|
361
|
-
return this.directory(...args);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Reads the file content. If a `codec` has been specified then the content is decoded.
|
|
366
|
-
* @param {Object} [options] - directory configuration options
|
|
367
|
-
* @param {Boolean} [options.codec] - codec for encoding/decoding file data
|
|
368
|
-
* @return {String|Object} the file content
|
|
369
|
-
* @example
|
|
370
|
-
* const text = file('myfile.txt').read();
|
|
371
|
-
* @example
|
|
372
|
-
* const data = file('myfile.json', { codec: 'json' }).read();
|
|
373
|
-
* @example
|
|
374
|
-
* const data = file('myfile.json').read({ codec: 'json' });
|
|
375
|
-
*/
|
|
376
|
-
read(options) {
|
|
377
|
-
const opts = this.options(options);
|
|
378
|
-
const file = promises.readFile(this.state.path, opts);
|
|
379
|
-
return opts.codec
|
|
380
|
-
? file.then(text => codec$2(opts.codec).decode(text))
|
|
381
|
-
: file;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Writes the file content. If a `codec` has been specified then the content will be encoded.
|
|
386
|
-
* @param {String|Object} data - directory configuration options
|
|
387
|
-
* @param {Object} [options] - directory configuration options
|
|
388
|
-
* @param {Boolean} [options.codec] - codec for encoding/decoding file data
|
|
389
|
-
* @example
|
|
390
|
-
* file('myfile.txt').write('Hello World');
|
|
391
|
-
* @example
|
|
392
|
-
* file('myfile.json', { codec: 'json' }).write({ message: 'Hello World' });
|
|
393
|
-
* @example
|
|
394
|
-
* file('myfile.json').write({ message: 'Hello World' }, { codec: 'json' });
|
|
395
|
-
*/
|
|
396
|
-
write(data, options) {
|
|
397
|
-
const opts = this.options(options);
|
|
398
|
-
const text = opts.codec
|
|
399
|
-
? codec$2(opts.codec).encode(data)
|
|
400
|
-
: data;
|
|
401
|
-
return promises.writeFile(this.state.path, text, opts).then( () => this );
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Function to create a new {@link File} object for a file
|
|
407
|
-
* @param {String} path - file path
|
|
408
|
-
* @param {Object} [options] - configuration options
|
|
409
|
-
* @param {Boolean} [options.codec] - a codec for encoding/decoding files
|
|
410
|
-
* @return {Object} the {@link File} object
|
|
411
|
-
*/
|
|
412
|
-
const file = (path, options) => {
|
|
413
|
-
return new File(path, options);
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
class Directory extends Path {
|
|
417
|
-
/**
|
|
418
|
-
* Fetch a new {@link File} object for a file in the directory.
|
|
419
|
-
* @param {string} path - file path
|
|
420
|
-
* @param {Object} [options] - file configuration options
|
|
421
|
-
* @param {String} [options.codec] - codec for encoding/decoding file data
|
|
422
|
-
* @return {Object} the {@link File} object
|
|
423
|
-
*/
|
|
424
|
-
file(path, options) {
|
|
425
|
-
this.debug("file(%s, %o)", path, options);
|
|
426
|
-
return file(this.relativePath(path), this.options(options));
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Fetch a new {@link Directory} object for a sub-directory in the directory.
|
|
431
|
-
* @param {string} path - directory path
|
|
432
|
-
* @param {Object} [options] - directory configuration options
|
|
433
|
-
* @param {String} [options.codec] - codec for encoding/decoding file data
|
|
434
|
-
* @return {Object} the {@link Directory} object
|
|
435
|
-
*/
|
|
436
|
-
directory(path, options) {
|
|
437
|
-
this.debug("directory(%s, %o)", path, options);
|
|
438
|
-
return dir(this.relativePath(path), this.options(options));
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* An alias for the {@link directory} method for lazy people
|
|
443
|
-
* @return {Object} the {@link Directory} object
|
|
444
|
-
*/
|
|
445
|
-
dir(path, options) {
|
|
446
|
-
this.debug("dir(%s, %o)", path, options);
|
|
447
|
-
return this.directory(path, options);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Returns a new {@link Directory} object for the parent directory
|
|
452
|
-
* @param {Object} [options] - directory configuration options
|
|
453
|
-
* @param {Boolean} [options.codec] - codec for encoding/decoding file data
|
|
454
|
-
* @return {Object} a {@link Directory} object for the parent
|
|
455
|
-
*/
|
|
456
|
-
parent(options) {
|
|
457
|
-
this.debug("parent()");
|
|
458
|
-
return this.directory('..', options);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Returns the names of the files and sub-directories in the directory
|
|
463
|
-
* @return {Promise} fulfills with an array of the file and directory names
|
|
464
|
-
*/
|
|
465
|
-
async read() {
|
|
466
|
-
this.debug("read()");
|
|
467
|
-
return await promises.readdir(this.path());
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* Determines if the directory is empty.
|
|
472
|
-
* @return {Promise} fulfills with a boolean value true (empty) or false (not empty).
|
|
473
|
-
*/
|
|
474
|
-
async isEmpty() {
|
|
475
|
-
this.debug("isEmpty()");
|
|
476
|
-
const entries = await this.read();
|
|
477
|
-
return entries.length === 0;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Determines if the directory is not empty.
|
|
482
|
-
* @return {Promise} fulfills with a boolean value true (not empty) or false (empty).
|
|
483
|
-
*/
|
|
484
|
-
async notEmpty() {
|
|
485
|
-
this.debug("notEmpty()");
|
|
486
|
-
const empty = await this.isEmpty();
|
|
487
|
-
return !empty;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Empty the directory.
|
|
492
|
-
* @param {Object} [options] - configuration options
|
|
493
|
-
* @param {Boolean} [options.force] - force removal of files and directories
|
|
494
|
-
* @param {Boolean} [options.recursive] - recursively empty and delete sub-directories
|
|
495
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
496
|
-
*/
|
|
497
|
-
async empty(options={}) {
|
|
498
|
-
this.debug("empty(%o)", options);
|
|
499
|
-
if (await this.exists() && await this.notEmpty()) {
|
|
500
|
-
await promises.rm(this.path(), options);
|
|
501
|
-
}
|
|
502
|
-
return this;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Make the directory.
|
|
507
|
-
* @param {Object} [options] - configuration options
|
|
508
|
-
* @param {Boolean} [options.recursive] - create intermediate directories
|
|
509
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
510
|
-
*/
|
|
511
|
-
async mkdir(options={}) {
|
|
512
|
-
this.debug("mkdir(%o)", options);
|
|
513
|
-
const exists = await this.exists();
|
|
514
|
-
if (! exists) {
|
|
515
|
-
await promises.mkdir(this.path(), options);
|
|
516
|
-
}
|
|
517
|
-
return this;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* Remove the directory.
|
|
522
|
-
* @param {Object} [options] - configuration options
|
|
523
|
-
* @param {Boolean} [options.empty] - delete items in directory
|
|
524
|
-
* @param {Boolean} [options.force] - force delete files and directories
|
|
525
|
-
* @param {Boolean} [options.recursive] - recursively delete sub-directories
|
|
526
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
527
|
-
*/
|
|
528
|
-
async rmdir(options={}) {
|
|
529
|
-
this.debug("rmdir(%o)", options);
|
|
530
|
-
if (options.empty) {
|
|
531
|
-
await this.empty(options);
|
|
532
|
-
}
|
|
533
|
-
if (await this.exists()) {
|
|
534
|
-
await promises.rmdir(this.path());
|
|
535
|
-
}
|
|
536
|
-
return this;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Create the directory and any intermediate directories.
|
|
541
|
-
* @param {Object} [options] - configuration options
|
|
542
|
-
* @param {Boolean} [options.recursive=true] - recursively create intermediate directories
|
|
543
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
544
|
-
*/
|
|
545
|
-
create(options={ recursive: true }) {
|
|
546
|
-
this.debug("create(%o)", options);
|
|
547
|
-
return this.mkdir(options);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Empty and delete the directory.
|
|
552
|
-
* @param {Object} [options] - configuration options
|
|
553
|
-
* @param {Boolean} [options.empty=true] - empty directory of any files and sub-directories
|
|
554
|
-
* @param {Boolean} [options.recursive=true] - recursively delete sub-directories
|
|
555
|
-
* @param {Boolean} [options.force=true] - force deletion of files and sub-directories
|
|
556
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
557
|
-
*/
|
|
558
|
-
destroy(options={ empty: true, recursive: true, force: true }) {
|
|
559
|
-
this.debug("destroy(%o)", options);
|
|
560
|
-
return this.rmdir(options);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* Assert that a directory exists and optionally create it
|
|
565
|
-
* @param {Object} [options] - configuration options
|
|
566
|
-
* @param {Boolean} [options.create] - create the directory and any intermediate directories if it doesn't exist - equivalent to adding `mkdir` and `recursive` options or calling {@link create}
|
|
567
|
-
* @param {Boolean} [options.mkdir] - create the directory, add the `recursive` option to create intermediate directories - equivalent to calling {@link mkdir}
|
|
568
|
-
* @param {Boolean} [options.recursive] - when used with `mkdir`, creates any intermediate directories
|
|
569
|
-
* @return {Promise} fulfills to the {@link Directory} object
|
|
570
|
-
*/
|
|
571
|
-
async mustExist(options={}) {
|
|
572
|
-
this.debug("mustExist(%o)", options);
|
|
573
|
-
if (await this.exists()) {
|
|
574
|
-
return this;
|
|
575
|
-
}
|
|
576
|
-
if (options.mkdir) {
|
|
577
|
-
return this.mkdir(options);
|
|
578
|
-
}
|
|
579
|
-
if (options.create) {
|
|
580
|
-
return this.create();
|
|
581
|
-
}
|
|
582
|
-
fail("Directory does not exist: ", this.path());
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Function to create a new {@link Directory} object
|
|
588
|
-
* @param {string} path - directory path
|
|
589
|
-
* @param {Object} [options] - configuration options
|
|
590
|
-
* @param {Boolean} [options.codec] - a codec for encoding/decoding files
|
|
591
|
-
* @return {Object} the {@link Directory} object
|
|
592
|
-
*/
|
|
593
|
-
const dir = (path, options) => {
|
|
594
|
-
return new Directory(path, options);
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Function to create a new {@link Directory} object for the current working directory
|
|
599
|
-
* @param {Object} [options] - configuration options
|
|
600
|
-
* @param {Boolean} [options.codec] - a codec for encoding/decoding files
|
|
601
|
-
* @return {Object} the {@link Directory} object
|
|
602
|
-
*/
|
|
603
|
-
const cwd = options => {
|
|
604
|
-
return dir(process.cwd(), options);
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
/**
|
|
608
|
-
* Function to create a new {@link Directory} object for the directory of a JS source file
|
|
609
|
-
* @param {string} url - module url - from `import.meta.url`
|
|
610
|
-
* @param {Object} [options] - configuration options
|
|
611
|
-
* @param {Boolean} [options.codec] - a codec for encoding/decoding files
|
|
612
|
-
* @return {Object} the {@link Directory} object
|
|
613
|
-
*/
|
|
614
|
-
const bin = (url, options) => {
|
|
615
|
-
return dir(
|
|
616
|
-
path.dirname(url.replace(/^file:\/\//, '')),
|
|
617
|
-
options
|
|
618
|
-
);
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
/**
|
|
622
|
-
* Split a comma/whitespace delimited string into an Array
|
|
623
|
-
* @param {String} [value] - string to split
|
|
624
|
-
* @return {Array} array of split strings
|
|
625
|
-
* @example
|
|
626
|
-
* const strings = splitList('one two three')
|
|
627
|
-
* @example
|
|
628
|
-
* const strings = splitList('one,two,three')
|
|
629
|
-
* @example
|
|
630
|
-
* const strings = splitList('one, two, three')
|
|
631
|
-
*/
|
|
632
|
-
function splitList(value) {
|
|
633
|
-
return isString(value)
|
|
634
|
-
? value.split(/,\s*|\s+/)
|
|
635
|
-
: isArray(value)
|
|
636
|
-
? value
|
|
637
|
-
: [value];
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Join an Array into a single string
|
|
642
|
-
* @param {Array} [array] - array to join
|
|
643
|
-
* @param {String} [joint=' '] - delimiter to join strings
|
|
644
|
-
* @param {String} [lastJoint=joint] - delimiter for final item
|
|
645
|
-
* @return {String} joined string
|
|
646
|
-
* @example
|
|
647
|
-
* joinList(['one', 'two', 'three']); // one two three
|
|
648
|
-
* @example
|
|
649
|
-
* joinList(['one', 'two', 'three'], ', '); // one, two, three
|
|
650
|
-
* @example
|
|
651
|
-
* joinList(['one', 'two', 'three'], ', ', ' and '); // one, two and three
|
|
652
|
-
*/
|
|
653
|
-
function joinList(array, joint=' ', lastJoint=joint) {
|
|
654
|
-
let copy = [...array];
|
|
655
|
-
const last = copy.pop();
|
|
656
|
-
return copy.length
|
|
657
|
-
? [copy.join(joint), last].join(lastJoint)
|
|
658
|
-
: last;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Join an Array into a single string using commas for delimiters and ` and ` for the final item
|
|
663
|
-
* @param {Array} [array] - array to join
|
|
664
|
-
* @param {String} [joint=', '] - delimiter to join strings
|
|
665
|
-
* @param {String} [lastJoint=' and '] - delimiter for final item
|
|
666
|
-
* @return {String} joined string
|
|
667
|
-
* @example
|
|
668
|
-
* joinListAnd(['one', 'two', 'three']); // one, two and three
|
|
669
|
-
*/
|
|
670
|
-
function joinListAnd(array, joint=', ', lastJoint=' and ') {
|
|
671
|
-
return joinList(array, joint, lastJoint);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* Join an Array into a single string using commas for delimiters and ` or ` for the final item
|
|
676
|
-
* @param {Array} [array] - array to join
|
|
677
|
-
* @param {String} [joint=', '] - delimiter to join strings
|
|
678
|
-
* @param {String} [lastJoint=' or '] - delimiter for final item
|
|
679
|
-
* @return {String} joined string
|
|
680
|
-
* @example
|
|
681
|
-
* joinListOr(['one', 'two', 'three']); // one, two or three
|
|
682
|
-
*/
|
|
683
|
-
function joinListOr(array, joint=', ', lastJoint=' or ') {
|
|
684
|
-
return joinList(array, joint, lastJoint);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* Capitalise a string by converting the first character to upper case and other characters to lower case
|
|
689
|
-
* @param {String} [word] - word to capitalise
|
|
690
|
-
* @return {String} capitalised string
|
|
691
|
-
* @example
|
|
692
|
-
* capitalise('badger'); // Badger
|
|
693
|
-
* @example
|
|
694
|
-
* capitalise('BADGER'); // Badger
|
|
695
|
-
*/
|
|
696
|
-
function capitalise(word) {
|
|
697
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
/**
|
|
701
|
-
* Convert a snake case string to studly caps
|
|
702
|
-
* @param {String} [snake] - word to capitalise
|
|
703
|
-
* @return {String} capitalised string
|
|
704
|
-
* @example
|
|
705
|
-
* snakeToStudly('happy_badger_dance'); // HappyBadgerDance
|
|
706
|
-
* @example
|
|
707
|
-
* snakeToStudly('happy_badger/dance'); // HappyBadger/Dance
|
|
708
|
-
*/
|
|
709
|
-
function snakeToStudly(snake) {
|
|
710
|
-
return snake.split('/').map(
|
|
711
|
-
// each segment can be like foo_bar which we convert to FooBar
|
|
712
|
-
segment => segment.split('_').map(capitalise).join('')
|
|
713
|
-
).join('/');
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* Convert a snake case string to camel case
|
|
718
|
-
* @param {String} [snake] - word to capitalise
|
|
719
|
-
* @return {String} capitalised string
|
|
720
|
-
* @example
|
|
721
|
-
* snakeToCamel('happy_badger_dance'); // happyBadgerDance
|
|
722
|
-
* @example
|
|
723
|
-
* snakeToCamel('happy_badger/dance'); // happyBadger/dance
|
|
724
|
-
*/
|
|
725
|
-
function snakeToCamel(snake) {
|
|
726
|
-
return snake.split('/').map(
|
|
727
|
-
// each segment can be like foo_bar which we convert to FooBar
|
|
728
|
-
segment => segment.split('_').map((i, n) => n ? capitalise(i) : i).join('')
|
|
729
|
-
).join('/');
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* Assert that a parameter object contains an item with a defined/non-null value
|
|
734
|
-
* @param {Object} params={} - parameters object
|
|
735
|
-
* @param {String} name - parameter that must be included
|
|
736
|
-
* @return {any} the parameter value
|
|
737
|
-
* @throws {Error} if the parameter is not defined or null
|
|
738
|
-
* @example
|
|
739
|
-
* const foo = requiredParam({ foo: 10 }, 'foo');
|
|
740
|
-
*/
|
|
741
|
-
function requiredParam(params={}, name) {
|
|
742
|
-
const value = params[name];
|
|
743
|
-
if (hasValue(value)) {
|
|
744
|
-
return value;
|
|
745
|
-
}
|
|
746
|
-
else {
|
|
747
|
-
fail("Missing value for required parameter: ", name);
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Assert that a parameter object contains all specified item with a defined/non-null value
|
|
753
|
-
* @param {Object} params={} - parameters object
|
|
754
|
-
* @param {Array|String} names - parameters that must be included, as an Array or whitespace/comma delimited string (see {@link splitList})
|
|
755
|
-
* @return {Array} the parameter values
|
|
756
|
-
* @throws {Error} if any parameter is not defined or null
|
|
757
|
-
* @example
|
|
758
|
-
* const [foo, bar] = requiredParams({ foo: 10, bar: 20 }, 'foo bar');
|
|
759
|
-
*/
|
|
760
|
-
function requiredParams(params={}, names) {
|
|
761
|
-
return splitList(names).map( name => requiredParam(params, name) );
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
/**
|
|
765
|
-
* An alias for {@link requiredParams} for people who don't like typing long names (and for symmetry with {@link anyParams}))
|
|
766
|
-
*/
|
|
767
|
-
const allParams=requiredParams;
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* Assert that a parameter object contains any of the specified items with a defined/non-null value
|
|
771
|
-
* @param {Object} params={} - parameters object
|
|
772
|
-
* @param {Array|String} names - parameters of which at least one must be included, as an Array or whitespace/comma delimited string (see {@link splitList})
|
|
773
|
-
* @return {Array} the parameter values
|
|
774
|
-
* @throws {Error} if any parameter is not defined or null
|
|
775
|
-
* @example
|
|
776
|
-
* const [foo, bar] = anyParams({ foo: 10, wiz: 99 }, 'foo bar');
|
|
777
|
-
*/
|
|
778
|
-
function anyParams(params, names) {
|
|
779
|
-
let found = false;
|
|
780
|
-
const nlist = splitList(names);
|
|
781
|
-
const values = nlist.map(
|
|
782
|
-
name => {
|
|
783
|
-
const value = params[name];
|
|
784
|
-
if (hasValue(value)) {
|
|
785
|
-
found = true;
|
|
786
|
-
}
|
|
787
|
-
return value;
|
|
788
|
-
}
|
|
789
|
-
);
|
|
790
|
-
return found
|
|
791
|
-
? values
|
|
792
|
-
: fail("Missing value for one of: ", joinListOr(nlist));
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
const defaults = {
|
|
796
|
-
codecs: 'yaml json',
|
|
797
|
-
};
|
|
798
|
-
|
|
799
|
-
class Config {
|
|
800
|
-
constructor(params={}) {
|
|
801
|
-
const options = { ...defaults, ...params };
|
|
802
|
-
const [rootDir] = allParams(options, 'dir');
|
|
803
|
-
const [codec, codecs] = anyParams(options, 'codec codecs');
|
|
804
|
-
|
|
805
|
-
this.state = {
|
|
806
|
-
dir: dir(rootDir),
|
|
807
|
-
codecs: splitList(codecs) || [codec],
|
|
808
|
-
};
|
|
809
|
-
|
|
810
|
-
addDebug(this, options.debug, options.debugPrefix, options.debugColor);
|
|
811
|
-
this.debug('root dir: ', this.state.dir.path());
|
|
812
|
-
this.debug('codecs: ', this.state.codecs);
|
|
813
|
-
}
|
|
814
|
-
async file(uri) {
|
|
815
|
-
for (let codec of this.state.codecs) {
|
|
816
|
-
const path = uri + '.' + codec;
|
|
817
|
-
const file = this.state.dir.file(path, { codec });
|
|
818
|
-
this.debug('looking for config file: ', file.path());
|
|
819
|
-
if (await file.exists()) {
|
|
820
|
-
this.debug('config file exists: ', file.path());
|
|
821
|
-
return file;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
return undefined;
|
|
825
|
-
}
|
|
826
|
-
async config(uri, defaults) {
|
|
827
|
-
const file = await this.file(uri);
|
|
828
|
-
return file
|
|
829
|
-
? await file.read()
|
|
830
|
-
: (defaults || fail("No configuration file for " + uri))
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const config = options => new Config(options);
|
|
835
|
-
|
|
836
|
-
const defaults$1 = {
|
|
837
|
-
config: {
|
|
838
|
-
dir: 'config',
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
class Workspace {
|
|
842
|
-
constructor(props={}) {
|
|
843
|
-
const rootDir = dir(requiredParam(props, 'dir'));
|
|
844
|
-
const cfgDir = rootDir.dir(props.config?.dir || defaults$1.config.dir);
|
|
845
|
-
const cfgOpts = { ...defaults$1.config, ...(props.config||{}), dir: cfgDir };
|
|
846
|
-
const cfgObj = config(cfgOpts);
|
|
847
|
-
|
|
848
|
-
this.state = {
|
|
849
|
-
rootDir: rootDir,
|
|
850
|
-
configDir: cfgDir,
|
|
851
|
-
config: cfgObj
|
|
852
|
-
};
|
|
853
|
-
|
|
854
|
-
addDebug(this, props.debug, props.debugPrefix, props.debugColor);
|
|
855
|
-
this.debug('root dir: ', rootDir.path());
|
|
856
|
-
this.debug('config dir: ', cfgDir.path());
|
|
857
|
-
}
|
|
858
|
-
dir(path, options) {
|
|
859
|
-
this.debug("dir(%s, %o)", path, options);
|
|
860
|
-
return hasValue(path)
|
|
861
|
-
? this.state.rootDir(path, options)
|
|
862
|
-
: this.state.rootDir;
|
|
863
|
-
}
|
|
864
|
-
configDir(path, options) {
|
|
865
|
-
this.debug("configDir(%s, %o)", path, options);
|
|
866
|
-
return hasValue(path)
|
|
867
|
-
? this.state.configDir(path, options)
|
|
868
|
-
: this.state.configDir;
|
|
869
|
-
}
|
|
870
|
-
config(uri, defaults) {
|
|
871
|
-
this.debug("config(%s, %o)", uri, defaults);
|
|
872
|
-
return hasValue(uri)
|
|
873
|
-
? this.state.config.config(uri, defaults)
|
|
874
|
-
: this.state.config;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
const workspace = props => new Workspace(props);
|
|
879
|
-
|
|
880
|
-
exports.Config = Config;
|
|
881
|
-
exports.Path = Path;
|
|
882
|
-
exports.Workspace = Workspace;
|
|
883
|
-
exports.allParams = allParams;
|
|
884
|
-
exports.anyParams = anyParams;
|
|
885
|
-
exports.bin = bin;
|
|
886
|
-
exports.capitalise = capitalise;
|
|
887
|
-
exports.codec = codec$2;
|
|
888
|
-
exports.codecs = codecs;
|
|
889
|
-
exports.config = config;
|
|
890
|
-
exports.cwd = cwd;
|
|
891
|
-
exports.dir = dir;
|
|
892
|
-
exports.doNothing = doNothing;
|
|
893
|
-
exports.fail = fail;
|
|
894
|
-
exports.file = file;
|
|
895
|
-
exports.hasValue = hasValue;
|
|
896
|
-
exports.haveValue = haveValue;
|
|
897
|
-
exports.isArray = isArray;
|
|
898
|
-
exports.isFunction = isFunction;
|
|
899
|
-
exports.isNull = isNull;
|
|
900
|
-
exports.isObject = isObject;
|
|
901
|
-
exports.isString = isString;
|
|
902
|
-
exports.isUndefined = isUndefined;
|
|
903
|
-
exports.joinList = joinList;
|
|
904
|
-
exports.joinListAnd = joinListAnd;
|
|
905
|
-
exports.joinListOr = joinListOr;
|
|
906
|
-
exports.noValue = noValue;
|
|
907
|
-
exports.requiredParam = requiredParam;
|
|
908
|
-
exports.requiredParams = requiredParams;
|
|
909
|
-
exports.rethrow = rethrow;
|
|
910
|
-
exports.snakeToCamel = snakeToCamel;
|
|
911
|
-
exports.snakeToStudly = snakeToStudly;
|
|
912
|
-
exports.splitList = splitList;
|
|
913
|
-
exports.workspace = workspace;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("js-yaml"),e=require("node:process"),r=require("node:path"),i=require("node:fs/promises");function s(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}function o(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,i.get?i:{enumerable:!0,get:function(){return t[r]}})}})),e.default=t,Object.freeze(e)}var n=s(t),a=s(e),c=s(r);function u(t){return"string"==typeof t}function d(t){return Array.isArray(t)}function h(t){return"object"==typeof t&&!d(t)&&!f(t)}function p(t){return void 0===t}function f(t){return null===t}function l(t){return!(p(t)||f(t))}function g(...t){throw new Error(t.join(""))}function b(t){throw t}function x(){}const y={reset:0,bold:1,bright:1,dark:2,black:0,red:1,green:2,yellow:3,blue:4,magenta:5,cyan:6,grey:7,white:8,fg:30,bg:40},m=(t,e="fg")=>{let r=[],i=t.split(/ /,2);const s=i.pop(),o=(e?y[e]:0)+y[s];if(r.push(o),i.length){const t=i.length?i.shift():"dark";r.push(y[t])}return"["+r.join(";")+"m"};function w(t,e="",r){return t?e?(t,...i)=>console.log("%s"+e+"%s"+t,r?((t={})=>{const e=h(t)?t:{fg:t};let r=[];return e.bg&&r.push(m(e.bg,"bg")),e.fg&&r.push(m(e.fg,"fg")),r.join("")})(r):"",m("reset"),...i):console.log.bind(console):x}function j(t,e,r="",i){t.debug=w(e,r,i)}const P={json:{encode:t=>JSON.stringify(t),decode:t=>JSON.parse(t)},yaml:{encode:t=>n.default.dump(t),decode:t=>n.default.load(t)}},v=t=>P[t.toLowerCase()],k={encoding:"utf8"};class E{constructor(t,e={}){t instanceof E&&(t=t.path()),this.state={path:t,options:{...k,...e}},j(this,e.debug,e.debugPrefix||"Path",e.debugColor)}path(){return this.state.path}relativePath(...t){return c.default.join(this.state.path,...t)}options(t={}){return{...this.state.options,...t}}async exists(){try{return await this.stat(),!0}catch(t){return"ENOENT"!==t.code&&b(t)}}async stat(){const t=await i.stat(this.state.path);return this.state.stats=t}unstat(){return this.state.stats=void 0,console.log("XXX unstat: ",this.state.stats),this}}class C extends E{directory(t){return q(c.default.dirname(this.state.path),t)}dir(...t){return this.directory(...t)}read(t){const e=this.options(t),r=i.readFile(this.state.path,e);return e.codec?r.then((t=>v(e.codec).decode(t))):r}write(t,e){const r=this.options(e),s=r.codec?v(r.codec).encode(t):t;return i.writeFile(this.state.path,s,r).then((()=>this))}async delete(t){return await i.rm(this.state.path,t),this}}const O=(t,e)=>new C(t,e);class D extends E{file(t,e){return this.debug("file(%s, %o)",t,e),O(this.relativePath(t),this.options(e))}directory(t,e){return this.debug("directory(%s, %o)",t,e),q(this.relativePath(t),this.options(e))}dir(t,e){return this.debug("dir(%s, %o)",t,e),this.directory(t,e)}parent(t){return this.debug("parent()"),this.directory("..",t)}async read(){return this.debug("read()"),await i.readdir(this.path())}async isEmpty(){this.debug("isEmpty()");return 0===(await this.read()).length}async notEmpty(){this.debug("notEmpty()");return!await this.isEmpty()}async empty(t={}){return this.debug("empty(%o)",t),await this.exists()&&await this.notEmpty()&&await i.rm(this.path(),t),this}async mkdir(t={}){this.debug("mkdir(%o)",t);return await this.exists()||await i.mkdir(this.path(),t),this}async rmdir(t={}){return this.debug("rmdir(%o)",t),t.empty&&await this.empty(t),await this.exists()&&await i.rmdir(this.path()),this}create(t={recursive:!0}){return this.debug("create(%o)",t),this.mkdir(t)}destroy(t={empty:!0,recursive:!0,force:!0}){return this.debug("destroy(%o)",t),this.rmdir(t)}async mustExist(t={}){return this.debug("mustExist(%o)",t),await this.exists()?this:t.mkdir?this.mkdir(t):t.create?this.create():void g("Directory does not exist: ",this.path())}}const q=(t,e)=>new D(t,e);function L(t){return u(t)?t.split(/,\s*|\s+/):d(t)?t:[t]}function N(t,e=" ",r=e){let i=[...t];const s=i.pop();return i.length?[i.join(e),s].join(r):s}function _(t,e=", ",r=" or "){return N(t,e,r)}function A(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}function M(t={},e){const r=t[e];if(l(r))return r;g("Missing value for required parameter: ",e)}function S(t={},e){return L(e).map((e=>M(t,e)))}const F=S;function T(t,e){let r=!1;const i=L(e),s=i.map((e=>{const i=t[e];return l(i)&&(r=!0),i}));return r?s:g("Missing value for one of: ",_(i))}const V={codecs:"yaml json"};class X{constructor(t={}){const e={...V,...t},[r]=F(e,"dir"),[i,s]=T(e,"codec codecs");this.state={dir:q(r),codecs:L(s)||[i]},j(this,e.debug,e.debugPrefix,e.debugColor),this.debug("root dir: ",this.state.dir.path()),this.debug("codecs: ",this.state.codecs)}async file(t){for(let e of this.state.codecs){const r=t+"."+e,i=this.state.dir.file(r,{codec:e});if(this.debug("looking for config file: ",i.path()),await i.exists())return this.debug("config file exists: ",i.path()),i}}async config(t,e){const r=await this.file(t);return r?await r.read():e||g("No configuration file for "+t)}}const J={dir:["lib","library","src","components"],ext:["js","mjs"]};class U{constructor(t={}){const e=q(M(t,"root")),r=t.directory||t.dir||t.dirs||J.dir,i=t.extension||t.ext||t.exts||J.ext,s=L(r).map((t=>e.dir(t))),o=L(i).map((t=>t.replace(/^\./,"")));this.state={dirs:s,exts:o},j(this,t.debug,t.debugPrefix,t.debugColor)}async dirs(){return this.state.dirsExist||(this.state.dirsExist=await this.dirsExist())}async dirsExist(){const t=this.state.dirs,e=await Promise.all(t.map((t=>t.exists())));return t.filter(((t,r)=>e[r]))}async lib(t){const e=await this.dirs(),r=this.state.exts;for(let i of e)for(let e of r){const r=i.file(t+"."+e);this.debug("looking for module %s as",t,r.path());if(await r.exists()){const t=await function(t){return Promise.resolve().then((function(){return o(require(t))}))}(r.path());return this.debug("loaded %s as",r.path()),t}}g("Library not found: ",t)}}const z={},W={dir:"config"};class B{constructor(t={}){const e=q(M(t,"dir")),r=e.dir(t.config?.dir||W.dir),i={...W,...t.config||{},dir:r},s=new X(i),o={...z,...t.library||{},root:e},n=new U(o);this.state={rootDir:e,config:s,library:n},j(this,t.debug,t.debugPrefix,t.debugColor),this.debug("root dir: ",e.path()),this.debug("config dir: ",r.path())}dir(t,e){return this.debug("dir(%s, %o)",t,e),l(t)?this.state.rootDir.dir(t,e):this.state.rootDir}file(t,e){return this.debug("file(%s, %o)",t,e),this.state.rootDir.file(t,e)}read(t,e){return this.debug("read(%s, %o)",t,e),this.file(t,e).read()}write(t,e,r){return this.debug("write(%s, %o, %o)",t,e,r),this.file(t,r).write(e)}configDir(t,e){return this.debug("configDir(%s, %o)",t,e),l(t)?this.state.configDir(t,e):this.state.configDir}async config(t,e){return this.debug("config(%s, %o)",t,e),l(t)?this.state.config.config(t,e):this.state.config}async lib(t){return this.state.library.lib(t)}async component(t,e){const r=await this.config(t,{}),i=await this.lib(r.component?.library||t),s=r.component?.export||"default";return new(i[s]||g("No '",s,"' export from component library: ",t))(this,{...r,...e})}}exports.Component=class{constructor(t,e={}){this.workspace=t,this.props=e,j(this,e.debug,e.debugPrefix,e.debugColor),this.initComponent(e)}initComponent(){}},exports.Config=X,exports.Library=U,exports.Path=E,exports.Workspace=B,exports.allParams=F,exports.anyParams=T,exports.bin=(t,e)=>q(c.default.dirname(t.replace(/^file:\/\//,"")),e),exports.capitalise=A,exports.codec=v,exports.codecs=P,exports.config=t=>new X(t),exports.cwd=t=>q(a.default.cwd(),t),exports.dir=q,exports.doNothing=x,exports.fail=g,exports.file=O,exports.hasValue=l,exports.haveValue=function(...t){return t.every((t=>l(t)))},exports.isArray=d,exports.isFunction=function(t){return"function"==typeof t},exports.isNull=f,exports.isObject=h,exports.isString=u,exports.isUndefined=p,exports.joinList=N,exports.joinListAnd=function(t,e=", ",r=" and "){return N(t,e,r)},exports.joinListOr=_,exports.library=t=>new U(t),exports.noValue=function(t){return!l(t)},exports.requiredParam=M,exports.requiredParams=S,exports.rethrow=b,exports.snakeToCamel=function(t){return t.split("/").map((t=>t.split("_").map(((t,e)=>e?A(t):t)).join(""))).join("/")},exports.snakeToStudly=function(t){return t.split("/").map((t=>t.split("_").map(A).join(""))).join("/")},exports.splitList=L,exports.workspace=t=>new B(t);
|
|
2
|
+
//# sourceMappingURL=badger.cjs.js.map
|