politty 0.4.8 → 0.4.10

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.
@@ -5,6 +5,42 @@ let node_util = require("node:util");
5
5
  let string_width = require("string-width");
6
6
  string_width = require_subcommand_router.__toESM(string_width);
7
7
 
8
+ //#region src/core/case-proxy.ts
9
+ /**
10
+ * Wrap an args object with a Proxy that allows dual-case access.
11
+ *
12
+ * Given `{ "my-option": "value" }`, both `obj["my-option"]` and `obj.myOption`
13
+ * will return `"value"`.
14
+ *
15
+ * - `Object.keys()`, `JSON.stringify()`, and spread return only the original keys.
16
+ * - The `in` operator detects both case variants.
17
+ */
18
+ function createDualCaseProxy(obj) {
19
+ return new Proxy(obj, {
20
+ get(target, prop, receiver) {
21
+ if (typeof prop === "string") {
22
+ if (prop in target) return Reflect.get(target, prop, receiver);
23
+ const camel = require_lazy.toCamelCase(prop);
24
+ if (camel !== prop && camel in target) return Reflect.get(target, camel, receiver);
25
+ const kebab = require_lazy.toKebabCase(prop);
26
+ if (kebab !== prop && kebab in target) return Reflect.get(target, kebab, receiver);
27
+ }
28
+ return Reflect.get(target, prop, receiver);
29
+ },
30
+ has(target, prop) {
31
+ if (typeof prop === "string") {
32
+ if (prop in target) return true;
33
+ const camel = require_lazy.toCamelCase(prop);
34
+ if (camel !== prop && camel in target) return true;
35
+ const kebab = require_lazy.toKebabCase(prop);
36
+ if (kebab !== prop && kebab in target) return true;
37
+ }
38
+ return Reflect.has(target, prop);
39
+ }
40
+ });
41
+ }
42
+
43
+ //#endregion
8
44
  //#region src/executor/command-runner.ts
9
45
  /**
10
46
  * Execute a command lifecycle: setup → run → cleanup
@@ -906,6 +942,15 @@ var DuplicateAliasError = class extends Error {
906
942
  this.name = "DuplicateAliasError";
907
943
  }
908
944
  };
945
+ /**
946
+ * Error thrown when fields are case variants of each other (e.g. "my-option" and "myOption")
947
+ */
948
+ var CaseVariantCollisionError = class extends Error {
949
+ constructor(message) {
950
+ super(message);
951
+ this.name = "CaseVariantCollisionError";
952
+ }
953
+ };
909
954
 
910
955
  //#endregion
911
956
  //#region src/validator/command-validator.ts
@@ -927,6 +972,25 @@ function checkDuplicateFields(extracted, commandPath) {
927
972
  return errors;
928
973
  }
929
974
  /**
975
+ * Check for case-variant collisions (e.g. "my-option" and "myOption" defined simultaneously)
976
+ */
977
+ function checkCaseVariantCollisions(extracted, commandPath) {
978
+ const errors = [];
979
+ const canonicalMap = /* @__PURE__ */ new Map();
980
+ for (const field of extracted.fields) {
981
+ const camel = require_lazy.toCamelCase(field.name);
982
+ const existing = canonicalMap.get(camel);
983
+ if (existing && existing !== field.name) errors.push({
984
+ commandPath,
985
+ type: "case_variant_collision",
986
+ message: `Fields "${existing}" and "${field.name}" are case variants of each other and would collide.`,
987
+ field: field.name
988
+ });
989
+ canonicalMap.set(camel, field.name);
990
+ }
991
+ return errors;
992
+ }
993
+ /**
930
994
  * Check for duplicate aliases and alias-field name conflicts
931
995
  */
932
996
  function checkDuplicateAliases(extracted, commandPath) {
@@ -1063,11 +1127,42 @@ function validateReservedAliases(extracted, _hasSubCommands) {
1063
1127
  }
1064
1128
  }
