js-dev-tool 1.2.19 → 1.2.21

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
@@ -30,10 +30,11 @@ This section reflects the current `package.json#exports` and `package.json#files
30
30
  | --- | --- |
31
31
  | `js-dev-tool` | Root namespace object with `{ progress, common, utils }` |
32
32
  | `js-dev-tool/utils` | File, JSON, CLI, TSV/CSV, and small utility helpers |
33
- | `js-dev-tool/common` | File-system and terminal rendering primitives |
33
+ | `js-dev-tool/common` | File-system helpers, terminal rendering primitives, and `isMain` |
34
34
  | `js-dev-tool/progress` | Progress renderer, spinner helpers, webpack / browserify progress hooks |
35
35
  | `js-dev-tool/progress/progress-extras` | Environment and webpack-version helpers |
36
36
  | `js-dev-tool/extras/algorithms` | Binary-search helper |
37
+ | `js-dev-tool/extras/gzip-tool` | Deterministic gzip + Base64 source-literal helpers |
37
38
  | `js-dev-tool/extras/jsonl` | JSONL readers, JSONL-to-array/map helpers, and `jsonMinify` |
38
39
  | `js-dev-tool/extras/json-minify` | `jsonMinify` |
39
40
  | `js-dev-tool/extras/progress-light` | Small fixed-frame spinner |
@@ -93,6 +94,20 @@ console.log(map["1"], deps.slice(0, 5));
93
94
  - `createLogStreamAndResolvePath(logPath)`
94
95
  - `renderLine(msg?, row?)`
95
96
  - `cursor(enabled, output?)`
97
+ - `isMain(moduleOrPathOrMeta)`
98
+
99
+ `isMain(...)` is the cross-module-system entry-point check. It accepts:
100
+
101
+ - CommonJS: `module` or `__filename`
102
+ - ESM: `import.meta` or `fileURLToPath(import.meta.url)`
103
+
104
+ ```js
105
+ const { isMain } = require("js-dev-tool/common");
106
+
107
+ if (isMain(module)) {
108
+ console.log("run only when executed directly");
109
+ }
110
+ ```
96
111
 
97
112
  ## `progress`
98
113
 
@@ -190,6 +205,34 @@ async function main() {
190
205
  main().catch(console.error);
191
206
  ```
192
207
 
