@nmakarov/cli-toolkit 0.14.0 → 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 (49) 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 +214 -91
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +214 -90
  28. package/dist/index.js.map +1 -1
  29. package/dist/init.cjs +192 -76
  30. package/dist/init.cjs.map +1 -1
  31. package/dist/init.js +192 -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/dist/screen.cjs +2 -0
  46. package/dist/screen.cjs.map +1 -1
  47. package/dist/screen.js +2 -0
  48. package/dist/screen.js.map +1 -1
  49. package/package.json +9 -2
package/dist/params.cjs CHANGED
@@ -177,17 +177,53 @@ var Params = class _Params {
177
177
  context;
178
178
  // Partial context during initialization
179
179
  params = {};
180
+ paramSources = {};
180
181
  definitions = {};
181
182
  args;
182
183
  paramSetters = [];
183
184
  paramGetters = [];
184
185
  trackedParams = [];
186
+ _currentModule = "script";
187
+ /** Resolved early in constructor so cleanup does not read params lazily */
188
+ _showUsedParams = false;
185
189
  constructor(context, options = {}) {
186
190
  this.context = context;
187
191
  this.args = context.args;
188
192
  if (Object.keys(options).length > 0) {
189
193
  this.configure(options);
190
194
  }
195
+ this._showUsedParams = this.get("showUsedParams", "boolean default false");
196
+ if (context && typeof context.registerCleanup === "function") {
197
+ context.registerCleanup((ctx) => {
198
+ if (!ctx.params.getShowUsedParams()) return;
199
+ const byModule = ctx.params.getFiguredByModule();
200
+ const modules = Object.keys(byModule).sort();
201
+ if (modules.length === 0) return;
202
+ const logger = ctx.logger;
203
+ logger.debug("[Params]: list of used params:");
204
+ if (typeof logger.highlight !== "function") {
205
+ for (const mod of modules) {
206
+ logger.debug(` [${mod}]`);
207
+ for (const [key, entry] of Object.entries(byModule[mod])) {
208
+ logger.debug(` ${key}: ${JSON.stringify(entry.value)} (${entry.source})`);
209
+ }
210
+ }
211
+ return;
212
+ }
213
+ for (const mod of modules) {
214
+ logger.debug(` [${mod}]`);
215
+ for (const [key, entry] of Object.entries(byModule[mod])) {
216
+ const valueStr = JSON.stringify(entry.value);
217
+ const display = entry.source === "default" ? valueStr : logger.highlight(valueStr);
218
+ logger.debug(` ${key}: ${display} (${entry.source})`);
219
+ }
220
+ }
221
+ });
222
+ }
223
+ }
224
+ /** Whether --showUsedParams was requested (resolved in constructor). */
225
+ getShowUsedParams() {
226
+ return this._showUsedParams;
191
227
  }
192
228
  /**
193
229
  * Configure parameters
@@ -206,14 +242,15 @@ var Params = class _Params {
206
242
  return new _Params(context, options || {});
207
243
  }
208
244
  /**
209
- * Track a parameter request for --stopAfter=init feature
245
+ * Track a parameter request for --stopAfter=init and --showUsedParams
210
246
  */
211
- trackParam(key, definition, value, source) {
247
+ trackParam(key, definition, value, source, moduleName) {
212
248
  this.trackedParams.push({
213
249
  key,
214
250
  definition,
215
251
  value,
216
- source
252
+ source,
253
+ module: moduleName ?? this._currentModule
217
254
  });
218
255
  }
219
256
  /**
@@ -223,7 +260,7 @@ var Params = class _Params {
223
260
  return [...this.trackedParams];
224
261
  }
225
262
  /**
226
- * Get all figured parameters as a record
263
+ * Get all figured parameters as a record (flat, last occurrence per key)
227
264
  * Returns all parameters that were collected during initialization,
228
265
  * whether from CLI args, options, or defaults
229
266
  */
@@ -237,6 +274,19 @@ var Params = class _Params {
237
274
  }
238
275
  return result;
239
276
  }
277
+ /**
278
+ * Get figured parameters grouped by module name.
279
+ * Same param can appear in multiple modules (e.g. source, resource).
280
+ */
281
+ getFiguredByModule() {
282
+ const byModule = {};
283
+ for (const param of this.trackedParams) {
284
+ const mod = param.module;
285
+ if (!byModule[mod]) byModule[mod] = {};
286
+ byModule[mod][param.key] = { value: param.value, source: param.source };
287
+ }
288
+ return byModule;
289
+ }
240
290
  /**
241
291
  * Clear tracked parameters
242
292
  */
@@ -355,14 +405,19 @@ var Params = class _Params {
355
405
  source = "options";
356
406
  } else if (valFromArgs !== void 0 && valFromArgs !== null) {
357
407
  value = this.validate(key, valFromArgs, def);
358
- source = "cli";
408
+ const argsSource = this.args.getSource?.(key);
409
+ if (argsSource === "overrides") source = "options";
410
+ else if (argsSource === "cli" || argsSource === "env" || argsSource === "config") source = argsSource;
411
+ else if (argsSource === "default") source = "default";
412
+ else source = "cli";
359
413
  } else if (valFromParams !== void 0 && valFromParams !== null) {
360
414
  value = this.validate(key, valFromParams, def);
361
- source = "options";
415
+ source = this.paramSources[key] ?? "options";
362
416
  } else {
363
417
  value = this.validate(key, void 0, def);
364
418
  source = "default";
365
419
  }
420
+ this.paramSources[key] = source;
366
421
  this.trackParam(key, definition || "string", value, source);
367
422
  if (value !== void 0 && def.values && !def.values.includes(value)) {
368
423
  throw new ParamError(`key ${key} should be one of ${def.values}`);
@@ -383,19 +438,63 @@ var Params = class _Params {
383
438
  }
384
439
  }
385
440
  /**
386
- * Get all parameters from definitions
387
- * Processes parameters left-to-right to support cross-parameter references
441
+ * Get all parameters from definitions (main script).
442
+ * Same as getAllForModule("script", defs). Processes left-to-right for cross-parameter references.
388
443
  */
389
444
  getAll(defs) {
390
- const res = {};
391
- for (const [k, def] of Object.entries(defs)) {
392
- const value = this.get(k, def);
393
- res[k] = value;
394
- if (value !== void 0) {
395
- this.params[k] = value;
445
+ return this.getAllForModule("script", defs);
446
+ }
447
+ /**
448
+ * Get all parameters from definitions for a given module name.
449
+ * Figured params are grouped by module when using --showUsedParams.
450
+ * Processes parameters left-to-right to support cross-parameter references.
451
+ * If moduleName is omitted, it is inferred from the caller's file path (directory name under src/).
452
+ */
453
+ getAllForModule(moduleNameOrDefs, defs) {
454
+ let moduleName;
455
+ let definitions;
456
+ if (defs !== void 0) {
457
+ moduleName = moduleNameOrDefs;
458
+ definitions = defs;
459
+ } else {
460
+ definitions = moduleNameOrDefs;
461
+ moduleName = this._inferModuleNameFromStack();
462
+ }
463
+ const prev = this._currentModule;
464
+ this._currentModule = moduleName;
465
+ try {
466
+ const res = {};
467
+ for (const [k, def] of Object.entries(definitions)) {
468
+ const value = this.get(k, def);
469
+ res[k] = value;
470
+ if (value !== void 0) {
471
+ this.params[k] = value;
472
+ }
396
473
  }
474
+ return res;
475
+ } finally {
476
+ this._currentModule = prev;
477
+ }
478
+ }
479
+ /**
480
+ * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...
481
+ */
482
+ _inferModuleNameFromStack() {
483
+ const stack = new Error().stack;
484
+ if (!stack) return "script";
485
+ const lines = stack.split("\n");
486
+ const paramsIndexPath = "params" + (typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/") + "index.";
487
+ for (const line of lines) {
488
+ const parenMatch = line.match(/\(([^)]+)\)/);
489
+ if (!parenMatch) continue;
490
+ const parts = parenMatch[1].split(":");
491
+ if (parts.length < 3) continue;
492
+ const path = parts.slice(0, -2).join(":").replace(/^file:\/\//, "");
493
+ if (!path || path.includes(paramsIndexPath)) continue;
494
+ const srcMatch = path.match(/[/\\]src[/\\]([^/\\]+)(?:[/\\]|$)/);
495
+ if (srcMatch) return srcMatch[1];
397
496
  }
398
- return res;
497
+ return "script";
399
498
  }
400
499
  /**
401
500
  * Run all registered getters for a key
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/params.ts","../src/params/index.ts","../src/errors.ts","../src/params/custom-types.ts"],"sourcesContent":["// Re-export everything from the params module directory\nexport * from \"./params/index.js\";\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors\";\nimport { joiEdateType, joiStringArrayType } from \"./custom-types\";\n\n/**\n * Parameter definition types\n */\nexport type ParamDefinition = \n | string \n | Joi.Schema \n | { \n type?: string | Joi.Schema; \n values?: any[]; \n [key: string]: any; \n };\n\nexport type ParamGetter = (key: string, definition?: any) => any;\nexport type ParamSetter = (key: string, value: any) => boolean;\n\n/**\n * Args instance interface\n */\nexport interface ArgsInstance {\n get(key: string): any;\n}\n\n/**\n * Params constructor options\n */\nexport interface ParamsOptions {\n [key: string]: any;\n}\n\n/**\n * Tracked parameter information for --stopAfter=init\n */\ninterface TrackedParam {\n key: string;\n definition: ParamDefinition;\n value: any;\n source: \"cli\" | \"options\" | \"default\";\n}\n\n/**\n * Params class for parameter validation and type checking\n * Built on top of Args library with Joi validation\n */\nexport class Params {\n private context: any; // Partial context during initialization\n private params: Record<string, any> = {};\n private definitions: Record<string, any> = {};\n private args: ArgsInstance;\n private paramSetters: ParamSetter[] = [];\n private paramGetters: ParamGetter[] = [];\n private trackedParams: TrackedParam[] = [];\n\n constructor(context: any, options: ParamsOptions = {}) {\n // Context might be partial during initialization\n this.context = context;\n this.args = context.args;\n\n // Apply initial configuration\n if (Object.keys(options).length > 0) {\n this.configure(options);\n }\n }\n\n /**\n * Configure parameters\n * Only parameters present in options are updated\n */\n configure(options: ParamsOptions): void {\n for (const [k, v] of Object.entries(options)) {\n // TODO: opt values might be an object with definitions in it, so perhaps `this.set` should be used\n this.params[k] = v;\n }\n }\n\n /**\n * Initialize Params from context and CLI parameters\n * Note: Params is special - it's initialized early with partial context\n */\n static init(context: any, options?: ParamsOptions): Params {\n return new Params(context, options || {});\n }\n\n /**\n * Track a parameter request for --stopAfter=init feature\n */\n private trackParam(key: string, definition: ParamDefinition, value: any, source: \"cli\" | \"options\" | \"default\"): void {\n this.trackedParams.push({\n key,\n definition,\n value,\n source\n });\n }\n\n /**\n * Get all tracked parameters (for --stopAfter=init)\n */\n getTrackedParams(): TrackedParam[] {\n return [...this.trackedParams];\n }\n\n /**\n * Get all figured parameters as a record\n * Returns all parameters that were collected during initialization,\n * whether from CLI args, options, or defaults\n */\n getAllFigured(): Record<string, { value: any; source: \"cli\" | \"options\" | \"default\" }> {\n const result: Record<string, { value: any; source: \"cli\" | \"options\" | \"default\" }> = {};\n for (const param of this.trackedParams) {\n result[param.key] = {\n value: param.value,\n source: param.source,\n };\n }\n return result;\n }\n\n /**\n * Clear tracked parameters\n */\n clearTrackedParams(): void {\n this.trackedParams = [];\n }\n\n /**\n * Assign a parameter definition\n */\n assignDefinition(key: string, definition?: ParamDefinition): any {\n if (this.definitions[key] && !definition) {\n return this.definitions[key];\n }\n\n let type: Joi.Schema;\n if (!definition) {\n type = Joi.string();\n } else if (Joi.isSchema(definition)) {\n type = definition;\n } else if (Joi.isSchema(definition.type)) {\n type = definition.type;\n } else if (typeof definition === \"string\") {\n type = this.toJoi(definition);\n } else if (typeof definition.type === \"string\") {\n type = this.toJoi(definition.type);\n } else if (!definition.type) {\n type = Joi.string();\n } else {\n type = Joi.string();\n }\n\n if (!this.definitions[key]) {\n this.definitions[key] = {};\n }\n this.definitions[key].type = type;\n\n if (definition && definition.values) {\n if (Array.isArray(definition.values)) {\n this.definitions[key].values = definition.values;\n }\n }\n return this.definitions[key];\n }\n\n /**\n * Convert string definition to Joi schema\n */\n toJoi(str: string): Joi.Schema {\n let type: Joi.Schema;\n \n if (str.match(/^string|^text/i)) {\n type = Joi.string();\n } else if (str.match(/^number|^integer|^int/i)) {\n type = Joi.number();\n } else if (str.match(/^boolean|^bool/i)) {\n type = Joi.boolean();\n } else if (str.match(/^date/i)) {\n type = Joi.custom(joiEdateType);\n } else if (str.match(/^duration/i)) {\n type = Joi.string().isoDuration();\n } else if (str.match(/^array/i)) {\n let elementTypes = \"string\";\n const tmp = str.match(/\\((.*)\\)/);\n if (tmp && tmp[1].match(/string/i)) {\n elementTypes = \"string\";\n } else if (tmp && tmp[1].match(/number|integer|int/i)) {\n elementTypes = \"number\";\n } else if (tmp && tmp[1].match(/boolean|bool/i)) {\n elementTypes = \"boolean\";\n }\n type = Joi.custom(joiStringArrayType(elementTypes));\n } else {\n type = Joi.string();\n }\n\n // Handle default values\n const regexForDefault = /\\bdefault\\s+([^\\s]+)/;\n const matchForDefault = str.match(regexForDefault);\n if (matchForDefault) {\n const defValObj = type.validate(matchForDefault[1]);\n if (defValObj.error) {\n throw new ParamError(`default value \"${defValObj.value}\" type mismatch`);\n }\n // Joi's default() automatically allows undefined and applies the default\n type = type.default(defValObj.value);\n } else if (str.match(/required/)) {\n type = type.required();\n } else {\n // If not required and no default, make it optional\n type = type.optional();\n }\n\n return type;\n }\n\n /**\n * Validate a value against a definition\n */\n validate(key: string, val: any, def: any): any {\n // Convert null to undefined so Joi defaults can be applied\n // Joi's .default() only works with undefined, not null\n const normalizedVal = val === null ? undefined : val;\n \n // Pass current params as context to support cross-parameter references (e.g., @startTime+2h)\n // Use abortEarly: false to get all errors, and allowUnknown: false for strict validation\n const { value, error } = def.type.validate(normalizedVal, { \n context: { params: this.params },\n abortEarly: false,\n allowUnknown: false,\n });\n if (error) {\n const errs = error.details.map((el: any) => el.message).join(\", \");\n throw new ParamError(`\"${key}\" validation error: ${errs}`);\n }\n return value;\n }\n\n /**\n * Get a parameter value with validation\n */\n get(key: string, definition?: ParamDefinition): any {\n const def = this.assignDefinition(key, definition);\n let valFromGetters: any = undefined;\n \n if (def.volatile || true) {\n valFromGetters = this.runAllRegisteredGetters(key);\n }\n \n // Always call args.get() to mark the key as used, even if it doesn't exist\n // This ensures flags are marked as used regardless of when they're parsed\n const valFromArgs = this.args.get(key);\n const valFromParams = this.params[key];\n\n let source: \"cli\" | \"options\" | \"default\" = \"default\";\n let value: any;\n\n if (valFromGetters !== undefined && valFromGetters !== null) {\n value = this.validate(key, valFromGetters, def);\n source = \"options\";\n } else if (valFromArgs !== undefined && valFromArgs !== null) {\n value = this.validate(key, valFromArgs, def);\n source = \"cli\";\n } else if (valFromParams !== undefined && valFromParams !== null) {\n value = this.validate(key, valFromParams, def);\n source = \"options\";\n } else {\n // Use default from definition - Joi will apply default when value is undefined\n // We need to pass undefined explicitly so Joi can apply the default\n value = this.validate(key, undefined, def);\n source = \"default\";\n }\n\n // Track parameter for --stopAfter=init\n this.trackParam(key, definition || \"string\", value, source);\n\n if (value !== undefined && def.values && !def.values.includes(value)) {\n throw new ParamError(`key ${key} should be one of ${def.values}`);\n }\n return value;\n }\n\n /**\n * Set a parameter value with validation\n */\n set(key: string, val: any, definition?: ParamDefinition): void {\n // TODO: check if there's a test for this:\n if (val && val.type && val.value) {\n definition = val;\n val = val.value;\n }\n const def = this.assignDefinition(key, definition);\n\n if (!this.runAllRegisteredSetters(key, val)) {\n this.params[key] = val;\n }\n }\n\n /**\n * Get all parameters from definitions\n * Processes parameters left-to-right to support cross-parameter references\n */\n getAll(defs: Record<string, ParamDefinition>): Record<string, any> {\n const res: Record<string, any> = {};\n for (const [k, def] of Object.entries(defs)) {\n const value = this.get(k, def);\n res[k] = value;\n // Store validated value in params so subsequent params can reference it\n if (value !== undefined) {\n this.params[k] = value;\n }\n }\n return res;\n }\n\n /**\n * Run all registered getters for a key\n */\n runAllRegisteredGetters(key: string): any {\n let val: any = undefined;\n for (const getter of this.paramGetters) {\n val = getter(key, this.definitions[key]);\n if (val !== undefined && val !== null) {\n break;\n }\n }\n return val;\n }\n\n /**\n * Run all registered setters for a key\n */\n runAllRegisteredSetters(key: string, value: any): boolean {\n let setterUsed: boolean = false;\n for (const setter of this.paramSetters) {\n setterUsed = setter(key, value);\n if (setterUsed) {\n break;\n }\n }\n return setterUsed;\n }\n\n /**\n * Register a parameter getter\n */\n registerParamGetter(fn: ParamGetter): void {\n this.paramGetters.push(fn);\n }\n\n /**\n * Register a parameter setter\n */\n registerParamSetter(fn: ParamSetter): void {\n this.paramSetters.push(fn);\n }\n}\n\n// Export custom types for external use\nexport { joiEdateType, joiStringArrayType };\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors.js\";\n\n/**\n * Custom Joi type for enhanced date parsing with relative time support\n * Supports:\n * - ISO8601 strings: \"2025-01-01T01:01:01Z\"\n * - Relative time: \"-2h\", \"+1d\", \"now\"\n * - Cross-parameter references: \"@startTime+2h\", \"@endDate-30m\"\n * \n * Internal representation: UTC ISO8601 string (YYYY-MM-DDTHH:mm:ssZ)\n * \n * @param value - Date value to parse\n * @param helpers - Joi helpers (includes context with other params)\n * @returns ISO8601 string in UTC timezone\n */\nexport const joiEdateType = (value: any, helpers: Joi.CustomHelpers): string => {\n // If value is already a string in ISO format, validate and return\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/.test(value)) {\n const testDate = new Date(value);\n if (!isNaN(testDate.getTime())) {\n return value;\n }\n }\n\n // If value is a Date object, convert to ISO string\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n // If value is not a string, try to convert it\n if (typeof value !== \"string\") {\n value = String(value);\n }\n\n // Handle special keyword \"now\"\n if (value.toLowerCase() === \"now\") {\n return new Date().toISOString();\n }\n\n // Check for cross-parameter reference with relative time: @paramName+2h, @paramName-30m\n const referenceRegex = /^@(\\w+)([+-]\\d+[smhdwy])$/i;\n const referenceMatch = value.match(referenceRegex);\n \n if (referenceMatch) {\n const [, paramName, relativeExpr] = referenceMatch;\n \n // Get the referenced parameter from context (if available via helpers.state.ancestors)\n // For now, we'll use helpers.prefs.context which Joi provides\n const context = (helpers as any).prefs?.context;\n \n if (!context || !context.params) {\n throw new ParamError(`Cannot resolve cross-parameter reference @${paramName}: context not available. Ensure parameters are processed with proper context.`);\n }\n\n const referencedValue = context.params[paramName];\n \n if (referencedValue === undefined || referencedValue === null) {\n throw new ParamError(`Cannot resolve @${paramName}: parameter \"${paramName}\" is not defined or has no value. Parameters are evaluated left-to-right.`);\n }\n\n // Referenced value should be an ISO string or Date\n let referenceDate: Date;\n if (referencedValue instanceof Date) {\n referenceDate = referencedValue;\n } else if (typeof referencedValue === \"string\") {\n referenceDate = new Date(referencedValue);\n if (isNaN(referenceDate.getTime())) {\n throw new ParamError(`Referenced parameter @${paramName} has invalid date value: ${referencedValue}`);\n }\n } else {\n throw new ParamError(`Referenced parameter @${paramName} is not a valid date type (found: ${typeof referencedValue})`);\n }\n\n // Parse the relative expression and apply to reference date\n const relativeMatch = relativeExpr.match(/^([+-])(\\d+)([smhdwy])$/i);\n if (!relativeMatch) {\n throw new ParamError(`Invalid relative time expression in @${paramName}${relativeExpr}`);\n }\n\n const [, sign, amount, unit] = relativeMatch;\n const offset = calculateTimeOffset(parseInt(amount, 10), unit, sign);\n const resultDate = new Date(referenceDate.getTime() + offset);\n \n return resultDate.toISOString();\n }\n\n // Check for relative time expressions like \"-2h\", \"+1d\", \"-30m\", etc.\n const relativeTimeRegex = /^([+-])(\\d+)([smhdwy])$/i;\n const relativeMatch = value.match(relativeTimeRegex);\n \n if (relativeMatch) {\n const [, sign, amount, unit] = relativeMatch;\n const numAmount = parseInt(amount, 10);\n \n if (isNaN(numAmount)) {\n throw new ParamError(`Invalid relative time amount: ${amount}`);\n }\n\n const offset = calculateTimeOffset(numAmount, unit, sign);\n const resultDate = new Date(Date.now() + offset);\n \n return resultDate.toISOString();\n }\n\n // Try to parse as a regular date string\n const parsedDate = new Date(value);\n \n // Check if the parsed date is valid\n if (isNaN(parsedDate.getTime())) {\n throw new ParamError(`Invalid date format: ${value}. Expected a valid date string, \"now\", relative time expression (e.g., \"-2h\", \"+1d\"), or cross-parameter reference (e.g., \"@startTime+2h\")`);\n }\n\n return parsedDate.toISOString();\n};\n\n/**\n * Calculate time offset in milliseconds\n */\nfunction calculateTimeOffset(amount: number, unit: string, sign: string): number {\n let multiplier = 1;\n \n // Convert to milliseconds based on unit\n switch (unit.toLowerCase()) {\n case \"s\": // seconds\n multiplier = 1000;\n break;\n case \"m\": // minutes\n multiplier = 60 * 1000;\n break;\n case \"h\": // hours\n multiplier = 60 * 60 * 1000;\n break;\n case \"d\": // days\n multiplier = 24 * 60 * 60 * 1000;\n break;\n case \"w\": // weeks\n multiplier = 7 * 24 * 60 * 60 * 1000;\n break;\n case \"y\": // years (approximate)\n multiplier = 365 * 24 * 60 * 60 * 1000;\n break;\n default:\n throw new ParamError(`Invalid time unit: ${unit}. Supported units: s, m, h, d, w, y`);\n }\n\n return sign === \"+\" ? amount * multiplier : -amount * multiplier;\n}\n\n/**\n * Custom Joi type for string array parsing\n * Converts comma-separated strings to typed arrays\n */\nexport const joiStringArrayType = (type: string) => (value: any, helpers: Joi.CustomHelpers): any[] => {\n if (value === undefined || typeof value === \"function\") {\n return [];\n }\n \n const arr = value.split(/,\\s*/).map((el: string) => {\n if (type === \"number\") {\n const v = parseInt(el, 10);\n if (isNaN(v)) {\n throw new ParamError(`array element \"${el}\" should be numeric`);\n }\n return v;\n } else if (type === \"boolean\") {\n const v = el.match(/true|t|yes|1/i) ? true :\n el.match(/false|f|no|0/i) ? false : null;\n if (v === null) {\n throw new ParamError(`array element \"${el}\" should be boolean`);\n }\n return v;\n } else if (type === \"string\") {\n return el;\n } else {\n throw new ParamError(`unknown type \"${type}\" for array elements`);\n }\n });\n \n return arr;\n};\n\n"],"mappings":"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","names":["relativeMatch","Joi"]}
1
+ {"version":3,"sources":["../src/params.ts","../src/params/index.ts","../src/errors.ts","../src/params/custom-types.ts"],"sourcesContent":["// Re-export everything from the params module directory\nexport * from \"./params/index.js\";\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors\";\nimport { joiEdateType, joiStringArrayType } from \"./custom-types\";\n\n/**\n * Parameter definition types\n */\nexport type ParamDefinition = \n | string \n | Joi.Schema \n | { \n type?: string | Joi.Schema; \n values?: any[]; \n [key: string]: any; \n };\n\nexport type ParamGetter = (key: string, definition?: any) => any;\nexport type ParamSetter = (key: string, value: any) => boolean;\n\n/**\n * Args instance interface\n */\nexport interface ArgsInstance {\n get(key: string): any;\n}\n\n/**\n * Params constructor options\n */\nexport interface ParamsOptions {\n [key: string]: any;\n}\n\n/** Origin of a parameter value: CLI args, env var, config file, options/overrides, or definition default */\nexport type ParamSource = \"cli\" | \"env\" | \"config\" | \"options\" | \"default\";\n\n/**\n * Tracked parameter information for --stopAfter=init and --showUsedParams\n */\ninterface TrackedParam {\n key: string;\n definition: ParamDefinition;\n value: any;\n source: ParamSource;\n module: string;\n}\n\n/**\n * Params class for parameter validation and type checking\n * Built on top of Args library with Joi validation\n */\nexport class Params {\n private context: any; // Partial context during initialization\n private params: Record<string, any> = {};\n private paramSources: Record<string, ParamSource> = {};\n private definitions: Record<string, any> = {};\n private args: ArgsInstance;\n private paramSetters: ParamSetter[] = [];\n private paramGetters: ParamGetter[] = [];\n private trackedParams: TrackedParam[] = [];\n private _currentModule: string = \"script\";\n /** Resolved early in constructor so cleanup does not read params lazily */\n private _showUsedParams: boolean = false;\n\n constructor(context: any, options: ParamsOptions = {}) {\n // Context might be partial during initialization\n this.context = context;\n this.args = context.args;\n\n // Apply initial configuration\n if (Object.keys(options).length > 0) {\n this.configure(options);\n }\n\n // Resolve showUsedParams early (fail fast, consistent with \"params figured in init\")\n this._showUsedParams = this.get(\"showUsedParams\", \"boolean default false\");\n\n if (context && typeof context.registerCleanup === \"function\") {\n context.registerCleanup((ctx: any) => {\n if (!ctx.params.getShowUsedParams()) return;\n const byModule = ctx.params.getFiguredByModule();\n const modules = Object.keys(byModule).sort();\n if (modules.length === 0) return;\n const logger = ctx.logger;\n logger.debug(\"[Params]: list of used params:\");\n type Entry = { value: any; source: ParamSource };\n if (typeof logger.highlight !== \"function\") {\n for (const mod of modules) {\n logger.debug(` [${mod}]`);\n for (const [key, entry] of Object.entries(byModule[mod]) as [string, Entry][]) {\n logger.debug(` ${key}: ${JSON.stringify(entry.value)} (${entry.source})`);\n }\n }\n return;\n }\n for (const mod of modules) {\n logger.debug(` [${mod}]`);\n for (const [key, entry] of Object.entries(byModule[mod]) as [string, Entry][]) {\n const valueStr = JSON.stringify(entry.value);\n const display = entry.source === \"default\" ? valueStr : logger.highlight(valueStr);\n logger.debug(` ${key}: ${display} (${entry.source})`);\n }\n }\n });\n }\n }\n\n /** Whether --showUsedParams was requested (resolved in constructor). */\n getShowUsedParams(): boolean {\n return this._showUsedParams;\n }\n\n /**\n * Configure parameters\n * Only parameters present in options are updated\n */\n configure(options: ParamsOptions): void {\n for (const [k, v] of Object.entries(options)) {\n // TODO: opt values might be an object with definitions in it, so perhaps `this.set` should be used\n this.params[k] = v;\n }\n }\n\n /**\n * Initialize Params from context and CLI parameters\n * Note: Params is special - it's initialized early with partial context\n */\n static init(context: any, options?: ParamsOptions): Params {\n return new Params(context, options || {});\n }\n\n /**\n * Track a parameter request for --stopAfter=init and --showUsedParams\n */\n private trackParam(key: string, definition: ParamDefinition, value: any, source: ParamSource, moduleName?: string): void {\n this.trackedParams.push({\n key,\n definition,\n value,\n source,\n module: moduleName ?? this._currentModule,\n });\n }\n\n /**\n * Get all tracked parameters (for --stopAfter=init)\n */\n getTrackedParams(): TrackedParam[] {\n return [...this.trackedParams];\n }\n\n /**\n * Get all figured parameters as a record (flat, last occurrence per key)\n * Returns all parameters that were collected during initialization,\n * whether from CLI args, options, or defaults\n */\n getAllFigured(): Record<string, { value: any; source: ParamSource }> {\n const result: Record<string, { value: any; source: ParamSource }> = {};\n for (const param of this.trackedParams) {\n result[param.key] = {\n value: param.value,\n source: param.source,\n };\n }\n return result;\n }\n\n /**\n * Get figured parameters grouped by module name.\n * Same param can appear in multiple modules (e.g. source, resource).\n */\n getFiguredByModule(): Record<string, Record<string, { value: any; source: ParamSource }>> {\n const byModule: Record<string, Record<string, { value: any; source: ParamSource }>> = {};\n for (const param of this.trackedParams) {\n const mod = param.module;\n if (!byModule[mod]) byModule[mod] = {};\n byModule[mod][param.key] = { value: param.value, source: param.source };\n }\n return byModule;\n }\n\n /**\n * Clear tracked parameters\n */\n clearTrackedParams(): void {\n this.trackedParams = [];\n }\n\n /**\n * Assign a parameter definition\n */\n assignDefinition(key: string, definition?: ParamDefinition): any {\n if (this.definitions[key] && !definition) {\n return this.definitions[key];\n }\n\n let type: Joi.Schema;\n if (!definition) {\n type = Joi.string();\n } else if (Joi.isSchema(definition)) {\n type = definition;\n } else if (Joi.isSchema(definition.type)) {\n type = definition.type;\n } else if (typeof definition === \"string\") {\n type = this.toJoi(definition);\n } else if (typeof definition.type === \"string\") {\n type = this.toJoi(definition.type);\n } else if (!definition.type) {\n type = Joi.string();\n } else {\n type = Joi.string();\n }\n\n if (!this.definitions[key]) {\n this.definitions[key] = {};\n }\n this.definitions[key].type = type;\n\n if (definition && definition.values) {\n if (Array.isArray(definition.values)) {\n this.definitions[key].values = definition.values;\n }\n }\n return this.definitions[key];\n }\n\n /**\n * Convert string definition to Joi schema\n */\n toJoi(str: string): Joi.Schema {\n let type: Joi.Schema;\n \n if (str.match(/^string|^text/i)) {\n type = Joi.string();\n } else if (str.match(/^number|^integer|^int/i)) {\n type = Joi.number();\n } else if (str.match(/^boolean|^bool/i)) {\n type = Joi.boolean();\n } else if (str.match(/^date/i)) {\n type = Joi.custom(joiEdateType);\n } else if (str.match(/^duration/i)) {\n type = Joi.string().isoDuration();\n } else if (str.match(/^array/i)) {\n let elementTypes = \"string\";\n const tmp = str.match(/\\((.*)\\)/);\n if (tmp && tmp[1].match(/string/i)) {\n elementTypes = \"string\";\n } else if (tmp && tmp[1].match(/number|integer|int/i)) {\n elementTypes = \"number\";\n } else if (tmp && tmp[1].match(/boolean|bool/i)) {\n elementTypes = \"boolean\";\n }\n type = Joi.custom(joiStringArrayType(elementTypes));\n } else {\n type = Joi.string();\n }\n\n // Handle default values\n const regexForDefault = /\\bdefault\\s+([^\\s]+)/;\n const matchForDefault = str.match(regexForDefault);\n if (matchForDefault) {\n const defValObj = type.validate(matchForDefault[1]);\n if (defValObj.error) {\n throw new ParamError(`default value \"${defValObj.value}\" type mismatch`);\n }\n // Joi's default() automatically allows undefined and applies the default\n type = type.default(defValObj.value);\n } else if (str.match(/required/)) {\n type = type.required();\n } else {\n // If not required and no default, make it optional\n type = type.optional();\n }\n\n return type;\n }\n\n /**\n * Validate a value against a definition\n */\n validate(key: string, val: any, def: any): any {\n // Convert null to undefined so Joi defaults can be applied\n // Joi's .default() only works with undefined, not null\n const normalizedVal = val === null ? undefined : val;\n \n // Pass current params as context to support cross-parameter references (e.g., @startTime+2h)\n // Use abortEarly: false to get all errors, and allowUnknown: false for strict validation\n const { value, error } = def.type.validate(normalizedVal, { \n context: { params: this.params },\n abortEarly: false,\n allowUnknown: false,\n });\n if (error) {\n const errs = error.details.map((el: any) => el.message).join(\", \");\n throw new ParamError(`\"${key}\" validation error: ${errs}`);\n }\n return value;\n }\n\n /**\n * Get a parameter value with validation\n */\n get(key: string, definition?: ParamDefinition): any {\n const def = this.assignDefinition(key, definition);\n let valFromGetters: any = undefined;\n \n if (def.volatile || true) {\n valFromGetters = this.runAllRegisteredGetters(key);\n }\n \n // Always call args.get() to mark the key as used, even if it doesn't exist\n const valFromArgs = this.args.get(key);\n const valFromParams = this.params[key];\n\n let source: ParamSource = \"default\";\n let value: any;\n\n if (valFromGetters !== undefined && valFromGetters !== null) {\n value = this.validate(key, valFromGetters, def);\n source = \"options\";\n } else if (valFromArgs !== undefined && valFromArgs !== null) {\n value = this.validate(key, valFromArgs, def);\n const argsSource = (this.args as { getSource?(k: string): string }).getSource?.(key);\n if (argsSource === \"overrides\") source = \"options\";\n else if (argsSource === \"cli\" || argsSource === \"env\" || argsSource === \"config\") source = argsSource;\n else if (argsSource === \"default\") source = \"default\";\n else source = \"cli\";\n } else if (valFromParams !== undefined && valFromParams !== null) {\n value = this.validate(key, valFromParams, def);\n source = this.paramSources[key] ?? \"options\";\n } else {\n value = this.validate(key, undefined, def);\n source = \"default\";\n }\n\n this.paramSources[key] = source;\n // Track parameter for --stopAfter=init and --showUsedParams\n this.trackParam(key, definition || \"string\", value, source);\n\n if (value !== undefined && def.values && !def.values.includes(value)) {\n throw new ParamError(`key ${key} should be one of ${def.values}`);\n }\n return value;\n }\n\n /**\n * Set a parameter value with validation\n */\n set(key: string, val: any, definition?: ParamDefinition): void {\n // TODO: check if there's a test for this:\n if (val && val.type && val.value) {\n definition = val;\n val = val.value;\n }\n const def = this.assignDefinition(key, definition);\n\n if (!this.runAllRegisteredSetters(key, val)) {\n this.params[key] = val;\n }\n }\n\n /**\n * Get all parameters from definitions (main script).\n * Same as getAllForModule(\"script\", defs). Processes left-to-right for cross-parameter references.\n */\n getAll(defs: Record<string, ParamDefinition>): Record<string, any> {\n return this.getAllForModule(\"script\", defs);\n }\n\n /**\n * Get all parameters from definitions for a given module name.\n * Figured params are grouped by module when using --showUsedParams.\n * Processes parameters left-to-right to support cross-parameter references.\n * If moduleName is omitted, it is inferred from the caller's file path (directory name under src/).\n */\n getAllForModule(moduleNameOrDefs: string | Record<string, ParamDefinition>, defs?: Record<string, ParamDefinition>): Record<string, any> {\n let moduleName: string;\n let definitions: Record<string, ParamDefinition>;\n if (defs !== undefined) {\n moduleName = moduleNameOrDefs as string;\n definitions = defs;\n } else {\n definitions = moduleNameOrDefs as Record<string, ParamDefinition>;\n moduleName = this._inferModuleNameFromStack();\n }\n const prev = this._currentModule;\n this._currentModule = moduleName;\n try {\n const res: Record<string, any> = {};\n for (const [k, def] of Object.entries(definitions)) {\n const value = this.get(k, def);\n res[k] = value;\n if (value !== undefined) {\n this.params[k] = value;\n }\n }\n return res;\n } finally {\n this._currentModule = prev;\n }\n }\n\n /**\n * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...\n */\n private _inferModuleNameFromStack(): string {\n const stack = new Error().stack;\n if (!stack) return \"script\";\n const lines = stack.split(\"\\n\");\n const paramsIndexPath = \"params\" + (typeof process !== \"undefined\" && process.platform === \"win32\" ? \"\\\\\" : \"/\") + \"index.\";\n for (const line of lines) {\n const parenMatch = line.match(/\\(([^)]+)\\)/);\n if (!parenMatch) continue;\n const parts = parenMatch[1].split(\":\");\n if (parts.length < 3) continue;\n const path = parts.slice(0, -2).join(\":\").replace(/^file:\\/\\//, \"\");\n if (!path || path.includes(paramsIndexPath)) continue;\n const srcMatch = path.match(/[/\\\\]src[/\\\\]([^/\\\\]+)(?:[/\\\\]|$)/);\n if (srcMatch) return srcMatch[1];\n }\n return \"script\";\n }\n\n /**\n * Run all registered getters for a key\n */\n runAllRegisteredGetters(key: string): any {\n let val: any = undefined;\n for (const getter of this.paramGetters) {\n val = getter(key, this.definitions[key]);\n if (val !== undefined && val !== null) {\n break;\n }\n }\n return val;\n }\n\n /**\n * Run all registered setters for a key\n */\n runAllRegisteredSetters(key: string, value: any): boolean {\n let setterUsed: boolean = false;\n for (const setter of this.paramSetters) {\n setterUsed = setter(key, value);\n if (setterUsed) {\n break;\n }\n }\n return setterUsed;\n }\n\n /**\n * Register a parameter getter\n */\n registerParamGetter(fn: ParamGetter): void {\n this.paramGetters.push(fn);\n }\n\n /**\n * Register a parameter setter\n */\n registerParamSetter(fn: ParamSetter): void {\n this.paramSetters.push(fn);\n }\n}\n\n// Export custom types for external use\nexport { joiEdateType, joiStringArrayType };\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","import Joi from \"joi\";\nimport { ParamError } from \"../errors.js\";\n\n/**\n * Custom Joi type for enhanced date parsing with relative time support\n * Supports:\n * - ISO8601 strings: \"2025-01-01T01:01:01Z\"\n * - Relative time: \"-2h\", \"+1d\", \"now\"\n * - Cross-parameter references: \"@startTime+2h\", \"@endDate-30m\"\n * \n * Internal representation: UTC ISO8601 string (YYYY-MM-DDTHH:mm:ssZ)\n * \n * @param value - Date value to parse\n * @param helpers - Joi helpers (includes context with other params)\n * @returns ISO8601 string in UTC timezone\n */\nexport const joiEdateType = (value: any, helpers: Joi.CustomHelpers): string => {\n // If value is already a string in ISO format, validate and return\n if (typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z$/.test(value)) {\n const testDate = new Date(value);\n if (!isNaN(testDate.getTime())) {\n return value;\n }\n }\n\n // If value is a Date object, convert to ISO string\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n // If value is not a string, try to convert it\n if (typeof value !== \"string\") {\n value = String(value);\n }\n\n // Handle special keyword \"now\"\n if (value.toLowerCase() === \"now\") {\n return new Date().toISOString();\n }\n\n // Check for cross-parameter reference with relative time: @paramName+2h, @paramName-30m\n const referenceRegex = /^@(\\w+)([+-]\\d+[smhdwy])$/i;\n const referenceMatch = value.match(referenceRegex);\n \n if (referenceMatch) {\n const [, paramName, relativeExpr] = referenceMatch;\n \n // Get the referenced parameter from context (if available via helpers.state.ancestors)\n // For now, we'll use helpers.prefs.context which Joi provides\n const context = (helpers as any).prefs?.context;\n \n if (!context || !context.params) {\n throw new ParamError(`Cannot resolve cross-parameter reference @${paramName}: context not available. Ensure parameters are processed with proper context.`);\n }\n\n const referencedValue = context.params[paramName];\n \n if (referencedValue === undefined || referencedValue === null) {\n throw new ParamError(`Cannot resolve @${paramName}: parameter \"${paramName}\" is not defined or has no value. Parameters are evaluated left-to-right.`);\n }\n\n // Referenced value should be an ISO string or Date\n let referenceDate: Date;\n if (referencedValue instanceof Date) {\n referenceDate = referencedValue;\n } else if (typeof referencedValue === \"string\") {\n referenceDate = new Date(referencedValue);\n if (isNaN(referenceDate.getTime())) {\n throw new ParamError(`Referenced parameter @${paramName} has invalid date value: ${referencedValue}`);\n }\n } else {\n throw new ParamError(`Referenced parameter @${paramName} is not a valid date type (found: ${typeof referencedValue})`);\n }\n\n // Parse the relative expression and apply to reference date\n const relativeMatch = relativeExpr.match(/^([+-])(\\d+)([smhdwy])$/i);\n if (!relativeMatch) {\n throw new ParamError(`Invalid relative time expression in @${paramName}${relativeExpr}`);\n }\n\n const [, sign, amount, unit] = relativeMatch;\n const offset = calculateTimeOffset(parseInt(amount, 10), unit, sign);\n const resultDate = new Date(referenceDate.getTime() + offset);\n \n return resultDate.toISOString();\n }\n\n // Check for relative time expressions like \"-2h\", \"+1d\", \"-30m\", etc.\n const relativeTimeRegex = /^([+-])(\\d+)([smhdwy])$/i;\n const relativeMatch = value.match(relativeTimeRegex);\n \n if (relativeMatch) {\n const [, sign, amount, unit] = relativeMatch;\n const numAmount = parseInt(amount, 10);\n \n if (isNaN(numAmount)) {\n throw new ParamError(`Invalid relative time amount: ${amount}`);\n }\n\n const offset = calculateTimeOffset(numAmount, unit, sign);\n const resultDate = new Date(Date.now() + offset);\n \n return resultDate.toISOString();\n }\n\n // Try to parse as a regular date string\n const parsedDate = new Date(value);\n \n // Check if the parsed date is valid\n if (isNaN(parsedDate.getTime())) {\n throw new ParamError(`Invalid date format: ${value}. Expected a valid date string, \"now\", relative time expression (e.g., \"-2h\", \"+1d\"), or cross-parameter reference (e.g., \"@startTime+2h\")`);\n }\n\n return parsedDate.toISOString();\n};\n\n/**\n * Calculate time offset in milliseconds\n */\nfunction calculateTimeOffset(amount: number, unit: string, sign: string): number {\n let multiplier = 1;\n \n // Convert to milliseconds based on unit\n switch (unit.toLowerCase()) {\n case \"s\": // seconds\n multiplier = 1000;\n break;\n case \"m\": // minutes\n multiplier = 60 * 1000;\n break;\n case \"h\": // hours\n multiplier = 60 * 60 * 1000;\n break;\n case \"d\": // days\n multiplier = 24 * 60 * 60 * 1000;\n break;\n case \"w\": // weeks\n multiplier = 7 * 24 * 60 * 60 * 1000;\n break;\n case \"y\": // years (approximate)\n multiplier = 365 * 24 * 60 * 60 * 1000;\n break;\n default:\n throw new ParamError(`Invalid time unit: ${unit}. Supported units: s, m, h, d, w, y`);\n }\n\n return sign === \"+\" ? amount * multiplier : -amount * multiplier;\n}\n\n/**\n * Custom Joi type for string array parsing\n * Converts comma-separated strings to typed arrays\n */\nexport const joiStringArrayType = (type: string) => (value: any, helpers: Joi.CustomHelpers): any[] => {\n if (value === undefined || typeof value === \"function\") {\n return [];\n }\n \n const arr = value.split(/,\\s*/).map((el: string) => {\n if (type === \"number\") {\n const v = parseInt(el, 10);\n if (isNaN(v)) {\n throw new ParamError(`array element \"${el}\" should be numeric`);\n }\n return v;\n } else if (type === \"boolean\") {\n const v = el.match(/true|t|yes|1/i) ? true :\n el.match(/false|f|no|0/i) ? false : null;\n if (v === null) {\n throw new ParamError(`array element \"${el}\" should be boolean`);\n }\n return v;\n } else if (type === \"string\") {\n return el;\n } else {\n throw new ParamError(`unknown type \"${type}\" for array elements`);\n }\n });\n \n return arr;\n};\n\n"],"mappings":"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","names":["relativeMatch","Joi"]}
package/dist/params.js CHANGED
@@ -139,17 +139,53 @@ var Params = class _Params {
139
139
  context;
140
140
  // Partial context during initialization
141
141
  params = {};
142
+ paramSources = {};
142
143
  definitions = {};
143
144
  args;
144
145
  paramSetters = [];
145
146
  paramGetters = [];
146
147
  trackedParams = [];
148
+ _currentModule = "script";
149
+ /** Resolved early in constructor so cleanup does not read params lazily */
150
+ _showUsedParams = false;
147
151
  constructor(context, options = {}) {
148
152
  this.context = context;
149
153
  this.args = context.args;
150
154
  if (Object.keys(options).length > 0) {
151
155
  this.configure(options);
152
156
  }
157
+ this._showUsedParams = this.get("showUsedParams", "boolean default false");
158
+ if (context && typeof context.registerCleanup === "function") {
159
+ context.registerCleanup((ctx) => {
160
+ if (!ctx.params.getShowUsedParams()) return;
161
+ const byModule = ctx.params.getFiguredByModule();
162
+ const modules = Object.keys(byModule).sort();
163
+ if (modules.length === 0) return;
164
+ const logger = ctx.logger;
165
+ logger.debug("[Params]: list of used params:");
166
+ if (typeof logger.highlight !== "function") {
167
+ for (const mod of modules) {
168
+ logger.debug(` [${mod}]`);
169
+ for (const [key, entry] of Object.entries(byModule[mod])) {
170
+ logger.debug(` ${key}: ${JSON.stringify(entry.value)} (${entry.source})`);
171
+ }
172
+ }
173
+ return;
174
+ }
175
+ for (const mod of modules) {
176
+ logger.debug(` [${mod}]`);
177
+ for (const [key, entry] of Object.entries(byModule[mod])) {
178
+ const valueStr = JSON.stringify(entry.value);
179
+ const display = entry.source === "default" ? valueStr : logger.highlight(valueStr);
180
+ logger.debug(` ${key}: ${display} (${entry.source})`);
181
+ }
182
+ }
183
+ });
184
+ }
185
+ }
186
+ /** Whether --showUsedParams was requested (resolved in constructor). */
187
+ getShowUsedParams() {
188
+ return this._showUsedParams;
153
189
  }
154
190
  /**
155
191
  * Configure parameters
@@ -168,14 +204,15 @@ var Params = class _Params {
168
204
  return new _Params(context, options || {});
169
205
  }
170
206
  /**
171
- * Track a parameter request for --stopAfter=init feature
207
+ * Track a parameter request for --stopAfter=init and --showUsedParams
172
208
  */
173
- trackParam(key, definition, value, source) {
209
+ trackParam(key, definition, value, source, moduleName) {
174
210
  this.trackedParams.push({
175
211
  key,
176
212
  definition,
177
213
  value,
178
- source
214
+ source,
215
+ module: moduleName ?? this._currentModule
179
216
  });
180
217
  }
181
218
  /**
@@ -185,7 +222,7 @@ var Params = class _Params {
185
222
  return [...this.trackedParams];
186
223
  }
187
224
  /**
188
- * Get all figured parameters as a record
225
+ * Get all figured parameters as a record (flat, last occurrence per key)
189
226
  * Returns all parameters that were collected during initialization,
190
227
  * whether from CLI args, options, or defaults
191
228
  */
@@ -199,6 +236,19 @@ var Params = class _Params {
199
236
  }
200
237
  return result;
201
238
  }
239
+ /**
240
+ * Get figured parameters grouped by module name.
241
+ * Same param can appear in multiple modules (e.g. source, resource).
242
+ */
243
+ getFiguredByModule() {
244
+ const byModule = {};
245
+ for (const param of this.trackedParams) {
246
+ const mod = param.module;
247
+ if (!byModule[mod]) byModule[mod] = {};
248
+ byModule[mod][param.key] = { value: param.value, source: param.source };
249
+ }
250
+ return byModule;
251
+ }
202
252
  /**
203
253
  * Clear tracked parameters
204
254
  */
@@ -317,14 +367,19 @@ var Params = class _Params {
317
367
  source = "options";
318
368
  } else if (valFromArgs !== void 0 && valFromArgs !== null) {
319
369
  value = this.validate(key, valFromArgs, def);
320
- source = "cli";
370
+ const argsSource = this.args.getSource?.(key);
371
+ if (argsSource === "overrides") source = "options";
372
+ else if (argsSource === "cli" || argsSource === "env" || argsSource === "config") source = argsSource;
373
+ else if (argsSource === "default") source = "default";
374
+ else source = "cli";
321
375
  } else if (valFromParams !== void 0 && valFromParams !== null) {
322
376
  value = this.validate(key, valFromParams, def);
323
- source = "options";
377
+ source = this.paramSources[key] ?? "options";
324
378
  } else {
325
379
  value = this.validate(key, void 0, def);
326
380
  source = "default";
327
381
  }
382
+ this.paramSources[key] = source;
328
383
  this.trackParam(key, definition || "string", value, source);
329
384
  if (value !== void 0 && def.values && !def.values.includes(value)) {
330
385
  throw new ParamError(`key ${key} should be one of ${def.values}`);
@@ -345,19 +400,63 @@ var Params = class _Params {
345
400
  }
346
401
  }
347
402
  /**
348
- * Get all parameters from definitions
349
- * Processes parameters left-to-right to support cross-parameter references
403
+ * Get all parameters from definitions (main script).
404
+ * Same as getAllForModule("script", defs). Processes left-to-right for cross-parameter references.
350
405
  */
351
406
  getAll(defs) {
352
- const res = {};
353
- for (const [k, def] of Object.entries(defs)) {
354
- const value = this.get(k, def);
355
- res[k] = value;
356
- if (value !== void 0) {
357
- this.params[k] = value;
407
+ return this.getAllForModule("script", defs);
408
+ }
409
+ /**
410
+ * Get all parameters from definitions for a given module name.
411
+ * Figured params are grouped by module when using --showUsedParams.
412
+ * Processes parameters left-to-right to support cross-parameter references.
413
+ * If moduleName is omitted, it is inferred from the caller's file path (directory name under src/).
414
+ */
415
+ getAllForModule(moduleNameOrDefs, defs) {
416
+ let moduleName;
417
+ let definitions;
418
+ if (defs !== void 0) {
419
+ moduleName = moduleNameOrDefs;
420
+ definitions = defs;
421
+ } else {
422
+ definitions = moduleNameOrDefs;
423
+ moduleName = this._inferModuleNameFromStack();
424
+ }
425
+ const prev = this._currentModule;
426
+ this._currentModule = moduleName;
427
+ try {
428
+ const res = {};
429
+ for (const [k, def] of Object.entries(definitions)) {
430
+ const value = this.get(k, def);
431
+ res[k] = value;
432
+ if (value !== void 0) {
433
+ this.params[k] = value;
434
+ }
358
435
  }
436
+ return res;
437
+ } finally {
438
+ this._currentModule = prev;
439
+ }
440
+ }
441
+ /**
442
+ * Infer module name from call stack: first caller outside params/index gives path like .../src/<moduleName>/...
443
+ */
444
+ _inferModuleNameFromStack() {
445
+ const stack = new Error().stack;
446
+ if (!stack) return "script";
447
+ const lines = stack.split("\n");
448
+ const paramsIndexPath = "params" + (typeof process !== "undefined" && process.platform === "win32" ? "\\" : "/") + "index.";
449
+ for (const line of lines) {
450
+ const parenMatch = line.match(/\(([^)]+)\)/);
451
+ if (!parenMatch) continue;
452
+ const parts = parenMatch[1].split(":");
453
+ if (parts.length < 3) continue;
454
+ const path = parts.slice(0, -2).join(":").replace(/^file:\/\//, "");
455
+ if (!path || path.includes(paramsIndexPath)) continue;
456
+ const srcMatch = path.match(/[/\\]src[/\\]([^/\\]+)(?:[/\\]|$)/);
457
+ if (srcMatch) return srcMatch[1];
359
458
  }
360
- return res;
459
+ return "script";
361
460
  }
362
461
  /**
363
462
  * Run all registered getters for a key