1065
1129
  /**
1130
+ * Validate that no case-variant collisions exist
1131
+ *
1132
+ * @param extracted - Extracted fields from schema
1133
+ * @throws {CaseVariantCollisionError} If case-variant collisions are found
1134
+ */
1135
+ function validateCaseVariantCollisions(extracted) {
1136
+ const errors = checkCaseVariantCollisions(extracted, []);
1137
+ if (errors.length > 0) {
1138
+ const err = errors[0];
1139
+ throw new CaseVariantCollisionError(err.message);
1140
+ }
1141
+ }
1142
+ /**
1143
+ * Validate that no case-variant collisions exist between two schemas
1144
+ * (e.g., global args and command args).
1145
+ *
1146
+ * @param extractedA - Extracted fields from first schema (e.g., global args)
1147
+ * @param extractedB - Extracted fields from second schema (e.g., command args)
1148
+ * @throws {CaseVariantCollisionError} If cross-schema case-variant collisions are found
1149
+ */
1150
+ function validateCrossSchemaCollisions(extractedA, extractedB) {
1151
+ const canonicalMap = /* @__PURE__ */ new Map();
1152
+ for (const field of extractedA.fields) canonicalMap.set(require_lazy.toCamelCase(field.name), field.name);
1153
+ for (const field of extractedB.fields) {
1154
+ const camel = require_lazy.toCamelCase(field.name);
1155
+ const existing = canonicalMap.get(camel);
1156
+ if (existing && existing !== field.name) throw new CaseVariantCollisionError(`Global field "${existing}" and command field "${field.name}" are case variants of each other and would collide.`);
1157
+ }
1158
+ }
1159
+ /**
1066
1160
  * Collect validation errors for a single command's schema (non-throwing)
1067
1161
  */
