view-ignored 0.2.1 → 0.3.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.
Files changed (58) hide show
  1. package/README.md +23 -27
  2. package/bin/viewig +3 -1
  3. package/out/src/browser/binds/index.d.ts +40 -21
  4. package/out/src/browser/binds/index.js +62 -48
  5. package/out/src/browser/binds/plugins/git.d.ts +22 -3
  6. package/out/src/browser/binds/plugins/git.js +57 -21
  7. package/out/src/browser/binds/plugins/npm.d.ts +36 -9
  8. package/out/src/browser/binds/plugins/npm.js +125 -59
  9. package/out/src/browser/binds/plugins/vsce.d.ts +24 -8
  10. package/out/src/browser/binds/plugins/vsce.js +56 -16
  11. package/out/src/browser/binds/plugins/yarn.d.ts +5 -10
  12. package/out/src/browser/binds/plugins/yarn.js +18 -68
  13. package/out/src/browser/binds/scanner.d.ts +56 -0
  14. package/out/src/browser/binds/scanner.js +134 -0
  15. package/out/src/browser/binds/targets.d.ts +35 -11
  16. package/out/src/browser/binds/targets.js +10 -17
  17. package/out/src/browser/errors.d.ts +58 -7
  18. package/out/src/browser/errors.js +40 -12
  19. package/out/src/browser/filtering.d.ts +15 -0
  20. package/out/src/browser/filtering.js +12 -0
  21. package/out/src/browser/fs/directory.d.ts +181 -0
  22. package/out/src/browser/fs/directory.js +235 -0
  23. package/out/src/browser/{fileinfo.d.ts → fs/file-info.d.ts} +38 -27
  24. package/out/src/browser/fs/file-info.js +86 -0
  25. package/out/src/browser/fs/file.d.ts +41 -0
  26. package/out/src/browser/fs/file.js +43 -0
  27. package/out/src/browser/fs/index.d.ts +4 -0
  28. package/out/src/browser/fs/index.js +4 -0
  29. package/out/src/browser/fs/source-info.d.ts +29 -0
  30. package/out/src/browser/fs/source-info.js +31 -0
  31. package/out/src/browser/index.d.ts +2 -2
  32. package/out/src/browser/index.js +2 -2
  33. package/out/src/browser/lib.d.ts +102 -101
  34. package/out/src/browser/lib.js +86 -120
  35. package/out/src/browser/sorting.d.ts +22 -2
  36. package/out/src/browser/sorting.js +37 -32
  37. package/out/src/browser/styling.d.ts +41 -15
  38. package/out/src/browser/styling.js +28 -97
  39. package/out/src/cli.d.ts +73 -34
  40. package/out/src/cli.js +308 -155
  41. package/out/src/config.d.ts +163 -65
  42. package/out/src/config.js +285 -171
  43. package/out/src/errors.d.ts +7 -0
  44. package/out/src/errors.js +1 -0
  45. package/out/src/index.d.ts +2 -2
  46. package/out/src/index.js +2 -2
  47. package/out/src/lib.d.ts +4 -4
  48. package/out/src/lib.js +4 -4
  49. package/out/src/styling.d.ts +10 -4
  50. package/out/src/styling.js +46 -33
  51. package/package.json +37 -24
  52. package/out/src/bin.d.ts +0 -2
  53. package/out/src/bin.js +0 -3
  54. package/out/src/browser/fileinfo.js +0 -78
  55. package/out/src/browser/scanner.d.ts +0 -103
  56. package/out/src/browser/scanner.js +0 -161
  57. package/out/src/browser/sourceinfo.d.ts +0 -62
  58. package/out/src/browser/sourceinfo.js +0 -107