208
+ ### `js-dev-tool/extras/gzip-tool`
209
+
210
+ Exports:
211
+
212
+ - `gzip(data, useZeroTimestamp?)`
213
+ - `toBase64SourceLiteral(rawData, wrapSize?)`
214
+
215
+ Use this module when you want deterministic gzip output and a clean way to embed the compressed bytes into JavaScript source.
216
+
217
+ Key behaviors:
218
+
219
+ - `gzip(...)` compresses with gzip level `9`
220
+ - `gzip(..., true)` zeroes the gzip `mtime` header so repeated builds with the same input stay byte-stable
221
+ - `toBase64SourceLiteral(...)` wraps Base64 output with trailing `\` line continuations so the result can be pasted into a multi-line JavaScript string literal
222
+ - `wrapSize` must be a finite integer between `1` and `2048`
223
+
224
+ Example:
225
+
226
+ ```js
227
+ const { gzip, toBase64SourceLiteral } = require("js-dev-tool/extras/gzip-tool");
228
+
229
+ const compressed = gzip("console.log(\"hello\");");
230
+ const sourceLiteral = toBase64SourceLiteral(compressed, 76);
231
+
232
+ console.log(compressed.length);
233
+ console.log(sourceLiteral);
234
+ ```
235
+
193
236
  ### `js-dev-tool/extras/progress-light`
194
237
 
195
238
  Exports:
package/common/index.d.ts CHANGED
@@ -43,17 +43,29 @@ export function renderLine(msg?: string, row?: number): void;
43
43
  */
44
44
  export function cursor(enabled: boolean, output?: NodeJS.WriteStream): void;
45
45
  /**
46
- * Returns `true` if the given module is the entry point of the current process.
46
+ * Minimal `import.meta`-compatible shape accepted by `isMain`.
47
47
  *
48
- * Accepts either a `module` object (CommonJS) or a file path string,
49
- * making it usable from both CommonJS and ESM contexts.
48
+ * Only `url` is required. `resolve` stays optional so the same shape works
49
+ * across older and newer Node.js ESM runtimes.
50
+ */
51
+ declare type TImportMeta = {
52
+ url: string;
53
+ resolve?: (filePath: string) => string;
54
+ };
55
+ /**
56
+ * Returns `true` when the provided CommonJS module, absolute file path, or
57
+ * ESM `import.meta` object represents the current process entry point.
58
+ *
59
+ * This gives one API that works across both module systems:
60
+ * - CommonJS: `module` or `__filename`
61
+ * - ESM: `import.meta` or `fileURLToPath(import.meta.url)`
50
62
  *
51
63
  * Equivalent to `import.meta.main` in Deno / Bun,
52
64
  * or `process.argv[1] === fileURLToPath(import.meta.url)` in ESM.
53
65
  *
54
- * @param {Partial<NodeJS.Module> | string} modOrFilePath
55
- * Pass `module` or `__filename` (CommonJS),
56
- * or `fileURLToPath(import.meta.url)` (ESM).
66
+ * @param {Partial<NodeJS.Module> | TImportMeta | string} modOrPathOrMeta
67
+ * Pass `module` or `__filename` from CommonJS,
68
+ * or `import.meta` / `fileURLToPath(import.meta.url)` from ESM.
57
69
  * @returns {boolean} `true` if the calling module is the entry point.
58
70
  *
59
71
  * @example
@@ -67,7 +79,12 @@ export function cursor(enabled: boolean, output?: NodeJS.WriteStream): void;
67
79
  * if (isMain(__filename)) { main(); }
68
80
  *
69
81
  * @example
70
- * // ESM — via fileURLToPath:
82
+ * // ESM — via import.meta object:
83
+ * import { isMain } from "js-dev-tool/common";
84
+ * if (isMain(import.meta)) { main(); }
85
+ *
86
+ * @example
87
+ * // ESM — via fileURLToPath(import.meta.url):
71
88
  * import { isMain } from "js-dev-tool/common";
72
89
  * import { fileURLToPath } from "node:url";
73
90
  * if (isMain(fileURLToPath(import.meta.url))) { main(); }
@@ -76,4 +93,4 @@ export function cursor(enabled: boolean, output?: NodeJS.WriteStream): void;
76
93
  * @verified CJS: Confirmed working on Node.js v11.15.0 — v26.3.0.
77
94
  * @verified ESM: Confirmed working on Node.js v12.22.11 — v26.3.0.
78
95
  */
79
- export function isMain(modOrFilePath: Partial<NodeJS.Module> | string): boolean;
96
+ export function isMain(modOrPathOrMeta: Partial<NodeJS.Module> | TImportMeta | string): boolean;
package/common/index.js CHANGED
@@ -13,6 +13,7 @@
13
13
  const fs = require("fs");
14
14
  const path = require("path");
15
15
  const rl = require("readline");
16
+ const { fileURLToPath } = require("url");
16
17
  /**
17
18
  * @param {string} dest
18
19
  */
@@ -56,17 +57,30 @@ const cursor = (enabled, output = process.stderr) => {
56
57
  }
57
58
  };
58
59
  /**
59
- * Returns `true` if the given module is the entry point of the current process.
60
+ * Minimal `import.meta`-compatible shape accepted by {@link isMain}.
60
61
  *
61
- * Accepts either a `module` object (CommonJS) or a file path string,
62
- * making it usable from both CommonJS and ESM contexts.
62
+ * Only `url` is required. `resolve` stays optional so the same shape works
63
+ * across older and newer Node.js ESM runtimes.
64
+ *
65
+ * @typedef {{
66
+ * url: string;
67
+ * resolve?: (filePath: string) => string;
68
+ * }} TImportMeta
69
+ */
70
+ /**
71
+ * Returns `true` when the provided CommonJS module, absolute file path, or
72
+ * ESM `import.meta` object represents the current process entry point.
73
+ *
74
+ * This gives one API that works across both module systems:
75
+ * - CommonJS: `module` or `__filename`
76
+ * - ESM: `import.meta` or `fileURLToPath(import.meta.url)`
63
77
  *
64
78
  * Equivalent to `import.meta.main` in Deno / Bun,
65
79
  * or `process.argv[1] === fileURLToPath(import.meta.url)` in ESM.
66
80
  *
67
- * @param {Partial<NodeJS.Module> | string} modOrFilePath
68
- * Pass `module` or `__filename` (CommonJS),
69
- * or `fileURLToPath(import.meta.url)` (ESM).
81
+ * @param {Partial<NodeJS.Module> | TImportMeta | string} modOrPathOrMeta
82
+ * Pass `module` or `__filename` from CommonJS,
83
+ * or `import.meta` / `fileURLToPath(import.meta.url)` from ESM.
70
84
  * @returns {boolean} `true` if the calling module is the entry point.
71
85
  *
72
86
  * @example
@@ -80,7 +94,12 @@ const cursor = (enabled, output = process.stderr) => {
80
94
  * if (isMain(__filename)) { main(); }
81
95
  *
82
96
  * @example
83
- * // ESM — via fileURLToPath:
97
+ * // ESM — via import.meta object:
98
+ * import { isMain } from "js-dev-tool/common";
99
+ * if (isMain(import.meta)) { main(); }
100
+ *
101
+ * @example
102
+ * // ESM — via fileURLToPath(import.meta.url):
84
103
  * import { isMain } from "js-dev-tool/common";
85
104
  * import { fileURLToPath } from "node:url";
86
105
  * if (isMain(fileURLToPath(import.meta.url))) { main(); }
@@ -89,11 +108,18 @@ const cursor = (enabled, output = process.stderr) => {
89
108
  * @verified CJS: Confirmed working on Node.js v11.15.0 — v26.3.0.
90
109
  * @verified ESM: Confirmed working on Node.js v12.22.11 — v26.3.0.
91
110
  */
92
- function isMain(modOrFilePath) {
93
- if (typeof modOrFilePath === "string") {
94
- return process.argv[1] === modOrFilePath;
111
+ function isMain(modOrPathOrMeta) {
112
+ /** @type {string=} */
113
+ let pathString;
114
+ if (typeof modOrPathOrMeta === "string") {
115
+ pathString = modOrPathOrMeta;
116
+ } else if ("url" in modOrPathOrMeta /* && "resolve" in modOrPathOrMeta */) {
117
+ pathString = fileURLToPath(modOrPathOrMeta.url);
118
+ }
119
+ if (pathString) {
120
+ return process.argv[1] === pathString;
95
121
  }
96
- return require.main === modOrFilePath;
122
+ return require.main === modOrPathOrMeta;
97
123
  }
98
124
  module.exports = {
99
125
  checkParentDirectory,
@@ -49,11 +49,16 @@ function toBase64SourceLiteral(rawData, wrapSize = 100) {
49
49
  if (wrapSize > 2048) throw new Error(`"wrapSize" is expected to be 2048 or less - ${wrapSize}`);
50
50
  if (wrapSize < 1) throw new Error(`A wrapSize of 0 or less will result in an infinite loop, so please make it 1 or greater. - ${wrapSize}`);
51
51
  const base64 = Buffer.from(rawData).toString("base64");
52
- let wrapped = "";
53
- for (let offset = 0, L = base64.length; offset < L;) {
54
- wrapped += `${base64.slice(offset, offset += wrapSize)}\\\n`;
52
+ const L = base64.length;
53
+ if (!L) return "";
54
+ let wrapped = "", lineSuffix = "\\\n";
55
+ for (let offset = 0; offset < L;) {
56
+ if (
57
+ (offset + wrapSize) >= L
58
+ ) lineSuffix = "";
59
+ wrapped += (base64.slice(offset, offset += wrapSize) + lineSuffix);
55
60
  }
56
- return wrapped.slice(0, -2);
61
+ return wrapped;
57
62
  }
58
63
  module.exports = {
59
64
  gzip, toBase64SourceLiteral
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-dev-tool",
3
- "version": "1.2.19",
3
+ "version": "1.2.21",
4
4
  "type": "commonjs",
5
5
  "bin": {
6
6
  "jstool": "tools.js",
@@ -84,7 +84,7 @@
84
84
  "!tool.sh"
85
85
  ],
86
86
  "peerDependencies": {
87
- "archiver": "^4.0.1",
87
+ "archiver": "^7.0.1",
88
88
  "webpack": "*"
89
89
  },
90
90
  "dependencies": {
@@ -95,7 +95,7 @@
95
95
  "replace": "^1.2.2",
96
96
  "rm-cstyle-cmts": "^3.4.4",
97
97
  "terser": "^5.48.0",
98
- "tin-args": "^0.1.6",
98
+ "tin-args": "^0.1.7",
99
99
  "ts-cc-map": "^1.1.0"
100
100
  }
101
101
  }
package/progress/index.js CHANGED
@@ -14,6 +14,7 @@ const {
14
14
  wppHandlerV4,
15
15
  isWebpackV5later,
16
16
  } = require("./progress-extras");
17
+ const _log = console.log;
17
18
  /**
18
19
  *
19
20
  * @param {string[]} frames progress frame.
@@ -106,7 +107,7 @@ const createProgressObject = (frames, formatOpt, messageEmitter) => {
106
107
  * adjust to next line
107
108
  */
108
109
  newLine() {
109
- console.log();
110
+ _log();
110
111
  },
111
112
  /**
112
113
  * change the fps rate
@@ -204,7 +205,7 @@ function createWebpackProgressPluginHandler(
204
205
  {
205
206
  const shortenProgress = (/** @type {number} */ pct) => {
206
207
  renderer(formatPercentage(pct));
207
- pct === 1 && (console.log(), (dotted = 0));
208
+ pct === 1 && (_log(), (dotted = 0));
208
209
  };
209
210
  if (logFilePath !== void 0) {
210
211
  const wppLogger = lib.createLogStreamAndResolvePath(logFilePath);
@@ -8,6 +8,7 @@
8
8
  /// <reference path="./index.d.ts"/>
9
9
  "use strict";
10
10
  const lib = require("../common");
11
+ const _log = console.log;
11
12
  const checkENV = () => {
12
13
  const env = process.env;
13
14
  if (env.CI) return "ci";
@@ -32,7 +33,7 @@ const wppHandlerV4 = ((renderer, cwd) => {
32
33
  message +
33
34
  ` [${modules}, ${actives}] ${path}`,
34
35
  );
35
- percentage === 1 && console.log();
36
+ percentage === 1 && _log();
36
37
  };
37
38
  })(lib.renderLine, process.cwd());
38
39
  /** @type {TWebpackProgressHandler} */
@@ -46,7 +47,7 @@ const wppHandlerV5 = ((renderer/*, cwd*/) => {
46
47
  renderer(
47
48
  `pct: ${(percentage * 100).toFixed(4)}%, process: [${message}]${pathOrPluginName ? `, info: [${pathOrPluginName}]` : ""}${args.length ? " - " : ""}${args[0]?.slice(args[0].length - maxLen) || ""}`,
48
49
  );
49
- percentage === 1 && console.log();
50
+ percentage === 1 && _log();
50
51
  };
51
52
  })(lib.renderLine/*, process.cwd()*/);
52
53
  /** @type {boolean} */
package/tool-lib/cjbm.js CHANGED
@@ -109,8 +109,9 @@ function getReplacer(ext) {
109
109
  }
110
110
  /**
111
111
  * @param {string} ext
112
+ * @param {NsJsTool.TDevConsole} logger
112
113
  */
113
- const emitProcessCallback = (ext) => {
114
+ const emitProcessCallback = (ext, logger) => {
114
115
  /**
115
116
  * @param {string[]} sourceFiles
116
117
  */
@@ -126,7 +127,7 @@ const emitProcessCallback = (ext) => {
126
127
  fs.rename(sourceFile, afterPath, err => {
127
128
  if (err) console.error(err);
128
129
  else {
129
- console.log(`renamed: ${sourceFile} => ${afterPath}`);
130
+ logger.log(`renamed: ${sourceFile} => ${afterPath}`);
130
131
  }
131
132
  });
132
133
  }
@@ -143,7 +144,7 @@ module.exports = () => {
143
144
  /**
144
145
  * about regex: see [[tools.js] regex - (C)onvert (J)S to (B)rowser (M)odule](https://regex101.com/r/EpuQLT/37)
145
146
  */
146
- fn() {
147
+ fn(logger) {
147
148
  const bases = getBasePaths();
148
149
  const ext = params.ext || "js";
149
150
  /**
@@ -157,22 +158,25 @@ module.exports = () => {
157
158
  return data.replace(reImportExportDetection, getReplacer(ext));
158
159
  }, {
159
160
  bases,
160
- cb: emitProcessCallback(ext)
161
+ cb: emitProcessCallback(ext, logger)
161
162
  },
162
163
  );
163
164
  },
164
165
  get help() {
165
- return `${this.taskName}
166
- ex - jstool -cmd cjbm [-root ./build | -basePath "./dist/esm,extra-tests/mini-semaphore"] [-ext js] [-test /\\.js$/] [-targets "['core.js', 'object.js']"]
167
- note:
168
- root - Recursively searches for files.
169
- This option is useful, but if there are directories that need to be avoided, use the 'basePath' option
170
- basePath - can be "<path>,<path>,..." (array type arg)
171
- ext - specifies the module extension for import/export clauses. default is "js"
172
- test - Any file extension can be specified. (The default is /\\.js$/)
173
- targets - specify this if you want to apply it only to a specific file.
174
- the file specified here should be directly under \`basePath\`!
175
- value must be array type arg, "['<path>', '<path>',...]" or "<path>,<path>,..."
166
+ const level = 16;
167
+ return `jstool -cmd cjbm [-root "./build" | -basePath "./dist/esm,extra-tests/mini-semaphore"] [-ext "js"] [-test "/\\.js$/"] [-targets "['core.js', 'object.js']"]
168
+
169
+ ${" Example:".red}
170
+ ${"jstool".yellow} ${"-cmd".green} ${"cjbm".cyan} ${"-basePath".green} ${"dist/esm,extra-tests/mini-semaphore".gray(level)} ${"-targets".green} ${"core.js,object.js".gray(level)}
171
+
172
+ ${" Options:".red}
173
+ ${" root".cyan} ${`: Recursively scan a single root directory.`.gray(level)}
174
+ ${" basePath".cyan} ${`: Source directory path(s). Use this when you want tighter scan control.`.gray(level)}
175
+ ${" ext".cyan} ${`: Module extension used in import/export clauses. default is "js".`.gray(level)}
176
+ ${" test".cyan} ${`: Target file matcher. default is /\\.js$/.`.gray(level)}
177
+ ${" targets".cyan} ${`: Limit processing to specific files directly under basePath.`.gray(level)}
178
+
179
+ ${" Note:".magenta} ${`targets accepts comma-separated values or array type arg such as "['core.js','object.js']".`.gray(level)}
176
180
  `;
177
181
  },
178
182
  };
@@ -12,10 +12,10 @@
12
12
  * @file comment trick toggle
13
13
  */
14
14
  /**
15
- *
16
15
  * @param {string} code
16
+ * @param {NsJsTool.TDevConsole} logger
17
17
  */
18
- function cleanup(code) {
18
+ function cleanup(code, logger) {
19
19
  const reCleanUp = new RegExp(
20
20
  "\s*\/(?:\s*\/+\*\s+(?:ctt|comment-toggle-trick|https:\/\/coderwall)([\s\S]+?)(?:\s+)\/\*\/[\s\S]+|\s*\*\s+(?:ctt|comment-toggle-trick|https:\/\/coderwall)[\s\S]+\/\*\/([\s\S]+?))\s*\/{2,}\*\/", "g"
21
21
  );
@@ -25,12 +25,13 @@ function cleanup(code) {
25
25
  }
26
26
  /**
27
27
  * @param {string} code
28
+ * @param {NsJsTool.TDevConsole} logger
28
29
  */
29
- function doIt(code) {
30
+ function doIt(code, logger) {
30
31
  return code.replace(
31
32
  /\/+(?=\*\s?(ctt|comment-toggle-trick|https:\/\/coderwall))/g, ($0) => {
32
33
  const slashes = $0.length === 2 ? "/" : "//";
33
- console.log(
34
+ logger.log(
34
35
  "the-comment-toggle-trick: %s",
35
36
  /*enableBefore*/ slashes.length === 2
36
37
  ? "-->enable before<--, mute after"
@@ -47,24 +48,28 @@ function doIt(code) {
47
48
  module.exports = () => {
48
49
  return {
49
50
  taskName: "comment trick toggle",
50
- fn(mode) {
51
+ fn(logger, mode) {
51
52
  processSources(
52
53
  /** @type {string} */ (this.taskName), (code) => {
53
- return mode === "clean" ? cleanup(code) : doIt(code);
54
+ return mode === "clean" ? cleanup(code, logger) : doIt(code, logger);
54
55
  }, {
55
56
  ...params,
56
57
  },
57
58
  );
58
59
  },
59
60
  get help() {
60
- return `Do comment trick toggle
61
- It recognizes three markers: \`ctt | comment-toggle-trick | https://coderwall\`
62
- jstool -cmd cmtTrick[:clean] (-base <source dir> | -bases "<source dir>,<source dir>,...") [-test re/\\\\.js$/]
63
- note:
64
- :clean - remove comment token etc leaving the currently enabled code
65
- base (or root) - scan single source folder
66
- bases - must be array type arg, "['<path>', '<path>',...]" or "<path>,<path>,..."
67
- test - terget extension, default is /\\\\.js$/
61
+ const level = 16;
62
+ return `jstool -cmd cmtTrick[:clean] (-basePath "<source dir>" | -basePath "<source dir>,<source dir>,...") [-test "re/\\\\.js$/"]
63
+
64
+ ${" Example:".red}
65
+ ${"jstool".yellow} ${"-cmd".green} ${"cmtTrick:clean".cyan} ${"-basePath".green} ${"src,examples".gray(level)} ${"-test".green} ${"re/\\\\.js$/".gray(level)}
66
+
67
+ ${" Options:".red}
68
+ ${" :clean".cyan} ${`: Remove comment tokens and leave the currently enabled code.`.gray(level)}
69
+ ${" basePath".cyan} ${`: Source directory path(s). Comma-separated or array type arg is accepted.`.gray(level)}
70
+ ${" test".cyan} ${`: Target file matcher. default is /\\\\.js$/.`.gray(level)}
71
+
72
+ ${" Note:".magenta} ${`Recognized markers: ctt | comment-toggle-trick | https://coderwall`.gray(level)}
68
73
  `;
69
74
  },
70
75
  };
package/tool-lib/ps.js CHANGED
@@ -21,8 +21,9 @@ module.exports = {
21
21
  /**
22
22
  * @param {import("fs")} fs
23
23
  * @param {import("../utils")} utils
24
+ * @param {NsJsTool.TDevConsole} logger
24
25
  */
25
- globalize: (fs, utils) => {
26
+ globalize: (fs, utils, logger) => {
26
27
  /**
27
28
  * @param {string} dir
28
29
  * @param {string[]} sourceFiles
@@ -32,12 +33,12 @@ module.exports = {
32
33
  const visitDirectory = (dir, sourceFiles, testRe, recurse) => {
33
34
  if (dir.length) {
34
35
  if (!fs.existsSync(dir)) {
35
- console.info(`directory: [${dir}] is not found`);
36
+ console.warn(`directory: [${dir}] is not found`);
36
37
  } else {
37
38
  utils.walkDirSync(dir, (dirent) => {
38
39
  const currentPath = `${dir}/${dirent.name}`;
39
40
  if (dirent.isFile() && testRe.test(dirent.name)) {
40
- DEBUG && console.log("processSources::", dirent.name);
41
+ DEBUG && logger.log("processSources::", dirent.name);
41
42
  sourceFiles.push(currentPath);
42
43
  } else if (recurse && dirent.isDirectory()) {
43
44
  visitDirectory(currentPath, sourceFiles, testRe, true);
@@ -72,8 +73,8 @@ module.exports = {
72
73
  sourceFiles = [];
73
74
  const reFile = params.test || test;
74
75
  const actualBases = isArray(bases) ? bases : [base];
75
- DEBUG && console.log("processSources::", actualBases, reFile);
76
- DEBUG && console.log("processSources::re", reFile, reFile.constructor);
76
+ DEBUG && logger.log("processSources::", actualBases, reFile);
77
+ DEBUG && logger.log("processSources::re", reFile, reFile.constructor);
77
78
  if (root) {
78
79
  visitDirectory(root.trim(), sourceFiles, reFile, true);
79
80
  } else {
@@ -88,7 +89,7 @@ module.exports = {
88
89
  }
89
90
  }
90
91
  sourceFiles = sourceFiles.filter(Boolean);
91
- DEBUG && console.log("processSources::processSources:", sourceFiles);
92
+ DEBUG && logger.log("processSources::processSources:", sourceFiles);
92
93
  let count = sourceFiles.length;
93
94
  let written = 0;
94
95
  /** @type {() => void} */
package/tool-lib/rws.js CHANGED
@@ -49,18 +49,29 @@ const decrementVersion = (nversionArray) => {
49
49
  * + Too many record entries can be hard to see,
50
50
  * so if there are more than 10 entries, they will be truncated.
51
51
  * @param {TVersionRecords} record
52
+ * @param {number=} [max=5]
52
53
  */
53
- const shortenRecord = (record) => {
54
+ const shortenRecord = (record, max = 5) => {
54
55
  let keys = /** @type {TVersionString[]} */ (Object.keys(record));
55
- if (keys.length > 10) {
56
- keys = keys.slice(keys.length - 10);
56
+ if (typeof max !== "number") {
57
+ console.warn(`rws::shortenRecord - "max" parameter is invalid, force set 5. (max: ${max})`);
58
+ max = 5;
59
+ } else {
60
+ if (!Number.isFinite(max)) max = 5;
61
+ else {
62
+ if (max < 1) max = 1;
63
+ else if (max > keys.length) max = keys.length;
64
+ }
65
+ }
66
+ if (keys.length > max) {
67
+ keys = keys.slice(keys.length - max);
57
68
  /** @type {TVersionRecords} */
58
- const newRecord = {};
69
+ const shortRecord = {};
59
70
  for (let i = 0; i < keys.length; ) {
60
71
  const key = keys[i++];
61
- newRecord[key] = record[key];
72
+ shortRecord[key] = record[key];
62
73
  }
63
- return newRecord;
74
+ return shortRecord;
64
75
  }
65
76
  return record;
66
77
  };
@@ -72,7 +83,7 @@ const shortenRecord = (record) => {
72
83
  module.exports = (fs, utils) => {
73
84
  return {
74
85
  taskName: "(R)ecord(W)ebpack(S)ize",
75
- fn() {
86
+ fn(logger) {
76
87
  const versionSourcePath = params.versionSource || "./package.json";
77
88
  /** @type {{ version: TVersionString }} */
78
89
  const thisPackage = utils.readJson(versionSourcePath);
@@ -139,7 +150,7 @@ module.exports = (fs, utils) => {
139
150
  if (prevEntry) {
140
151
  if (isDiff(prevEntry, entry)) {
141
152
  sizeRecord[versionStr] = entry;
142
- utils.log(shortenRecord(sizeRecord));
153
+ utils.log(shortenRecord(sizeRecord, params.printMax));
143
154
  msg = "[%s] is updated";
144
155
  } else {
145
156
  needWrite = false;
@@ -163,15 +174,21 @@ module.exports = (fs, utils) => {
163
174
  }
164
175
  },
165
176
  get help() {
166
- return `${this.taskName}
167
- ex - jstool -cmd rws [-versionSource "<version source path>"] [-webpack lib/webpack.js -umd umd/webpack.js -dest "./dev-extras/webpack-size.json"] [-rws-tags "web/login:./dist/es/web/login.mjs,webpack-esm:./dist/webpack-esm/index.mjs"]
168
- note:
169
- versionSource - JSON file path used to read the "version" field. if not specified then apply "./package.json"
170
- webpack - if not specified then apply "./dist/webpack/index.js"
171
- umd - if not specified then apply "./dist/umd/index.js"
172
- bin - if not specified then apply "./dist/bin/index.js"
173
- rws-tags - It is treated as parameter array separated by ":", e.g - "web/login:./dist/es/web/login.mjs,webpack-esm:./dist/webpack-esm/index.mjs"
174
- dest - if not specified then apply "./logs/webpack-size.json"
177
+ const level = 16;
178
+ return `jstool -cmd rws [-versionSource "./package.json"] [-webpack "./dist/webpack/index.js" -umd "./dist/umd/index.js" -bin "./dist/bin/index.js"]\\
179
+ [-dest "./logs/webpack-size.json"] [-printMax 5] [-rws-tags "web/login:./dist/es/web/login.mjs,webpack-esm:./dist/webpack-esm/index.mjs"]
180
+
181
+ ${" Example:".red}
182
+ ${"jstool".yellow} ${"-cmd".green} ${"rws".cyan} ${"-versionSource".green} ${"packages/web/package.json".gray(level)} ${"-dest".green} ${"./dev-extras/webpack-size.json".gray(level)}
183
+
184
+ ${" Options:".red}
185
+ ${" versionSource".cyan} ${`: JSON file path used to read the "version" field. default is "./package.json"`.gray(level)}
186
+ ${" webpack".cyan} ${`: Source path for the webpack bundle. default is "./dist/webpack/index.js"`.gray(level)}
187
+ ${" umd".cyan} ${`: Source path for the UMD bundle. default is "./dist/umd/index.js"`.gray(level)}
188
+ ${" bin".cyan} ${`: Source path for the bin bundle. default is "./dist/bin/index.js"`.gray(level)}
189
+ ${" dest".cyan} ${`: Output path of the size record JSON. default is "./logs/webpack-size.json"`.gray(level)}
190
+ ${" printMax".cyan} ${`: Max number of record entries shown in the preview log. default is 5`.gray(level)}
191
+ ${" rws-tags".cyan} ${`: Extra tag:path pairs separated by ",". e.g. "web/login:./dist/es/web/login.mjs,webpack-esm:./dist/webpack-esm/index.mjs"`.gray(level)}
175
192
  `;