1068
1162
  function collectSchemaErrors(extracted, _hasSubCommands, commandPath) {
1069
1163
  return [
1070
1164
  ...checkDuplicateFields(extracted, commandPath),
1165
+ ...checkCaseVariantCollisions(extracted, commandPath),
1071
1166
  ...checkDuplicateAliases(extracted, commandPath),
1072
1167
  ...checkPositionalConfig(extracted, commandPath),
1073
1168
  ...checkReservedAliases(extracted, commandPath)
@@ -1499,9 +1594,11 @@ function parseArgs(argv, command, options = {}) {
1499
1594
  extracted = require_lazy.extractFields(command.args);
1500
1595
  if (!options.skipValidation) {
1501
1596
  validateDuplicateFields(extracted);
1597
+ validateCaseVariantCollisions(extracted);
1502
1598
  validateDuplicateAliases(extracted);
1503
1599
  validatePositionalConfig(extracted);
1504
1600
  validateReservedAliases(extracted, hasSubCommands);
1601
+ if (options.globalExtracted) validateCrossSchemaCollisions(options.globalExtracted, extracted);
1505
1602
  }
1506
1603
  }
1507
1604
  const hasUserDefinedH = extracted?.fields.some((f) => f.alias === "H" && f.overrideBuiltinAlias === true) ?? false;
@@ -2086,9 +2183,10 @@ async function runCommandInternal(command, argv, options = {}) {
2086
2183
  validatedGlobalArgs = globalValidation.data;
2087
2184
  }
2088
2185
  if (!command.args) {
2089
- if (options._globalExtracted) await runEffects(validatedGlobalArgs, options._globalExtracted, validatedGlobalArgs);
2186
+ const proxiedGlobalArgs = createDualCaseProxy(validatedGlobalArgs);
2187
+ if (options._globalExtracted) await runEffects(proxiedGlobalArgs, options._globalExtracted, proxiedGlobalArgs);
2090
2188
  collector?.stop();
2091
- return await executeLifecycle(command, validatedGlobalArgs, {
2189
+ return await executeLifecycle(command, proxiedGlobalArgs, {
2092
2190
  handleSignals: options.handleSignals,
2093
2191
  captureLogs: options.captureLogs,
2094
2192
  existingLogs: getCurrentLogs(),
@@ -2106,12 +2204,14 @@ async function runCommandInternal(command, argv, options = {}) {
2106
2204
  logs: getCurrentLogs()
2107
2205
  };
2108
2206
  }
2109
- if (options._globalExtracted) await runEffects(validatedGlobalArgs, options._globalExtracted, validatedGlobalArgs);
2110
- if (parseResult.extractedFields) await runEffects(validationResult.data, parseResult.extractedFields, validatedGlobalArgs);
2111
- const mergedArgs = {
2112
- ...validatedGlobalArgs,
2113
- ...validationResult.data
2114
- };
2207
+ const proxiedCommandArgs = createDualCaseProxy(validationResult.data);
2208
+ const proxiedGlobalArgs = createDualCaseProxy(validatedGlobalArgs);
2209
+ if (options._globalExtracted) await runEffects(proxiedGlobalArgs, options._globalExtracted, proxiedGlobalArgs);
2210
+ if (parseResult.extractedFields) await runEffects(proxiedCommandArgs, parseResult.extractedFields, proxiedGlobalArgs);
2211
+ const mergedArgs = createDualCaseProxy({
2212
+ ...proxiedGlobalArgs,
2213
+ ...proxiedCommandArgs
2214
+ });
2115
2215
  collector?.stop();
2116
2216
  return await executeLifecycle(command, mergedArgs, {
2117
2217
  handleSignals: options.handleSignals,
@@ -2141,6 +2241,7 @@ function extractAndValidateGlobal(options) {
2141
2241
  const extracted = require_lazy.extractFields(options.globalArgs);
2142
2242
  if (!options.skipValidation) {
2143
2243
  validateDuplicateFields(extracted);
2244
+ validateCaseVariantCollisions(extracted);
2144
2245
  validateDuplicateAliases(extracted);
2145
2246
  validateReservedAliases(extracted, true);
2146
2247
  const positionalNames = extracted.fields.filter((f) => f.positional).map((f) => f.name);
@@ -2150,6 +2251,12 @@ function extractAndValidateGlobal(options) {
2150
2251
  }
2151
2252
 
2152
2253
  //#endregion
2254
+ Object.defineProperty(exports, 'CaseVariantCollisionError', {
2255
+ enumerable: true,
2256
+ get: function () {
2257
+ return CaseVariantCollisionError;
2258
+ }
2259
+ });
2153
2260
  Object.defineProperty(exports, 'DuplicateAliasError', {
2154
2261
  enumerable: true,
2155
2262
  get: function () {
@@ -2174,6 +2281,12 @@ Object.defineProperty(exports, 'ReservedAliasError', {
2174
2281
  return ReservedAliasError;
2175
2282
  }
2176
2283
  });
2284
+ Object.defineProperty(exports, 'createDualCaseProxy', {
2285
+ enumerable: true,
2286
+ get: function () {
2287
+ return createDualCaseProxy;
2288
+ }
2289
+ });
2177
2290
  Object.defineProperty(exports, 'formatCommandValidationErrors', {
2178
2291
  enumerable: true,
2179
2292
  get: function () {
@@ -2258,12 +2371,24 @@ Object.defineProperty(exports, 'symbols', {
2258
2371
  return symbols;
2259
2372
  }
2260
2373
  });
2374
+ Object.defineProperty(exports, 'validateCaseVariantCollisions', {
2375
+ enumerable: true,
2376
+ get: function () {
2377
+ return validateCaseVariantCollisions;
2378
+ }
2379
+ });
2261
2380
  Object.defineProperty(exports, 'validateCommand', {
2262
2381
  enumerable: true,
2263
2382
  get: function () {
2264
2383
  return validateCommand;
2265
2384
  }
2266
2385
  });
2386
+ Object.defineProperty(exports, 'validateCrossSchemaCollisions', {
2387
+ enumerable: true,
2388
+ get: function () {
2389
+ return validateCrossSchemaCollisions;
2390
+ }
2391
+ });
2267
2392
  Object.defineProperty(exports, 'validateDuplicateAliases', {
2268
2393
  enumerable: true,
2269
2394
  get: function () {
@@ -2288,4 +2413,4 @@ Object.defineProperty(exports, 'validateReservedAliases', {
2288
2413
  return validateReservedAliases;
2289
2414
  }
2290
2415
  });
2291
- //# sourceMappingURL=runner-nKNXknDl.cjs.map
2416
+ //# sourceMappingURL=runner-DXmgHXNR.cjs.map