package/out/src/cli.js CHANGED
@@ -1,249 +1,402 @@
1
- import fs from "fs";
2
- import { Chalk } from "chalk";
3
- import { Argument, InvalidArgumentError, Option, Command } from "commander";
4
- import * as Config from "./config.js";
5
- import { BuiltIns, loadPluginsQueue, targetGet } from "./browser/binds/index.js";
6
- import { decorCondition, formatFiles } from "./browser/styling.js";
7
- import { ErrorNoSources, scanProject, Sorting } from "./lib.js";
8
- import { boxError, formatConfigConflicts } from "./styling.js";
9
- import ora from "ora";
10
- import packageJSON from "../package.json" with { type: "json" };
11
- import { format } from "util";
12
- export const { version } = packageJSON;
1
+ /* eslint-disable unicorn/no-process-exit */
2
+ import { format } from 'node:util';
3
+ import * as process from 'node:process';
4
+ import { icons } from '@m234/nerd-fonts';
5
+ import { Chalk } from 'chalk';
6
+ import { Argument, InvalidArgumentError, Option, Command, } from 'commander';
7
+ import { Listr } from 'listr2';
8
+ import * as Config from './config.js';
9
+ import { targetGet, loadPlugins, loadBuiltIns, targetList, } from './browser/binds/index.js';
10
+ import { decorCondition, formatFiles, } from './browser/styling.js';
11
+ import { sortNameList } from './browser/sorting.js';
12
+ import { boxError, decorNameList, highlight, stringTime, styleNameList, } from './styling.js';
13
+ import { Directory, package_, makeOptionsReal, scan, Sorting, ViewIgnoredError, } from './lib.js';
14
+ import { filterNameList } from './browser/filtering.js';
15
+ /**
16
+ * @private
17
+ */
13
18
  export function logError(message, options) {
14
- console.log(boxError(message, { noColor: getColorLevel(program.opts()) === 0, ...options }));
19
+ console.log(boxError(message, { ...options }));
15
20
  }
16
21
  /**
17
- * Use it instead of {@link program}.parse()
22
+ * Use it instead of {@link program.parse}.
23
+ * @private
18
24
  */