176
193
  },
177
194
  };
@@ -6,6 +6,7 @@
6
6
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
7
  */
8
8
  /// <reference types="literate-regex/global"/>
9
+ /// <reference types="tin-args" preserve="true"/>
9
10
  /**
10
11
  * @date 2023-10-25
11
12
  */
@@ -19,7 +20,7 @@ declare global {
19
20
  declare type TStringReplacer = (matchs: string, ...args: any[]) => string;
20
21
  /** use `(R)ecord(W)ebpack(S)ize` */
21
22
  declare type TRwsTags = "webpack" | "umd" | "bin";
22
- declare var params: ReturnType<typeof import("tin-args")<TToolArgs>>;
23
+ declare var params: NsTinArgs.TTinArgsReturnType<TToolArgs>;
23
24
  declare var isArray: typeof Array.isArray;
24
25
  /**
25
26
  * @date 2025/2/18 0:46:03
@@ -65,6 +66,8 @@ declare global {
65
66
  minor?: true;
66
67
  patch?: true;
67
68
  extras: string[];
69
+ /** rws */
70
+ printMax?: number;
68
71
  /** rws, backup */
69
72
  dest: string;
70
73
  /** backup */
@@ -135,7 +138,7 @@ declare global {
135
138
  cb?: (sourceFiles: string[]) => void
136
139
  }
137
140
  declare type TJSToolEntry = {
138
- fn: (mode?: string) => void;
141
+ fn: (logger: NsJsTool.TDevConsole, mode?: string) => void;
139
142
  help: string;
140
143
  taskName: string;
141
144
  }
@@ -145,5 +148,13 @@ declare global {
145
148
  declare type TVersionString = `${number}.${number}.${number}${string}`;
146
149
  declare type TVersionRecords = Record<TVersionString, Partial<Record<TRwsTags, number>>>;
147
150
  declare type TSizeRecordEntry = TVersionRecords["0.0.0"];
151
+ declare namespace NsJsTool {
152
+ type TDevConsole = {
153
+ log: Console["log"];
154
+ warn: Console["warn"];
155
+ error: Console["error"];
156
+ info: Console["info"];
157
+ };
158
+ }
148
159
  }
149
- export = {};
160
+ export {};
@@ -19,7 +19,7 @@ module.exports =
19
19
  (utils) => {
20
20
  return {
21
21
  taskName: "zip",
22
- fn() {
22
+ fn(logger) {
23
23
  const comment = params.comment;
24
24
  const paths = params.args;
25
25
  if (Array.isArray(paths)) {
@@ -29,8 +29,18 @@ module.exports =
29
29
  }
30
30
  }
31
31
  },
32
- help: `jstool -cmd zip [-comment "the comment"] lib/webpack.js lib/type-ids.js
33
- It is possible to create zip files with comments
34
- `,
32
+ get help() {
33
+ const level = 16;
34
+ return `jstool -cmd zip [-comment "the comment"] lib/webpack.js lib/type-ids.js
35
+
36
+ ${" Example:".red}
37
+ ${"jstool".yellow} ${"-cmd".green} ${"zip".cyan} ${"-comment".green} ${"release artifact".gray(level)} ${"lib/webpack.js lib/type-ids.js".gray(level)}
38
+
39
+ ${" Options:".red}
40
+ ${" comment".cyan} ${`: ZIP comment string embedded into the output archive.`.gray(level)}
41
+
42
+ ${" Note:".magenta} ${`Pass target file paths as args after the options.`.gray(level)}
43
+ `;
44
+ },
35
45
  };
36
46
  };
package/tools.js CHANGED
@@ -18,8 +18,25 @@ const utils = require("./utils");
18
18
  global.params = require("tin-args")();
19
19
  global.verbose = params.verb;
20
20
  global.isArray = Array.isArray;
21
- require("./tool-lib/ps").globalize(fs, utils);
22
- utils.log(params);
21
+ /**
22
+ * @date 2026/06/27 15:59:10
23
+ * @since v1.5.23-dev
24
+ * @type {NsJsTool.TDevConsole}
25
+ */
26
+ const devLogger = (() => {
27
+ const emptyLogger = /** @type {NsJsTool.TDevConsole} */({
28
+ log() {},
29
+ info() {},
30
+ warn() {},
31
+ error() {},
32
+ });
33
+ if (process.env.CI) return emptyLogger;
34
+ return params.verb ? console : emptyLogger;
35
+ })();
36
+ /** shorthand of __`console.log`__ */
37
+ const _log = console.log;
38
+ if (verbose) utils.log(params);
39
+ require("./tool-lib/ps").globalize(fs, utils, devLogger);
23
40
  /**
24
41
  * how to config terser, see {@link https://github.com/terser/terser#minify-options-structure Minify options structure}
25
42
  *
@@ -78,7 +95,7 @@ const ToolFunctions = {
78
95
  */
79
96
  replace: {
80
97
  taskName: "replace",
81
- fn() {
98
+ fn(logger) {
82
99
  const re = params.regex;
83
100
  const after = params.after || "";
84
101
  let targets = params.args || params.targets
@@ -91,26 +108,27 @@ const ToolFunctions = {
91
108
  }
92
109
  },
93
110
  get help() {
111
+ const level = 16;
94
112
  return `jstool -cmd replace [-after <replacement>] -regex \"/^\\s+<!--[\\s\\S]+?-->(?:\\r?\\n)?/gm\" [-targets "<path>,<path>,..." | <args: file, file file...>]
95
113
 
96
114
  ${" Options:".red}
97
- ${" after".cyan} ${`: If omitted, "" (empty string) is used, meaning that the matched string is deleted.`.gray(16)}
98
- ${" targets".cyan}${`: Single path string or Array type arg, "['<path>', '<path>',...]" or "<path>,<path>,..."`.gray(16)}
115
+ ${" after".cyan} ${`: If omitted, "" (empty string) is used, meaning that the matched string is deleted.`.gray(level)}
116
+ ${" targets".cyan}${`: Single path string or Array type arg, "['<path>', '<path>',...]" or "<path>,<path>,..."`.gray(level)}
99
117
 
100
- ${" remarks".magenta}${": targets - can use args parameter instead".gray(16)}${`
118
+ ${" remarks".magenta}${": targets - can use args parameter instead".gray(level)}${`
101
119
  It is better to use the <args: file, file file...>
102
- e.g - ${"jstool".yellow} ${"-cmd".green} ${"replace".cyan} ${"-after".green} ${`".."`.red} ${"-regex".green} ${String.raw`'re/(?<=reference path=")(\.)(?=\/index.d.ts")/'`.magenta} ${"build/**/*.js".gray(16)}
120
+ e.g - ${"jstool".yellow} ${"-cmd".green} ${"replace".cyan} ${"-after".green} ${`".."`.red} ${"-regex".green}=${String.raw`'r/(?<=reference path=")(\.)(?=\/index.d.ts")/'`.magenta} ${"build/**/*.js".gray(level)}
103
121
  ^^^^^^^^^^^^^
104
- `.gray(16)}`;
122
+ `.gray(level)}`;
105
123
  },
106
124
  },
107
125
  version: {
108
126
  taskName: "version",
109
- fn() {
127
+ fn(logger) {
110
128
  let { major, minor /*, patch*/, pkgJsons = ["./package.json"] } = params;
111
129
  /** @type {string} */
112
130
  let currentVersion;
113
- /** @type {string} */
131
+ /** @type {string=} */
114
132
  let nextVersion;
115
133
  !isArray(pkgJsons) && (pkgJsons = [pkgJsons]);
116
134
  utils.fireReplace(
@@ -156,18 +174,28 @@ ${" remarks".magenta}${": targets - can use args parameter instead".gray(16)}${
156
174
  paths,
157
175
  );
158
176
  }
159
- // @ts-ignore
160
177
  console.log("version updated: %s", nextVersion);
161
178
  },
162
- help: `jstool -cmd version [-major | -minor] [-pkgJsons "./package.json,../package.json"] [-extras "test/web/index.html"]
163
- bump top level package.json version(can specify "package.json" paths by \`pkgJsons\` option if need), specify patch version is unnecessary.
164
- note:
165
- extras - can be "<path>,<path>,..." (array type arg)
166
- `,
179
+ get help() {
180
+ const level = 16;
181
+ return `jstool -cmd version [-major | -minor] [-pkgJsons "./package.json,../package.json"] [-extras "test/web/index.html"]
182
+
183
+ ${" Example:".red}
184
+ ${"jstool".yellow} ${"-cmd".green} ${"version".cyan} ${"-minor".green} ${"-extras".green} ${"README.md,test/web/index.html".gray(level)}
185
+
186
+ ${" Options:".red}
187
+ ${" major".cyan} ${`: Bump major version and reset minor/patch to 0.`.gray(level)}
188
+ ${" minor".cyan} ${`: Bump minor version and reset patch to 0.`.gray(level)}
189
+ ${" pkgJsons".cyan} ${`: Target package.json path(s). Comma-separated or array type arg is accepted.`.gray(level)}
190
+ ${" extras".cyan} ${`: Additional files whose version strings should be replaced too.`.gray(level)}
191
+
192
+ ${" Note:".magenta} ${`If neither -major nor -minor is specified, patch version is bumped.`.gray(level)}
193
+ `;
194
+ },
167
195
  },
168
196
  minify: {
169
197
  taskName: "minify",
170
- fn() {
198
+ fn(logger) {
171
199
  const Terser = require("terser");
172
200
  const sx = params.suffix;
173
201
  let suffix = ".mini";
@@ -195,12 +223,19 @@ ${" remarks".magenta}${": targets - can use args parameter instead".gray(16)}${
195
223
  opt,
196
224
  );
197
225
  },
198
- help: `jstool -cmd minify -basePath extra-tests/web/mini-semaphore [-test "re/\\.js$/"] [-suffix ".mini"]
199
- note:
200
- basePath - can be "<path>,<path>,..." (array type arg)
201
- test - can be omit, default is \`/\\.js$/\`
202
- suffix - can be omit, default is ".mini"
203
- `,
226
+ get help() {
227
+ const level = 16;
228
+ return `jstool -cmd minify -basePath "extra-tests/web/mini-semaphore" [-test "re/\\.js$/"] [-suffix ".mini"]
229
+
230
+ ${" Example:".red}
231
+ ${"jstool".yellow} ${"-cmd".green} ${"minify".cyan} ${"-basePath".green} ${"dist/esm,dist/cjs".gray(level)} ${"-suffix".green} ${".min".gray(level)}
232
+
233
+ ${" Options:".red}
234
+ ${" basePath".cyan} ${`: Source directory path(s). Comma-separated or array type arg is accepted.`.gray(level)}
235
+ ${" test".cyan} ${`: Target file matcher. default is /\\.js$/.`.gray(level)}
236
+ ${" suffix".cyan} ${`: Output suffix inserted before ".js". default is ".mini".`.gray(level)}
237
+ `;
238
+ },
204
239
  },
205
240
  /**
206
241
  * NOTE: keep comment that start with "/&#42;" when "&#42;/" end mark appears in same line.
@@ -209,12 +244,12 @@ ${" remarks".magenta}${": targets - can use args parameter instead".gray(16)}${
209
244
  */
210
245
  rmc: {
211
246
  taskName: "rm-cstyle-cmts",
212
- fn() {
247
+ fn(logger) {
213
248
  rmc.reset();
214
249
  if (params.rmc4ts) {
215
250
  const keepBangLine = params.rmc4ts === "keepBangLine";
216
251
  const reMultiLineChcker = /^\/\*(\*|!)\s|^\/\*(?!-).+\*\/$/;
217
- const reSingleLineChecer = /^\/\/+!/;
252
+ const reSingleLineChecer = /^(?:\/\/+!)/;
218
253
  rmc.setListener(({ event, fragment }) => {
219
254
  if (event === /*EScannerEvent.MultiLineComment*/ 1) {
220
255
  return reMultiLineChcker.test(fragment);
@@ -240,16 +275,23 @@ ${" remarks".magenta}${": targets - can use args parameter instead".gray(16)}${
240
275
  },
241
276
  );
242
277
  },
243
- help: `$ jstool -cmd rmc [-rmc4ts[:keepBangLine]] -basePath "./dist/cjs,./dist/cjs/gulp" -test "/\\.(js|d\\.ts)$/"
244
- note: basePath - can be "<path>,<path>,..." (array type arg)
245
- test - can be omit, defulat \`/\.js$/\`
246
- rmc4ts- for typescript source.
247
- keep comment that start with "/*" when "*/" end mark appears in same line.
248
- if start with "/*-" remove it
249
- keep leading "/// <reference ...>" directives above a top-level "use strict" line in CJS emit.(2026/02/03)
250
- rmc4ts=keepBangLine (2025/12/24)
251
- - In addition to the "rmc4ts" processing, it also preserves line comments that start with "//!".
252
- `,
278
+ get help() {
279
+ const level = 16;
280
+ return `jstool -cmd rmc [-rmc4ts[:keepBangLine]] -basePath "./dist/cjs,./dist/cjs/gulp" [-test "/\\.(js|d\\.ts)$/"] [-suffix ".clean"]
281
+
282
+ ${" Example:".red}
283
+ ${"jstool".yellow} ${"-cmd".green} ${"rmc".cyan} ${"-rmc4ts:keepBangLine".green} ${"-basePath".green} ${"dist/cjs,dist/cjs/gulp".gray(level)} ${"-test".green} ${"/\\.(js|d\\.ts)$/".gray(level)}
284
+
285
+ ${" Options:".red}
286
+ ${" basePath".cyan} ${`: Source directory path(s). Comma-separated or array type arg is accepted.`.gray(level)}
287
+ ${" test".cyan} ${`: Target file matcher. default is /\\.js$/.`.gray(level)}
288
+ ${" suffix".cyan} ${`: Output suffix inserted before ".js" when needed.`.gray(level)}
289
+ ${" rmc4ts".cyan} ${`: TypeScript-oriented mode. Preserves single-line /* */ comments except ones that start with "/*-".`.gray(level)}
290
+
291
+ ${" Extra:".magenta} ${`rmc4ts:keepBangLine also preserves line comments that start with "//!".`.gray(level)}
292
+ ${" Extra:".magenta} ${`Leading /// <reference ...> directives are kept above a top-level "use strict" line in CJS output.`.gray(level)}
293
+ `;
294
+ },
253
295
  },
254
296
  zip: require("./tool-lib/zip-task")(utils),
255
297
  };
@@ -298,25 +340,25 @@ function isJSToolEntry(entry) {
298
340
  */
299
341
  function printHelp(cmd) {
300
342
  const entry = ToolFunctions[cmd];
301
- console.log(`${cmd.yellow + " help:".green} ${entry.help.gray(8)}`);
343
+ _log(`${cmd.yellow + " help:".green} ${entry.help.gray(8)}`);
302
344
  }
303
345
  if (params.cmd) {
304
346
  const [task, mode] = params.cmd.split(":");
305
347
  const entry = ToolFunctions[task];
306
- isJSToolEntry(entry) && entry.fn(mode);
348
+ isJSToolEntry(entry) && entry.fn(devLogger, mode);
307
349
  } else if (params.shell) {
308
350
  const SCRIPT_DIR = path.dirname(process.argv[1]);
309
351
  const arg = `${params.major ? "-major" : params.minor ? "-minor" : ""}`;
310
352
  utils.execWithOutputResult(
311
353
  `bash ${SCRIPT_DIR}/scripts/tool.sh ${params.shell} ${arg}`,
312
354
  (result) => {
313
- console.log(result);
355
+ _log(result);
314
356
  },
315
357
  process.cwd(),
316
358
  );
317
359
  } else if (params.v) {
318
360
  const thisVersion = require("./package.json").version;
319
- console.log(
361
+ _log(
320
362
  `${"jstool".magenta} in "js-dev-scripts", version: ${thisVersion.green}
321
363
  more details see ${"https://github.com/jeffy-g/js-dev-scripts".blue}`,
322
364
  );
@@ -327,7 +369,7 @@ more details see ${"https://github.com/jeffy-g/js-dev-scripts".blue}`,
327
369
  printHelp(cmdName);
328
370
  } else {
329
371
  const commands = Object.keys(ToolFunctions);
330
- console.log(`
372
+ _log(`
331
373
  Usage: node jstool -cmd <command name>
332
374
  - - - - available commands:`);
333
375
  for (const cmd of commands) {
package/utils.js CHANGED
@@ -27,6 +27,7 @@ const lib = require("./common");
27
27
  const tinArgs = require("tin-args");
28
28
  const { listDependenciesOf } = require("./extras/list-deps-of");
29
29
  const CI = !!process.env.CI;
30
+ const _log = console.log;
30
31
  /**
31
32
  * Nothing is logged in a CI environment.
32
33
  */
@@ -53,7 +54,6 @@ function extractVersion(versionString = process.version) {
53
54
  const [major = 0, minor = 0, patch = 0] = pv ? pv.map((value, i) => {
54
55
  return (i > 0 && +value) || void 0;
55
56
  }).slice(1) : [];
56
- console.log("result:", major, minor, patch);
57
57
  return { major, minor, patch };
58
58
  }
59
59
  /**
@@ -257,16 +257,16 @@ function compressScript(scriptPath, comment = "") {
257
257
  compressionMethod: zlibZip.CompressionMethod.DEFLATE,
258
258
  os: zlibZip.OperatingSystem.MSDOS,
259
259
  });
260
- console.log(`added ${scriptPath} to zip`);
261
- console.log("start compress...");
260
+ _log(`added ${scriptPath} to zip`);
261
+ _log("start compress...");
262
262
  console.time("zip:compress");
263
263
  const compressed = zip.compress();
264
264
  console.timeEnd("zip:compress");
265
- console.log("compress done.\n");
265
+ _log("compress done.\n");
266
266
  const pp = path.parse(scriptPath);
267
267
  const output = `${pp.dir ? pp.dir + "/" : ""}${pp.name}.zip`;
268
268
  fs.writeFile(output, compressed, (err) => {
269
- console.log(`\nzip file created, error: ${err}\n => ${output}`);
269
+ _log(`\nzip file created, error: ${err}\n => ${output}`);
270
270
  });
271
271
  }
272
272
  /**
@@ -283,16 +283,16 @@ function compressScript2(scriptPath, comment = "") {
283
283
  const pp = path.parse(scriptPath);
284
284
  const output = fs.createWriteStream(`${pp.dir}/${pp.name}.zip`);
285
285
  output.on("close", function () {
286
- console.log(archive.pointer() + " total bytes");
287
- console.log(
286
+ _log(archive.pointer() + " total bytes");
287
+ _log(
288
288
  "archiver has been finalized and the output file descriptor has closed.",
289
289
  );
290
290
  });
291
291
  output.on("end", function () {
292
- console.log("Data has been drained");
292
+ _log("Data has been drained");
293
293
  });
294
294
  archive.on("progress", (progress) => {
295
- console.log(progress.entries.processed);
295
+ _log(progress.entries.processed);
296
296
  });
297
297
  archive.pipe(output);
298
298
  archive.file(scriptPath, {
@@ -313,7 +313,7 @@ function compressScript2(scriptPath, comment = "") {
313
313
  * @param {(result: string) => void} doneCallbackWithArgs gulp callback function.
314
314
  */
315
315
  function execWithOutputResult(command, doneCallbackWithArgs, cwd) {
316
- console.log();
316
+ _log();
317
317
  const { exec } = require("child_process");
318
318
  return exec(command, { cwd }, (err, stdout /* , stderr */) => {
319
319
  if (err) {
@@ -423,7 +423,7 @@ function copyText(content, message = "text copied!", chcp65001 = true) {
423
423
  if (err) {
424
424
  console.error(err);
425
425
  } else {
426
- console.log(message, stdout);
426
+ _log(message, stdout);
427
427
  }
428
428
  });
429
429
  // @ts-ignore