@nmakarov/cli-toolkit 0.14.2 → 0.16.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 (45) hide show
  1. package/dist/args.cjs +49 -9
  2. package/dist/args.cjs.map +1 -1
  3. package/dist/args.js +49 -9
  4. package/dist/args.js.map +1 -1
  5. package/dist/db.cjs +9 -2
  6. package/dist/db.cjs.map +1 -1
  7. package/dist/db.js +9 -2
  8. package/dist/db.js.map +1 -1
  9. package/dist/errors.cjs +17 -0
  10. package/dist/errors.cjs.map +1 -1
  11. package/dist/errors.js +15 -0
  12. package/dist/errors.js.map +1 -1
  13. package/dist/filedatabase.cjs +16 -24
  14. package/dist/filedatabase.cjs.map +1 -1
  15. package/dist/filedatabase.js +16 -23
  16. package/dist/filedatabase.js.map +1 -1
  17. package/dist/http-client.cjs +44 -34
  18. package/dist/http-client.cjs.map +1 -1
  19. package/dist/http-client.js +44 -34
  20. package/dist/http-client.js.map +1 -1
  21. package/dist/http-client2.cjs +368 -0
  22. package/dist/http-client2.cjs.map +1 -0
  23. package/dist/http-client2.js +340 -0
  24. package/dist/http-client2.js.map +1 -0
  25. package/dist/index.cjs +212 -91
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +212 -90
  28. package/dist/index.js.map +1 -1
  29. package/dist/init.cjs +190 -76
  30. package/dist/init.cjs.map +1 -1
  31. package/dist/init.js +190 -76
  32. package/dist/init.js.map +1 -1
  33. package/dist/logger.cjs +19 -36
  34. package/dist/logger.cjs.map +1 -1
  35. package/dist/logger.js +19 -36
  36. package/dist/logger.js.map +1 -1
  37. package/dist/mock-server.cjs +13 -16
  38. package/dist/mock-server.cjs.map +1 -1
  39. package/dist/mock-server.js +13 -16
  40. package/dist/mock-server.js.map +1 -1
  41. package/dist/params.cjs +114 -15
  42. package/dist/params.cjs.map +1 -1
  43. package/dist/params.js +114 -15
  44. package/dist/params.js.map +1 -1
  45. package/package.json +9 -2
