@guanghechen/commander 4.6.0 → 4.7.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.
@@ -1,30 +1,98 @@
1
1
  'use strict';
2
2
 
3
- var env = require('@guanghechen/env');
4
- var reporter = require('@guanghechen/reporter');
5
3
  var promises = require('node:fs/promises');
6
4
  var path = require('node:path');
5
+ var env = require('@guanghechen/env');
6
+ var reporter = require('@guanghechen/reporter');
7
7
  var fs = require('node:fs');
8
8
 
9
- function _interopNamespaceDefault(e) {
10
- var n = Object.create(null);
11
- if (e) {
12
- Object.keys(e).forEach(function (k) {
13
- if (k !== 'default') {
14
- var d = Object.getOwnPropertyDescriptor(e, k);
15
- Object.defineProperty(n, k, d.get ? d : {
16
- enumerable: true,
17
- get: function () { return e[k]; }
18
- });
9
+ const WINDOWS_DRIVE_ABSOLUTE_REGEX = /^[a-zA-Z]:[\\/]/;
10
+ function isAbsolutePath(filepath) {
11
+ return (filepath.startsWith('/') ||
12
+ filepath.startsWith('\\\\') ||
13
+ WINDOWS_DRIVE_ABSOLUTE_REGEX.test(filepath));
14
+ }
15
+ function resolvePathFrom(base, fragment) {
16
+ const useWindowsStyle = WINDOWS_DRIVE_ABSOLUTE_REGEX.test(base);
17
+ const normalizedBase = base.replace(/\\/g, '/');
18
+ const normalizedFragment = fragment.replace(/\\/g, '/');
19
+ const source = isAbsolutePath(normalizedFragment)
20
+ ? normalizedFragment
21
+ : `${normalizedBase.replace(/\/$/, '')}/${normalizedFragment}`;
22
+ const prefix = useWindowsStyle ? source.slice(0, 2) : '';
23
+ const body = useWindowsStyle ? source.slice(2) : source;
24
+ const stack = [];
25
+ for (const token of body.split('/')) {
26
+ if (token === '' || token === '.') {
27
+ continue;
28
+ }
29
+ if (token === '..') {
30
+ if (stack.length > 0) {
31
+ stack.pop();
19
32
  }
20
- });
33
+ continue;
34
+ }
35
+ stack.push(token);
21
36
  }
22
- n.default = e;
23
- return Object.freeze(n);
37
+ if (useWindowsStyle) {
38
+ const resolved = `${prefix}/${stack.join('/')}`;
39
+ return resolved.endsWith('/') ? resolved.slice(0, -1) : resolved;
40
+ }
41
+ return `/${stack.join('/')}`;
42
+ }
43
+ function createUnsupportedFsError(operation) {
44
+ return new Error(`runtime does not support file-system operation: ${operation}`);
45
+ }
46
+ function getFallbackCwd() {
47
+ const proc = globalThis.process;
48
+ if (proc && typeof proc.cwd === 'function') {
49
+ return proc.cwd();
50
+ }
51
+ return '/';
52
+ }
53
+ function createBrowserCommandRuntime() {
54
+ return {
55
+ cwd: () => getFallbackCwd(),
56
+ isAbsolute: filepath => isAbsolutePath(filepath),
57
+ resolve: (...paths) => {
58
+ if (paths.length === 0) {
59
+ return getFallbackCwd();
60
+ }
61
+ let resolved = getFallbackCwd();
62
+ for (const path of paths) {
63
+ if (path.length === 0) {
64
+ continue;
65
+ }
66
+ resolved = resolvePathFrom(resolved, path);
67
+ }
68
+ return resolved;
69
+ },
70
+ readFile: async () => {
71
+ throw createUnsupportedFsError('readFile');
72
+ },
73
+ stat: async () => {
74
+ throw createUnsupportedFsError('stat');
75
+ },
76
+ };
24
77
  }
25
78
 
26
- var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
27
- var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
79
+ let defaultRuntime = createBrowserCommandRuntime();
80
+ function getDefaultCommandRuntime() {
81
+ return defaultRuntime;
82
+ }
83
+ function setDefaultCommandRuntime(runtime) {
84
+ defaultRuntime = runtime;
85
+ }
86
+
87
+ function createNodeCommandRuntime() {
88
+ return {
89
+ cwd: () => process.cwd(),
90
+ isAbsolute: filepath => path.isAbsolute(filepath),
91
+ resolve: (...paths) => path.resolve(...paths),
92
+ readFile: filepath => promises.readFile(filepath, 'utf8'),
93
+ stat: filepath => promises.stat(filepath),
94
+ };
95
+ }
28
96
 
29
97
  const TERMINAL_STYLE = {
30
98
  bold: '\x1b[1m',
@@ -291,6 +359,7 @@ class Command {
291
359
  #builtin;
292
360
  #presetConfig;
293
361
  #reporter;
362
+ #runtime;
294
363
  #parent;
295
364
  #options = [];
296
365
  #arguments = [];
@@ -306,6 +375,7 @@ class Command {
306
375
  this.#builtin = normalizeBuiltinConfig(config.builtin);
307
376
  this.#presetConfig = config.preset;
308
377
  this.#reporter = config.reporter;
378
+ this.#runtime = config.runtime ?? getDefaultCommandRuntime();
309
379
  }
310
380
  get name() {
311
381
  return this.#name || undefined;
@@ -824,12 +894,12 @@ class Command {
824
894
  return await this.#assertPresetRoot(commandPreset.root, 'command.preset.root', commandPath);
825
895
  }
826
896
  async #assertPresetRoot(root, sourceName, commandPath) {
827
- if (!path.isAbsolute(root)) {
897
+ if (!this.#runtime.isAbsolute(root)) {
828
898
  throw new CommanderError('ConfigurationError', `invalid preset root from "${sourceName}": "${root}" is not an absolute directory`, commandPath);
829
899
  }
830
900
  let stats;
831
901
  try {
832
- stats = await promises.stat(root);
902
+ stats = await this.#runtime.stat(root);
833
903
  }
834
904
  catch (error) {
835
905
  throw new CommanderError('ConfigurationError', `invalid preset root from "${sourceName}": "${root}" cannot be accessed (${error.message})`, commandPath);
@@ -869,7 +939,7 @@ class Command {
869
939
  },
870
940
  ];
871
941
  }
872
- const absolutePath = path.resolve(presetRoot, defaultFilename);
942
+ const absolutePath = this.#runtime.resolve(presetRoot, defaultFilename);
873
943
  return [
874
944
  {
875
945
  displayPath: absolutePath,
@@ -879,13 +949,13 @@ class Command {
879
949
  ];
880
950
  }
881
951
  #resolvePresetFileAbsolutePath(filepath, presetRoot) {
882
- if (path.isAbsolute(filepath)) {
952
+ if (this.#runtime.isAbsolute(filepath)) {
883
953
  return filepath;
884
954
  }
885
955
  if (presetRoot !== undefined) {
886
- return path.resolve(presetRoot, filepath);
956
+ return this.#runtime.resolve(presetRoot, filepath);
887
957
  }
888
- return path.resolve(process.cwd(), filepath);
958
+ return this.#runtime.resolve(this.#runtime.cwd(), filepath);
889
959
  }
890
960
  #assertPresetOptionFragments(tokens, filepath, chain, optionPolicyMap) {
891
961
  if (tokens.length === 0) {
@@ -998,14 +1068,14 @@ class Command {
998
1068
  }
999
1069
  async #readPresetFile(file, commandPath) {
1000
1070
  try {
1001
- return await promises.readFile(file.absolutePath, 'utf8');
1071
+ return await this.#runtime.readFile(file.absolutePath);
1002
1072
  }
1003
1073
  catch (error) {
1004
1074
  const ioError = error;
1005
1075
  if (!file.explicit && ioError.code === 'ENOENT') {
1006
1076
  return undefined;
1007
1077
  }
1008
- throw new CommanderError('ConfigurationError', `failed to read preset file "${file.displayPath}": ${ioError.message}`, commandPath);
1078
+ throw new CommanderError('ConfigurationError', `failed to read preset file "${file.displayPath}": ${error.message}`, commandPath);
1009
1079
  }
1010
1080
  }
1011
1081
  #tokenizePresetOptions(content) {
@@ -1775,11 +1845,11 @@ class CompletionCommand extends Command {
1775
1845
  if (writeOpt !== undefined) {
1776
1846
  const filePath = typeof writeOpt === 'string' && writeOpt !== '' ? writeOpt : paths[shell];
1777
1847
  const expandedPath = expandHome(filePath);
1778
- const dir = path__namespace.dirname(expandedPath);
1779
- if (!fs__namespace.existsSync(dir)) {
1780
- fs__namespace.mkdirSync(dir, { recursive: true });
1848
+ const dir = path.dirname(expandedPath);
1849
+ if (!fs.existsSync(dir)) {
1850
+ fs.mkdirSync(dir, { recursive: true });
1781
1851
  }
1782
- fs__namespace.writeFileSync(expandedPath, script, 'utf-8');
1852
+ fs.writeFileSync(expandedPath, script, 'utf-8');
1783
1853
  console.log(`Completion script written to: ${expandedPath}`);
1784
1854
  }
1785
1855
  else {
@@ -2072,6 +2142,8 @@ class PwshCompletion {
2072
2142
  }
2073
2143
  }
2074
2144
 
2145
+ setDefaultCommandRuntime(createNodeCommandRuntime());
2146
+
2075
2147
  exports.BashCompletion = BashCompletion;
2076
2148
  exports.Coerce = Coerce;
2077
2149
  exports.Command = Command;
@@ -2079,6 +2151,9 @@ exports.CommanderError = CommanderError;
2079
2151
  exports.CompletionCommand = CompletionCommand;
2080
2152
  exports.FishCompletion = FishCompletion;
2081
2153
  exports.PwshCompletion = PwshCompletion;
2154
+ exports.createBrowserCommandRuntime = createBrowserCommandRuntime;
2155
+ exports.createNodeCommandRuntime = createNodeCommandRuntime;
2156
+ exports.getDefaultCommandRuntime = getDefaultCommandRuntime;
2082
2157
  exports.isDomain = isDomain;
2083
2158
  exports.isIp = isIp;
2084
2159
  exports.isIpv4 = isIpv4;
@@ -2086,4 +2161,5 @@ exports.isIpv6 = isIpv6;
2086
2161
  exports.logColorfulOption = logColorfulOption;
2087
2162
  exports.logDateOption = logDateOption;
2088
2163
  exports.logLevelOption = logLevelOption;
2164
+ exports.setDefaultCommandRuntime = setDefaultCommandRuntime;
2089
2165
  exports.silentOption = silentOption;