19
25
  export async function programInit() {
20
- Config.configManager.load();
21
- program.version('v' + version, '-v');
22
- program.addOption(new Option("--no-color", 'force disable colors').default(false));
23
- Config.configValueLinkCliOption("plugins", program, new Option('--plugins <modules...>', 'import modules to modify behavior'), parseArgArrStr);
24
- Config.configValueLinkCliOption("color", program, new Option("--color <level>", 'the interface color level'), parseArgInt);
25
- Config.configValueLinkCliOption("decor", program, new Option("--decor <decor>", "the interface decorations"));
26
- Config.configValueLinkCliOption("parsable", scanProgram, new Option('-p, --parsable [parsable]', "print parsable text"), parseArgBool);
27
- Config.configValueLinkCliOption("target", scanProgram, new Option("-t, --target <ignorer>", 'the scan target'));
28
- Config.configValueLinkCliOption("filter", scanProgram, new Option("--filter <filter>", 'filter results'));
29
- Config.configValueLinkCliOption("sort", scanProgram, new Option("--sort <sorter>", 'sort results'));
30
- Config.configValueLinkCliOption("style", scanProgram, new Option("--style <style>", 'results view mode'));
31
- Config.configValueLinkCliOption("depth", scanProgram, new Option("--depth <depth>", 'the max results depth'), parseArgInt);
32
- Config.configValueLinkCliOption("showSources", scanProgram, new Option("--show-sources [show]", 'show scan sources'), parseArgBool);
33
- program.parseOptions(process.argv);
34
- const flags = program.opts();
35
- const chalk = getChalk(flags);
36
- try {
37
- Config.configManager.load();
38
- }
39
- catch (error) {
40
- formatConfigConflicts(chalk, flags.decor, error);
41
- return;
42
- }
43
26
  try {
44
- await BuiltIns;
45
- const configPlugins = Config.configManager.get('plugins');
46
- const loaded = await loadPluginsQueue(flags.plugins);
47
- for (const load of loaded) {
48
- if (!load.isLoaded) {
49
- logError(format(load.exports), {
50
- title: `Unable to load plugin '${load.moduleName}' ` + (configPlugins.includes(load.moduleName)
51
- ? '(imported by ' + Config.configManager.filePath + ')'
52
- : '(imported by --plugins option)')
53
- });
27
+ const { configManager, configDefault, configValueArray, configValueString, configValueLiteral } = Config;
28
+ const flags = program.optsWithGlobals();
29
+ const chalk = new Chalk();
30
+ configManager.keySetValidator('plugins', configDefault.plugins, configValueArray(configValueString()));
31
+ const loadResultConfig = configManager.load();
32
+ const builtInPlugins = await loadBuiltIns();
33
+ const configPlugins = configManager.get('plugins');
34
+ const loadResultPlugins = (flags.plugins ? await loadPlugins(flags.plugins) : []).concat(builtInPlugins);
35
+ for (const loadResult of loadResultPlugins) {
36
+ if (loadResult.isLoaded) {
37
+ continue;
38
+ }
39
+ logError(format(loadResult.exports), {
40
+ title: `view-ignored - Plugin loading failed: '${loadResult.resource}' ${builtInPlugins.includes(loadResult)
41
+ ? '(imported from built-ins)'
42
+ : (configPlugins.includes(loadResult.resource)
43
+ ? '(imported by ' + configManager.path + ')'
44
+ : '(imported by --plugins option)')}.`,
45
+ });
46
+ }
47
+ const targets = targetList();
48
+ configManager.keySetValidator('target', configDefault.target, configValueLiteral(targets));
49
+ {
50
+ const title = 'view-ignored - Configuration loading failed.';
51
+ const infoSymbol = decorCondition(flags.decor, { ifEmoji: 'ℹ️', ifNerd: icons['nf-seti-info'].char, postfix: ' ' });
52
+ const errorIcon = decorCondition(flags.decor, {
53
+ ifNerd: icons['nf-seti-error'].char, ifEmoji: '⚠️', postfix: ' ',
54
+ });
55
+ const footer = `\n\n${chalk.blue(infoSymbol)}Configuration path: ${Config.configManager.path}`;
56
+ if (typeof loadResultConfig === 'string') {
57
+ logError(loadResultConfig + footer, { title });
58
+ process.exit(1);
59
+ }
60
+ if (loadResultConfig && loadResultConfig?.size > 0) {
61
+ const propertiesErrors = Array.from(loadResultConfig.entries()).map(([key, message]) => `${Config.configManager.getPairString(key, { chalk, types: false, real: true })} - ${chalk.red(errorIcon)}${message}`).join('\n');
62
+ logError(`Invalid properties:\n${propertiesErrors}${footer}`, { title });
63
+ process.exit(1);
54
64
  }
55
65
  }
66
+ program.version('v' + package_.version, '-v');
67
+ configManager.setOption('noColor', program, new Option('--no-color', 'force disable colors'), parseArgumentBoolean);
68
+ configManager.setOption('posix', program, new Option('--posix', 'use unix path separator'), parseArgumentBoolean);
69
+ configManager.setOption('plugins', program, new Option('--plugins <modules...>', 'import modules to modify behavior'), parseArgumentArrayString);
70
+ configManager.setOption('decor', program, new Option('--decor <decor>', 'the interface decorations'), createArgumentParserStringLiteral([...decorNameList]));
71
+ configManager.setOption('parsable', program, new Option('-p, --parsable [parsable]', 'print parsable text'), parseArgumentBoolean);
72
+ configManager.setOption('target', scanProgram, new Option('-t, --target <ignorer>', 'the scan target'), createArgumentParserStringLiteral(targets));
73
+ configManager.setOption('filter', scanProgram, new Option('--filter <filter>', 'filter results'), createArgumentParserStringLiteral([...filterNameList]));
74
+ configManager.setOption('sort', scanProgram, new Option('--sort <sorter>', 'sort results'), createArgumentParserStringLiteral([...sortNameList]));
75
+ configManager.setOption('style', scanProgram, new Option('--style <style>', 'results view mode'), createArgumentParserStringLiteral([...styleNameList]));
76
+ configManager.setOption('depth', scanProgram, new Option('--depth <depth>', 'the max results depth'), parseArgumentInteger);
77
+ configManager.setOption('showSources', scanProgram, new Option('--show-sources [show]', 'show scan sources'), parseArgumentBoolean);
78
+ configManager.setOption('concurrency', scanProgram, new Option('--concurrency [limit]', 'the limit for the signgle directory operations'), parseArgumentInteger);
79
+ program.parse();
56
80
  }
57
- catch (reason) {
58
- logError(format(reason));
81
+ catch (error) {
82
+ logError(format(error), { title: 'view-ignored - Fatal error.' });
59
83
  process.exit(1);
60
84
  }
61
- program.parse();
62
- }
63
- /** Chalk, but configured by view-ignored cli. */
64
- export function getColorLevel(flags) {
65
- const colorLevel = (flags.noColor ? 0 : Math.max(0, Math.min(Number(flags.color ?? 3), 3)));
66
- return colorLevel;
67
- }
68
- /** Chalk, but configured by view-ignored cli. */
69
- export function getChalk(flags) {
70
- const chalk = new Chalk({ level: getColorLevel(flags) });
71
- return chalk;
72
85
  }
73
86
  /**
74
87
  * `view-ignored` command-line programl
88
+ * @public
75
89
  */
76
90
  export const program = new Command();
77
91
  /**
78
92
  * Command-line 'scan' command.
93
+ * @public
79
94
  */
80
95
  export const scanProgram = program
81
- .command("scan")
96
+ .command('scan')
82
97
  .aliases(['sc'])
83
98
  .description('get ignored/included paths')
84
99
  .action(actionScan);
85
100
  /**
86
- * Command-line 'config' command.
87
- */
101
+ * Command-line 'config' command.
102
+ * @public
103
+ */
88
104
  export const cfgProgram = program
89
- .command("config")
105
+ .command('config')
90
106
  .alias('cfg')
91
107
  .description('cli config manipulation');
92
108
  /**
93
109
  * Command-line argument: key=value pair.
94
- * @see {@link parseArgKeyVal}
110
+ * @see {@link parseArgumentKeyValue}
111
+ * @public
95
112
  */
96
- export const argConfigKeyVal = new Argument('[pair]', "the configuration entry key=value'").argParser(parseArgKeyVal);
113
+ export const argumentConfigKeyValue = new Argument('[pair]', 'the configuration entry key=value\'').argParser(parseArgumentKeyValue);
97
114
  /**
98
115
  * Command-line argument: config property.
99
116
  * @see {@link Config.configKeyList}
117
+ * @public
118
+ */
119
+ export const argumentConfigKey = new Argument('[key]', 'the configuration setting name').choices(Config.configKeyList);
120
+ /**
121
+ * @public
122
+ */
123
+ export const cfgRealOption = new Option('--real', 'use default value(s) as fallback').default(false);
124
+ /**
125
+ * @public
100
126
  */
101
- export const argConfigKey = new Argument('[key]', 'the configuration setting name').choices(Config.configKeyList);
102
- export const cfgGetOption = new Option('--real', 'use default value(s) as fallback').default(false);
127
+ export const cfgTypesOption = new Option('--types', 'use default value(s) as fallback').default(false);
103
128
  cfgProgram
104
129
  .command('path').description('print the config file path')
105
130
  .action(actionCfgPath);
106
131
  cfgProgram
107
- .command('set').description("set config property using syntax 'key=value'")
108
- .addArgument(argConfigKeyVal)
132
+ .command('set').description('set config property using syntax \'key=value\'')
133
+ .addArgument(argumentConfigKeyValue)
134
+ .addOption(cfgRealOption)
135
+ .addOption(cfgTypesOption)
109
136
  .action(actionCfgSet);
110
137
  cfgProgram
111
- .command('unset').description("delete configuration value if cpecified, otherwise delete entire config")
112
- .addArgument(argConfigKey)
138
+ .command('unset').description('delete configuration value if cpecified, otherwise delete entire config')
139
+ .addArgument(argumentConfigKey)
140
+ .addOption(cfgRealOption)
141
+ .addOption(cfgTypesOption)
113
142
  .action(actionCfgUnset);
114
143
  cfgProgram
115
144
  .command('get').description('print configuration value(s). You can use --real option to view real values')
116
- .addOption(cfgGetOption)
117
- .addArgument(argConfigKey)
145
+ .addOption(cfgRealOption)
146
+ .addOption(cfgTypesOption)
147
+ .addArgument(argumentConfigKey)
118
148
  .action(actionCfgGet);
119
- export function parseArgArrStr(arg) {
120
- return arg.split(/[ ,|]/).filter(Boolean);
149
+ /**
150
+ * @public
151
+ */
152
+ export function parseArgumentArrayString(argument) {
153
+ return argument.split(/[ ,|]/).filter(Boolean);
121
154
  }
122
- export function parseArgBool(arg) {
123
- if (!Config.boolValues.includes(arg)) {
124
- throw new InvalidArgumentError(`Got invalid value '${arg}'. Should be a boolean.`);
155
+ /**
156
+ * @public
157
+ */
158
+ export function parseArgumentBoolean(argument) {
159
+ const errorMessage = Config.configValueSwitch()(argument);
160
+ if (errorMessage !== undefined) {
161
+ throw new InvalidArgumentError(errorMessage);
125
162
  }
126
- return Config.trueValues.includes(arg);
163
+ return Config.switchTrueValues.includes(argument);
127
164
  }
128
- export function parseArgInt(arg) {
129
- const num = parseInt(arg);
130
- if (!Number.isInteger(num)) {
131
- throw new InvalidArgumentError(`Got invalid value '${num}'. Should be an integer.`);
165
+ /**
166
+ * @public
167
+ */
168
+ export function parseArgumentInteger(argument) {
169
+ const value = Number.parseInt(argument, 10);
170
+ const errorMessage = Config.configValueInteger()(value);
171
+ if (errorMessage !== undefined) {
172
+ throw new InvalidArgumentError(errorMessage);
132
173
  }
133
- return num;
174
+ return value;
175
+ }
176
+ /**
177
+ * @public
178
+ */
179
+ export function createArgumentParserStringLiteral(choices) {
180
+ return function (argument) {
181
+ const errorMessage = Config.configValueLiteral(choices)(argument);
182
+ if (errorMessage !== undefined) {
183
+ throw new InvalidArgumentError(errorMessage);
184
+ }
185
+ return argument;
186
+ };
134
187
  }
135
- export function parseArgKey(key) {
136
- if (!Config.isConfigKey(key)) {
137
- throw new InvalidArgumentError(`Got invalid key '${key}'. Allowed config keys are ${Config.configKeyList.join(', ')}.`);
188
+ /**
189
+ * @public
190
+ */
191
+ export function parseArgumentKey(key) {
192
+ const errorMessage = Config.configManager.checkKey(key);
193
+ if (errorMessage !== undefined) {
194
+ throw new InvalidArgumentError(errorMessage);
138
195
  }
139
196
  return key;
140
197
  }
141
- export function parseArgKeyVal(pair) {
198
+ /**
199
+ * @public
200
+ */
201
+ export function parseArgumentKeyValue(pair) {
142
202
  const result = pair.split('=');
143
- const [key] = result;
144
- if (result.length !== 2) {
145
- throw new InvalidArgumentError(`Expected 'key=value'.`);
146
- }
147
- if (!Config.isConfigKey(key)) {
148
- throw new InvalidArgumentError(`Got invalid key '${key}'. Allowed config keys are ${Config.configKeyList.join(', ')}.`);
203
+ if (result.length > 2) {
204
+ throw new InvalidArgumentError('Expected \'key=value\'.');
149
205
  }
150
- const option = Config.configValueGetCliOption(key);
151
- const val = option.parseArg?.(result[1], undefined) ?? result[1];
152
- if (!Config.isConfigValue(key, val)) {
153
- const list = Config.configValueList(key);
154
- if (list === undefined) {
155
- throw new InvalidArgumentError(`Invalid value '${val}' for the key '${key}'.`);
156
- }
157
- if (Array.isArray(list)) {
158
- throw new InvalidArgumentError(`Invalid value '${val}' for the key '${key}'. Allowed config values are ${list.join(', ')}`);
206
+ if (result.length !== 2) {
207
+ const [key] = result;
208
+ const message = Config.configManager.checkKey(key);
209
+ if (message !== undefined) {
210
+ throw new InvalidArgumentError(`Expected 'key=value'. ${message}`);
159
211
  }
160
- throw new InvalidArgumentError(`Invalid value '${val}' for the key '${key}'. ${list}`);
161
212
  }
162
- return [key, val];
213
+ const [key, valueString] = result;
214
+ const { parseArg: parseArgument } = Config.configManager.getOption(key) ?? {};
215
+ const value = parseArgument?.(valueString, undefined) ?? valueString;
216
+ const message = Config.configManager.checkValue(key, value);
217
+ if (message !== undefined) {
218
+ throw new InvalidArgumentError(`Expected 'key=value'. ${message}`);
219
+ }
220
+ return [key, value];
163
221
  }
164
222
  /**
165
223
  * Command-line 'scan' command action.
224
+ * @public
166
225
  */
167
226
  export async function actionScan() {
168
- const flagsGlobal = scanProgram.optsWithGlobals();
227
+ const flags = scanProgram.optsWithGlobals();
169
228
  const cwd = process.cwd();
170
229
  const start = Date.now();
171
- const chalk = getChalk(program.opts());
172
- const fileInfoListP = scanProject(flagsGlobal.target, { filter: flagsGlobal.filter, maxDepth: flagsGlobal.depth })
173
- .catch((error) => {
174
- spinner.stop();
175
- spinner.clear();
176
- if (!(error instanceof ErrorNoSources)) {
177
- throw error;
178
- }
179
- console.error(`Bad sources for ${flagsGlobal.target}: ${ErrorNoSources.walk(flagsGlobal.target)}`);
230
+ const chalk = new Chalk();
231
+ const bind = targetGet(flags.target);
232
+ if (bind === undefined) {
233
+ logError(format(`Bad target '${flags.target}'. Registered targets: ${targetList().join(', ')}.`), { title: 'view-ignored - Fatal error.' });
180
234
  process.exit(1);
235
+ }
236
+ const optionsReal = makeOptionsReal({ posix: flags.posix || flags.parsable, concurrency: flags.concurrency });
237
+ const stream = Directory.deepStream('.', {
238
+ concurrency: optionsReal.concurrency,
239
+ cwd: optionsReal.cwd,
240
+ modules: optionsReal.modules,
181
241
  });
182
- if (flagsGlobal.parsable) {
183
- console.log((await fileInfoListP).map(fi => fi.filePath + (flagsGlobal.showSources ? '<' + fi.source.sourcePath : '')).join('|'));
184
- return;
242
+ if (flags.parsable) {
243
+ const fileInfoList = await scan(stream, {
244
+ ...optionsReal,
245
+ target: flags.target,
246
+ filter: flags.filter,
247
+ maxDepth: flags.depth,
248
+ });
249
+ console.log(fileInfoList.map(fileInfo => fileInfo.relativePath + (flags.showSources && fileInfo.source !== undefined ? '<' + (fileInfo.source.relativePath) : '')).join(','));
185
250
  }
186
- const spinner = ora({ text: cwd, color: 'white' });
187
- spinner.start();
188
- spinner.suffixText = "Generating...";
189
- const fileInfoList = await fileInfoListP;
190
- const sorter = Sorting[flagsGlobal.sort];
191
- const cache = new Map(fileInfoList.map(String).map(filePath => [filePath, fs.statSync(filePath).mtime.getTime()]));
192
- const lookedSorted = fileInfoList.sort((a, b) => sorter(a.toString(), b.toString(), cache));
193
- const files = formatFiles(lookedSorted, { chalk, style: flagsGlobal.style, decor: flagsGlobal.decor, showSources: flagsGlobal.showSources });
194
- const checkSymbol = decorCondition(flagsGlobal.decor, { ifEmoji: '✅', ifNerd: '\uf00c', postfix: ' ' });
195
- const fastSymbol = decorCondition(flagsGlobal.decor, { ifEmoji: '⚡', ifNerd: '\udb85\udc0c' });
196
- const bind = targetGet(flagsGlobal.target);
197
- const name = typeof bind.name === "string" ? bind.name : decorCondition(flagsGlobal.decor, bind.name);
198
- const infoSymbol = decorCondition(flagsGlobal.decor, { ifEmoji: 'ℹ️', ifNerd: '\ue66a', postfix: ' ' });
199
- const time = Date.now() - start;
200
- let message = '';
201
- message += files;
202
- message += '\n';
203
- message += `${chalk.green(checkSymbol)}Done in ${time < 400 ? chalk.yellow(fastSymbol) : ''}${time}ms.`;
204
- message += '\n';
205
- message += `${fileInfoList.length} files listed for ${name} (${flagsGlobal.filter}).`;
206
- message += '\n';
207
- if (bind.testCommand) {
208
- message += '\n';
209
- message += `${chalk.blue(infoSymbol)}You can use '${chalk.magenta(bind.testCommand)}' to check if the list is valid.`;
251
+ else {
252
+ let name = decorCondition(flags.decor, { ifNerd: bind.icon?.char, postfix: ' ' }) + bind.name;
253
+ if (bind.icon?.color !== undefined) {
254
+ name = chalk.hex('#' + bind.icon.color.toString(16))(name);
255
+ }
256
+ const context = {
257
+ count: {
258
+ files: 0, directories: 0, current: 0, total: 0,
259
+ },
260
+ fileInfoList: [],
261
+ stream,
262
+ message: '',
263
+ reading: new Promise(resolve => {
264
+ stream.on('end', data => {
265
+ resolve(data);
266
+ });
267
+ }),
268
+ };
269
+ const progress = new Listr([
270
+ {
271
+ title: `${name} ${chalk.hex('#73A7DE')(flags.filter)} ${cwd}`,
272
+ async task(context, task) {
273
+ return task.newListr([
274
+ {
275
+ title: 'Preparing',
276
+ async task() {
277
+ const { progress } = await context.reading;
278
+ Object.assign(context.count, progress);
279
+ },
280
+ },
281
+ {
282
+ title: 'Scanning',
283
+ async task() {
284
+ context.fileInfoList = await scan(context.stream, {
285
+ ...optionsReal,
286
+ target: flags.target,
287
+ filter: flags.filter,
288
+ maxDepth: flags.depth,
289
+ });
290
+ },
291
+ },
292
+ {
293
+ title: 'Printing',
294
+ async task() {
295
+ const sorter = Sorting[flags.sort];
296
+ const cache = new Map();
297
+ if (flags.sort === 'modified') {
298
+ const { tree } = await context.reading;
299
+ await tree.deepModifiedTime(cache, optionsReal);
300
+ }
301
+ const time = Date.now() - start;
302
+ const fileInfoListSorted = context.fileInfoList.sort((a, b) => sorter(String(a), String(b), cache));
303
+ const files = formatFiles(fileInfoListSorted, {
304
+ chalk,
305
+ posix: flags.posix,
306
+ style: flags.style,
307
+ decor: flags.decor,
308
+ showSources: flags.showSources,
309
+ });
310
+ const fastSymbol = decorCondition(flags.decor, { ifEmoji: '⚡', ifNerd: icons['nf-md-lightning_bolt'].char });
311
+ const infoSymbol = decorCondition(flags.decor, { ifEmoji: 'ℹ️', ifNerd: icons['nf-seti-info'].char, postfix: ' ' });
312
+ let message = '';
313
+ message += files;
314
+ message += '\n';
315
+ message += `Done in ${time < 2000 ? chalk.yellow(fastSymbol) : ''}${stringTime(time, chalk)}.`;
316
+ message += '\n';
317
+ message += `Listed ${highlight(String(context.fileInfoList.length), chalk)} files.`;
318
+ message += '\n';
319
+ message += `Processed ${highlight(String(context.count.files), chalk)} files and ${highlight(String(context.count.directories), chalk)} directories.`;
320
+ message += '\n';
321
+ if (bind.testCommand) {
322
+ message += '\n';
323
+ message += `${chalk.blue(infoSymbol)}You can use ${highlight(`'${bind.testCommand}'`, chalk)} to check if the list is valid.`;
324
+ }
325
+ message += '\n';
326
+ context.message = message;
327
+ },
328
+ },
329
+ ]);
330
+ },
331
+ },
332
+ ], {
333
+ ctx: context,
334
+ exitOnError: true,
335
+ });
336
+ try {
337
+ context.stream.run();
338
+ await progress.run();
339
+ }
340
+ catch (error) {
341
+ if (!(error instanceof ViewIgnoredError)) {
342
+ logError(format(error), { title: 'view-ignored - Error while scan.' });
343
+ }
344
+ }
345
+ console.log(context.message);
210
346
  }
211
- message += '\n';
212
- spinner.stop();
213
- spinner.clear();
214
- console.log(cwd + '\n' + message);
215
347
  }
216
348
  /**
217
349
  * Command-line 'config path' command action.
350
+ * @public
218
351
  */
219
352
  export function actionCfgPath() {
220
- console.log(Config.configFilePath);
353
+ console.log(Config.configManager.path);
221
354
  }
222
355
  /**
223
356
  * Command-line 'config set' command action
357
+ * @public
224
358
  */
225
- export function actionCfgSet(pair) {
359
+ export function actionCfgSet(pair, options) {
226
360
  if (pair === undefined) {
227
361
  console.log(`Allowed config keys are ${Config.configKeyList.join(', ')}.`);
228
362
  return;
229
363
  }
230
- const [key, val] = pair;
231
- Config.configManager.set(key, val).save();
232
- console.log(Config.configManager.getPairString(key));
364
+ const [key, value] = pair;
365
+ const errorMessage = Config.configManager.set(key, value);
366
+ if (errorMessage !== undefined) {
367
+ logError(errorMessage);
368
+ return;
369
+ }
370
+ const flags = scanProgram.optsWithGlobals();
371
+ const chalk = new Chalk();
372
+ Config.configManager.save();
373
+ console.log(Config.configManager.getPairString(key, {
374
+ chalk, real: options.real, types: options.types, parsable: flags.parsable,
375
+ }));
233
376
  }
234
377
  /**
235
378
  * Command-line 'config unset' command action
379
+ * @public
236
380
  */
237
- export function actionCfgUnset(key) {
381
+ export function actionCfgUnset(key, options) {
238
382
  if (key === undefined) {
239
383
  console.log('Configuration file has been completely deleted.');
240
384
  }
385
+ const flags = scanProgram.optsWithGlobals();
386
+ const chalk = new Chalk();
241
387
  Config.configManager.unset(key).save();
242
- console.log(Config.configManager.getPairString(key));
388
+ console.log(Config.configManager.getPairString(key, {
389
+ chalk, real: options.real, types: options.types, parsable: flags.parsable,
390
+ }));
243
391
  }
244
392
  /**
245
393
  * Command-line 'config unset' command action
394
+ * @public
246
395
  */
247
396
  export function actionCfgGet(key, options) {
248
- console.log(Config.configManager.getPairString(key, options.real));
397
+ const flags = scanProgram.optsWithGlobals();
398
+ const chalk = new Chalk();
399
+ console.log(Config.configManager.getPairString(key, {
400
+ chalk, real: options.real, types: options.types, parsable: flags.parsable,
401
+ }));
249
402
  }