package/dist/init.cjs CHANGED
@@ -1143,20 +1143,31 @@ var Args = class _Args {
1143
1143
  configValues = {};
1144
1144
  configsLoaded = [];
1145
1145
  env = "local";
1146
- constructor(config2 = {}) {
1146
+ constructor(contextOrConfig = {}, config2) {
1147
+ const hasContext = config2 !== void 0;
1148
+ const configToUse = hasContext ? config2 ?? {} : contextOrConfig ?? {};
1149
+ const context = hasContext ? contextOrConfig : void 0;
1147
1150
  this.aliases = {};
1148
1151
  this.overrides = {};
1149
1152
  this.defaults = {};
1150
1153
  this.prefixes = ["not", "no"];
1151
- if (Object.keys(config2).length > 0) {
1152
- this.configure(config2);
1154
+ if (Object.keys(configToUse).length > 0) {
1155
+ this.configure(configToUse);
1153
1156
  }
1154
- const args = config2.args || process.argv.slice(2);
1157
+ const args = configToUse.args || process.argv.slice(2);
1155
1158
  this.parseArgs(args);
1156
1159
  this.env = this.get("env")?.toLowerCase() || "local";
1157
1160
  this.loadDotEnv();
1158
1161
  this.loadConfigFiles();
1159
1162
  this.checkConflicts();
1163
+ if (context && typeof context.registerCleanup === "function") {
1164
+ context.registerCleanup((ctx) => {
1165
+ const unusedArgs = ctx.args.getUnused();
1166
+ if (unusedArgs.length > 0) {
1167
+ ctx.logger.warn("Unused CLI args:", unusedArgs.join(", "));
1168
+ }
1169
+ });
1170
+ }
1160
1171
  }
1161
1172
  /**
1162
1173
  * Configure Args options
@@ -1178,12 +1189,15 @@ var Args = class _Args {
1178
1189
  }
1179
1190
  }
1180
1191
  /**
1181
- * Initialize Args instance
1182
- * Note: Args is special - it's initialized first, so it can't take context
1183
- * This static method is for consistency with other components
1192
+ * Initialize Args instance.
1193
+ * Args.init(context, config) when used from init/setup: context has registerCleanup, Args registers unused-args cleanup.
1194
+ * Args.init(config) for standalone use (no cleanup).
1184
1195
  */
1185
- static init(config2 = {}) {
1186
- return new _Args(config2);
1196
+ static init(contextOrConfig, config2) {
1197
+ if (config2 !== void 0) {
1198
+ return new _Args(contextOrConfig, config2);
1199
+ }
1200
+ return new _Args(contextOrConfig ?? {});
1187
1201
  }
1188
1202
  /**
1189
1203
  * Parse command line arguments
@@ -1363,6 +1377,32 @@ var Args = class _Args {
1363
1377
  }
1364
1378
  return void 0;
1365
1379
  }
1380
+ /**
1381
+ * Return which layer provided the value for get(key): overrides, cli, config, env, or default.
1382
+ * Does not add key to usedKeys. Use after get(key) when you need the origin.
1383
+ */
1384
+ getSource(key) {
1385
+ const resolvedKey = this.aliases[key] || key;
1386
+ const lcKey = resolvedKey.toLowerCase();
1387
+ const overrideKey = Object.keys(this.overrides).find((k) => k.toLowerCase() === lcKey);
1388
+ if (overrideKey !== void 0) return "overrides";
1389
+ const lcKeyWithEnv = `${lcKey}${this.env ? `_${this.env.toLowerCase()}` : ""}`;
1390
+ if (this.env && this.args[lcKeyWithEnv] !== void 0) return "cli";
1391
+ if (this.args[lcKey] !== void 0) return "cli";
1392
+ const configKey = Object.keys(this.configValues).find((k) => k.toLowerCase() === lcKey);
1393
+ if (configKey !== void 0) return "config";
1394
+ const envKey = this.toEnvKey(resolvedKey);
1395
+ const envKeyWithEnv = `${envKey}${this.env ? `_${this.env.toUpperCase()}` : ""}`;
1396
+ const envSpecificKey = Object.keys(process.env).find((k) => this.env && k.toUpperCase() === envKeyWithEnv);
1397
+ const envKeyFound = Object.keys(process.env).find((k) => k.toUpperCase() === envKey);
1398
+ const envKeyAlt = envKey.replace(/_([0-9])/g, "$1");
1399
+ const envKeyAltFound = !envKeyFound ? Object.keys(process.env).find((k) => k.toUpperCase() === envKeyAlt) : null;
1400
+ if (envSpecificKey || envKeyFound || envKeyAltFound) return "env";
1401
+ const defaultKey = Object.keys(this.defaults).find((k) => k.toLowerCase() === lcKey);
1402
+ if (defaultKey !== void 0) return "default";
1403
+ if (lcKey === "env" && process.env.NODE_ENV !== void 0) return "env";
1404
+ return void 0;
1405
+ }
1366
1406
  /**
1367
1407
  * Set a value (for testing/internal use)
1368
1408
  */
@@ -1715,17 +1755,53 @@ var Params = class _Params {
1715
1755
  context;
1716
1756
  // Partial context during initialization
1717
1757
  params = {};
1758
+ paramSources = {};
1718
1759
  definitions = {};
1719
1760
  args;
1720
1761
  paramSetters = [];
1721
1762
  paramGetters = [];
1722
1763
  trackedParams = [];
1764
+ _currentModule = "script";
1765
+ /** Resolved early in constructor so cleanup does not read params lazily */
1766
+ _showUsedParams = false;
1723
1767
  constructor(context, options = {}) {
1724
1768
  this.context = context;
1725
1769
  this.args = context.args;
1726
1770
  if (Object.keys(options).length > 0) {
1727
1771
  this.configure(options);
1728
1772
  }
1773
+ this._showUsedParams = this.get("showUsedParams", "boolean default false");
1774
+ if (context && typeof context.registerCleanup === "function") {
1775
+ context.registerCleanup((ctx) => {
1776
+ if (!ctx.params.getShowUsedParams()) return;
1777
+ const byModule = ctx.params.getFiguredByModule();
1778
+ const modules = Object.keys(byModule).sort();
1779
+ if (modules.length === 0) return;
1780
+ const logger = ctx.logger;
1781
+ logger.debug("[Params]: list of used params:");
1782
+ if (typeof logger.highlight !== "function") {
1783
+ for (const mod of modules) {
1784
+ logger.debug(` [${mod}]`);
1785
+ for (const [key, entry] of Object.entries(byModule[mod])) {
1786
+ logger.debug(` ${key}: ${JSON.stringify(entry.value)} (${entry.source})`);
1787
+ }
1788
+ }
1789
+ return;
1790
+ }
1791
+ for (const mod of modules) {
1792
+ logger.debug(` [${mod}]`);
1793
+ for (const [key, entry] of Object.entries(byModule[mod])) {
1794
+ const valueStr = JSON.stringify(entry.value);
1795
+ const display = entry.source === "default" ? valueStr : logger.highlight(valueStr);
1796
+ logger.debug(` ${key}: ${display} (${entry.source})`);
1797
+ }
1798
+ }
1799
+ });
1800
+ }
1801
+ }
1802
+ /** Whether --showUsedParams was requested (resolved in constructor). */
1803
+ getShowUsedParams() {
1804
+ return this._showUsedParams;
1729
1805
  }
1730
1806
  /**
1731
1807
  * Configure parameters
@@ -1744,14 +1820,15 @@ var Params = class _Params {
1744
1820
  return new _Params(context, options || {});
1745
1821
  }
1746
1822
  /**
1747
- * Track a parameter request for --stopAfter=init feature
1823
+ * Track a parameter request for --stopAfter=init and --showUsedParams
1748
1824
  */
1749
- trackParam(key, definition, value, source) {
1825
+ trackParam(key, definition, value, source, moduleName) {
1750
1826
  this.trackedParams.push({
1751
1827
  key,
1752
1828
  definition,
1753
1829
  value,
1754
- source
1830
+ source,
1831
+ module: moduleName ?? this._currentModule
1755
1832
  });
1756
1833
  }
1757
1834
  /**
@@ -1761,7 +1838,7 @@ var Params = class _Params {
1761
1838
  return [...this.trackedParams];
1762
1839
  }
1763
1840
  /**
1764
- * Get all figured parameters as a record
1841
+ * Get all figured parameters as a record (flat, last occurrence per key)
1765
1842
  * Returns all parameters that were collected during initialization,
1766
1843
  * whether from CLI args, options, or defaults
1767
1844
  */
@@ -1775,6 +1852,19 @@ var Params = class _Params {
1775
1852
  }
1776
1853
  return result;
1777
1854
  }
1855
+ /**
1856
+ * Get figured parameters grouped by module name.
1857
+ * Same param can appear in multiple modules (e.g. source, resource).
1858
+ */
1859
+ getFiguredByModule() {
1860
+ const byModule = {};
1861
+ for (const param of this.trackedParams) {
1862
+ const mod = param.module;
1863
+ if (!byModule[mod]) byModule[mod] = {};
1864
+ byModule[mod][param.key] = { value: param.value, source: param.source };
1865
+ }
1866
+ return byModule;
1867
+ }
1778
1868
  /**
1779
1869
  * Clear tracked parameters
1780
1870
  */
@@ -1893,14 +1983,19 @@ var Params = class _Params {
1893
1983
  source = "options";
1894
1984
  } else if (valFromArgs !== void 0 && valFromArgs !== null) {
1895
1985
  value = this.validate(key, valFromArgs, def);
1896
- source = "cli";
1986
+ const argsSource = this.args.getSource?.(key);
1987
+ if (argsSource === "overrides") source = "options";
1988
+ else if (argsSource === "cli" || argsSource === "env" || argsSource === "config") source = argsSource;
1989
+ else if (argsSource === "default") source = "default";
1990
+ else source = "cli";
1897
1991
  } else if (valFromParams !== void 0 && valFromParams !== null) {
1898
1992
  value = this.validate(key, valFromParams, def);
1899
- source = "options";
1993
+ source = this.paramSources[key] ?? "options";
1900
1994
  } else {
1901
1995
  value = this.validate(key, void 0, def);
1902
1996
  source = "default";
1903
1997
  }
1998
+ this.paramSources[key] = source;
1904
1999
  this.trackParam(key, definition || "string", value, source);
1905
2000
  if (value !== void 0 && def.values && !def.values.includes(value)) {
1906
2001
  throw new ParamError(`key ${key} should be one of ${def.values}`);
@@ -1921,19 +2016,63 @@ var Params = class _Params {
1921
2016
  }
1922
2017
  }
1923
2018
  /**
1924
- * Get all parameters from definitions
1925
- * Processes parameters left-to-right to support cross-parameter references
2019
+ * Get all parameters from definitions (main script).
2020
+ * Same as getAllForModule("script", defs). Processes left-to-right for cross-parameter references.
1926
2021
  */
1927
2022
  getAll(defs) {
1928
- const res = {};
1929
- for (const [k, def] of Object.entries(defs)) {
1930
- const value = this.get(k, def);
1931
- res[k] = value;
1932
- if (value !== void 0) {
1933
- this.params[k] = value;
2023
+ return this.getAllForModule("script", defs);
2024
+ }
2025
+ /**
2026
+ * Get all parameters from definitions for a given module name.
2027
+ * Figured params are grouped by module when using --showUsedParams.
2028
+ * Processes parameters left-to-right to support cross-parameter references.
2029
+ * If moduleName is omitted, it is inferred from the caller's file path (directory name under src/).
2030
+ */
2031
+ getAllForModule(moduleNameOrDefs, defs) {
2032
+ let moduleName;
2033
+ let definitions;
2034
+ if (defs !== void 0) {
2035
+ moduleName = moduleNameOrDefs;
2036
+ definitions = defs;
2037
+ } else {
2038
+ definitions = moduleNameOrDefs;
2039
+ moduleName = this._inferModuleNameFromStack();
2040
+ }
2041
+ const prev = this._currentModule;
2042
+ this._currentModule = moduleName;
2043
+ try {
2044
+ const res = {};
2045
+ for (const [k, def] of Object.entries(definitions)) {
2046
+ const value = this.get(k, def);
2047
+ res[k] = value;
2048
+ if (value !== void 0) {
2049
+ this.params[k] = value;
2050
+ }
1934
2051
  }
2052
+ return res;
2053
+ } finally {
2054
+ this._currentModule = prev;
1935
2055
  }
1936
- return res;
2056
+ }
2057
+ /**
2058
+ * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...
2059
+ */
2060
+ _inferModuleNameFromStack() {
2061
+ const stack = new Error().stack;
2062
+ if (!stack) return "script";
2063
+ const lines = stack.split("\n");
2064
+ const paramsIndexPath = "params" + (typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/") + "index.";
2065
+ for (const line of lines) {
2066
+ const parenMatch = line.match(/\(([^)]+)\)/);
2067
+ if (!parenMatch) continue;
2068
+ const parts = parenMatch[1].split(":");
2069
+ if (parts.length < 3) continue;
2070
+ const path = parts.slice(0, -2).join(":").replace(/^file:\/\//, "");
2071
+ if (!path || path.includes(paramsIndexPath)) continue;
2072
+ const srcMatch = path.match(/[/\\]src[/\\]([^/\\]+)(?:[/\\]|$)/);
2073
+ if (srcMatch) return srcMatch[1];
2074
+ }
2075
+ return "script";
1937
2076
  }
1938
2077
  /**
1939
2078
  * Run all registered getters for a key
@@ -2043,8 +2182,7 @@ var Logger = class _Logger {
2043
2182
  this.updateTransport();
2044
2183
  }
2045
2184
  /**
2046
- * Configure logger options
2047
- * Only parameters present in options are updated
2185
+ * Configure logger options. Accepts both LoggerOptions shape and flat param names (levels string, progressWithTimes, progressThrottleMs).
2048
2186
  */
2049
2187
  configure(options) {
2050
2188
  if (options.mode !== void 0) {
@@ -2054,32 +2192,24 @@ var Logger = class _Logger {
2054
2192
  this.options.route = options.route;
2055
2193
  this.updateTransport();
2056
2194
  }
2057
- if (options.prefix !== void 0) {
2058
- this.options.prefix = options.prefix;
2059
- }
2060
- if (options.silent !== void 0) {
2061
- this.options.silent = options.silent;
2062
- }
2063
- if (options.showLevel !== void 0) {
2064
- this.options.showLevel = options.showLevel;
2065
- }
2066
- if (options.timestamp !== void 0) {
2067
- this.options.timestamp = options.timestamp;
2068
- }
2195
+ if (options.prefix !== void 0) this.options.prefix = options.prefix;
2196
+ if (options.silent !== void 0) this.options.silent = options.silent;
2197
+ if (options.showLevel !== void 0) this.options.showLevel = options.showLevel;
2198
+ if (options.timestamp !== void 0) this.options.timestamp = options.timestamp;
2069
2199
  if (options.levels !== void 0) {
2070
- this.options.levels = this.normalizeLevels(options.levels);
2200
+ const levels = typeof options.levels === "string" ? options.levels.split(",") : options.levels;
2201
+ this.options.levels = this.normalizeLevels(levels);
2071
2202
  }
2072
2203
  if (options.progress !== void 0) {
2073
- if (options.progress.withTimes !== void 0) {
2074
- this.options.progressTimes = options.progress.withTimes;
2075
- }
2076
- if (options.progress.throttleMs !== void 0) {
2077
- this.options.progressThrottle = options.progress.throttleMs;
2078
- }
2204
+ if (options.progress.withTimes !== void 0) this.options.progressTimes = options.progress.withTimes;
2205
+ if (options.progress.throttleMs !== void 0) this.options.progressThrottle = options.progress.throttleMs;
2079
2206
  }
2207
+ const flat = options;
2208
+ if (flat.progressWithTimes !== void 0) this.options.progressTimes = flat.progressWithTimes;
2209
+ if (flat.progressThrottleMs !== void 0) this.options.progressThrottle = flat.progressThrottleMs;
2080
2210
  }
2081
2211
  /**
2082
- * Initialize logger from context and CLI parameters
2212
+ * Initialize logger from context and CLI parameters. Whatever is in options goes (after discovered params).
2083
2213
  */
2084
2214
  static init(context, options) {
2085
2215
  const paramDefs = {
@@ -2093,20 +2223,8 @@ var Logger = class _Logger {
2093
2223
  progressWithTimes: "boolean default false",
2094
2224
  progressThrottleMs: "number"
2095
2225
  };
2096
- const cliParams = context.params.getAll(paramDefs);
2097
- const config2 = {
2098
- mode: options?.mode ?? cliParams.mode,
2099
- route: options?.route ?? cliParams.route,
2100
- prefix: options?.prefix ?? cliParams.prefix,
2101
- silent: options?.silent ?? cliParams.silent,
2102
- showLevel: options?.showLevel ?? cliParams.showLevel,
2103
- timestamp: options?.timestamp ?? cliParams.timestamp,
2104
- levels: options?.levels ?? (cliParams.levels ? cliParams.levels.split(",") : void 0),
2105
- progress: options?.progress ?? {
2106
- withTimes: cliParams.progressWithTimes,
2107
- throttleMs: cliParams.progressThrottleMs
2108
- }
2109
- };
2226
+ const discovered = context.params.getAllForModule(paramDefs);
2227
+ const config2 = { ...discovered, ...options };
2110
2228
  const logger = new _Logger(context, config2);
2111
2229
  context.logger = logger;
2112
2230
  return logger;
@@ -2133,6 +2251,10 @@ var Logger = class _Logger {
2133
2251
  }
2134
2252
  this.options.mode = mode;
2135
2253
  }
2254
+ /** Returns a styled string (bright white) for highlighting; keeps chalk inside logger. */
2255
+ highlight(text) {
2256
+ return import_chalk.default.whiteBright(text);
2257
+ }
2136
2258
  debug(message, ...chunks) {
2137
2259
  this.out({ level: "debug", message, chunks });
2138
2260
  }
@@ -2308,12 +2430,7 @@ function extractComponentOptions(opts, componentName) {
2308
2430
  return componentOptions;
2309
2431
  }
2310
2432
  function setup(opts = {}) {
2311
- const args = Args.init({
2312
- overrides: opts.overrides || {},
2313
- defaults: opts.defaults || {}
2314
- });
2315
2433
  const partialContext = {
2316
- args,
2317
2434
  emitter: new import_events.EventEmitter(),
2318
2435
  isStop: () => false,
2319
2436
  cleanupFunctions: [],
@@ -2321,6 +2438,11 @@ function setup(opts = {}) {
2321
2438
  partialContext.cleanupFunctions.push(fn);
2322
2439
  }
2323
2440
  };
2441
+ const args = Args.init(partialContext, {
2442
+ overrides: opts.overrides || {},
2443
+ defaults: opts.defaults || {}
2444
+ });
2445
+ partialContext.args = args;
2324
2446
  const params = Params.init(partialContext, opts.overrides || {});
2325
2447
  partialContext.params = params;
2326
2448
  const loggerOptions = extractComponentOptions(opts, "logger");
@@ -2381,6 +2503,7 @@ async function init(flow, opts = {}) {
2381
2503
  context.isStop = () => stop;
2382
2504
  context = await setupModules(context, opts);
2383
2505
  const stopAfter = context.args.get("stopAfter");
2506
+ const stopAllowance = context.params.get("stopAllowance", "number default 5");
2384
2507
  if (stopAfter === "init") {
2385
2508
  printAllParameters(context);
2386
2509
  process.exit(0);
@@ -2391,13 +2514,8 @@ async function init(flow, opts = {}) {
2391
2514
  process.exit(2);
2392
2515
  }
2393
2516
  stop = true;
2394
- let allowance = 5;
2395
- try {
2396
- allowance = context.params.get("stopAllowance", "number default 5");
2397
- } catch {
2398
- }
2399
- context.logger.info(`>> emitting stop with allowance ${allowance}`);
2400
- context.emitter.emit("stop", allowance);
2517
+ context.logger.info(`>> emitting stop with allowance ${stopAllowance}`);
2518
+ context.emitter.emit("stop", stopAllowance);
2401
2519
  });
2402
2520
  await flow(context);
2403
2521
  } catch (error) {
@@ -2428,10 +2546,6 @@ async function init(flow, opts = {}) {
2428
2546
  context.logger.warn("[cleanup] error in cleanup function:", error);
2429
2547
  }
2430
2548
  }
2431
- const unusedArgs = context.args.getUnused();
2432
- if (unusedArgs.length > 0) {
2433
- context.logger.warn("Unused CLI args:", unusedArgs.join(", "));
2434
- }
2435
2549
  }
2436
2550
  }
2437
2551
  }