@optique/core 1.0.0-dev.1852 → 1.0.0-dev.1856

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.
@@ -81,6 +81,29 @@ function defineProtectedDataProperty(context, target, key, descriptor) {
81
81
  set: () => throwReadonlyAnnotationMutation()
82
82
  });
83
83
  }
84
+ function copyRegExpMetadata(source, target, transformValue) {
85
+ const sourcePrototype = Object.getPrototypeOf(source);
86
+ if (Object.getPrototypeOf(target) !== sourcePrototype) Object.setPrototypeOf(target, sourcePrototype);
87
+ for (const key of Reflect.ownKeys(source)) {
88
+ if (key === "lastIndex") continue;
89
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
90
+ if (descriptor == null) continue;
91
+ if ("value" in descriptor && transformValue != null) {
92
+ Object.defineProperty(target, key, {
93
+ ...descriptor,
94
+ value: transformValue(descriptor.value)
95
+ });
96
+ continue;
97
+ }
98
+ Object.defineProperty(target, key, descriptor);
99
+ }
100
+ target.lastIndex = source.lastIndex;
101
+ }
102
+ function cloneRegExpShape(source) {
103
+ const cloned = new RegExp(source);
104
+ copyRegExpMetadata(source, cloned);
105
+ return cloned;
106
+ }
84
107
  function createProtectedObjectView(target, context) {
85
108
  if (Array.isArray(target)) {
86
109
  const view$1 = new Array(target.length);
@@ -231,12 +254,13 @@ function createProtectedDateView(target, context) {
231
254
  function createProtectedRegExpView(target, context) {
232
255
  const methodCache = /* @__PURE__ */ new Map();
233
256
  const cloned = new RegExp(target);
234
- cloned.lastIndex = target.lastIndex;
235
257
  const view = new Proxy(cloned, {
236
258
  get(clonedTarget, key) {
237
- const value = Reflect.get(clonedTarget, key, clonedTarget);
238
259
  if (key === "compile") return cacheProtectedMethod(methodCache, key, () => (..._args) => throwReadonlyAnnotationMutation());
239
- return typeof value === "function" ? value.bind(clonedTarget) : value;
260
+ const ownDescriptor = Object.getOwnPropertyDescriptor(clonedTarget, key);
261
+ if (ownDescriptor != null && "value" in ownDescriptor) return ownDescriptor.value;
262
+ const value = Reflect.get(clonedTarget, key, clonedTarget);
263
+ return typeof value === "function" ? value.bind(clonedTarget) : protectAnnotationValue(value, context);
240
264
  },
241
265
  set() {
242
266
  throwReadonlyAnnotationMutation();
@@ -254,7 +278,9 @@ function createProtectedRegExpView(target, context) {
254
278
  throwReadonlyAnnotationMutation();
255
279
  }
256
280
  });
257
- return registerProtectedAnnotationView(context, target, view);
281
+ registerProtectedAnnotationView(context, target, view);
282
+ copyRegExpMetadata(target, cloned, (value) => protectAnnotationValue(value, context));
283
+ return view;
258
284
  }
259
285
  function createProtectedURLSearchParamsView(target, context) {
260
286
  const methodCache = /* @__PURE__ */ new Map();
@@ -335,6 +361,20 @@ function protectAnnotationValue(value, context) {
335
361
  return value;
336
362
  }
337
363
  /**
364
+ * Normalizes annotation input for a fresh parse run.
365
+ *
366
+ * When callers feed a protected annotation view returned by `getAnnotations()`
367
+ * back into a new parse entrypoint, Optique unwraps it to the caller-owned
368
+ * record first so the new run gets its own protected views.
369
+ *
370
+ * @param annotations The caller-supplied annotations input.
371
+ * @returns The raw annotation record to inject for the new run.
372
+ * @internal
373
+ */
374
+ function normalizeRunAnnotationInput(annotations) {
375
+ return isProtectedAnnotationView(annotations) ? unwrapProtectedAnnotationTarget(annotations) : annotations;
376
+ }
377
+ /**
338
378
  * Extracts annotations from parser state.
339
379
  *
340
380
  * @param state Parser state that may contain annotations
@@ -423,8 +463,7 @@ function inheritAnnotations(source, target) {
423
463
  return cloned$1;
424
464
  }
425
465
  if (target instanceof RegExp) {
426
- const cloned$1 = new RegExp(target);
427
- cloned$1.lastIndex = target.lastIndex;
466
+ const cloned$1 = cloneRegExpShape(target);
428
467
  cloned$1[annotationKey] = annotations;
429
468
  return cloned$1;
430
469
  }
@@ -517,8 +556,7 @@ function injectAnnotations(state, annotations) {
517
556
  return cloned$1;
518
557
  }
519
558
  if (state instanceof RegExp) {
520
- const cloned$1 = new RegExp(state);
521
- cloned$1.lastIndex = state.lastIndex;
559
+ const cloned$1 = cloneRegExpShape(state);
522
560
  cloned$1[annotationKey] = protectedAnnotations;
523
561
  return cloned$1;
524
562
  }
@@ -570,4 +608,5 @@ exports.hasMeaningfulAnnotations = hasMeaningfulAnnotations;
570
608
  exports.inheritAnnotations = inheritAnnotations;
571
609
  exports.injectAnnotations = injectAnnotations;
572
610
  exports.isInjectedAnnotationWrapper = isInjectedAnnotationWrapper;
611
+ exports.normalizeRunAnnotationInput = normalizeRunAnnotationInput;
573
612
  exports.unwrapInjectedAnnotationWrapper = unwrapInjectedAnnotationWrapper;
@@ -64,6 +64,18 @@ type Annotations = Record<symbol, unknown>;
64
64
  */
65
65
  type ReadonlyAnnotations = Readonly<Annotations>;
66
66
  type AnnotationInput = Annotations | ReadonlyAnnotations;
67
+ /**
68
+ * Normalizes annotation input for a fresh parse run.
69
+ *
70
+ * When callers feed a protected annotation view returned by `getAnnotations()`
71
+ * back into a new parse entrypoint, Optique unwraps it to the caller-owned
72
+ * record first so the new run gets its own protected views.
73
+ *
74
+ * @param annotations The caller-supplied annotations input.
75
+ * @returns The raw annotation record to inject for the new run.
76
+ * @internal
77
+ */
78
+ declare function normalizeRunAnnotationInput(annotations: AnnotationInput): AnnotationInput;
67
79
  /**
68
80
  * Options for parse functions.
69
81
  * @since 0.10.0
@@ -76,7 +88,7 @@ interface ParseOptions {
76
88
  * Optique treats these values as immutable input and exposes them back to
77
89
  * parsers only through protected read-only views.
78
90
  */
79
- annotations?: Annotations;
91
+ annotations?: Annotations | ReadonlyAnnotations;
80
92
  }
81
93
  /**
82
94
  * Extracts annotations from parser state.
@@ -169,4 +181,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
169
181
  */
170
182
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
171
183
  //#endregion
172
- export { Annotations, ParseOptions, ReadonlyAnnotations, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
184
+ export { Annotations, ParseOptions, ReadonlyAnnotations, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, normalizeRunAnnotationInput, unwrapInjectedAnnotationWrapper };
@@ -64,6 +64,18 @@ type Annotations = Record<symbol, unknown>;
64
64
  */
65
65
  type ReadonlyAnnotations = Readonly<Annotations>;
66
66
  type AnnotationInput = Annotations | ReadonlyAnnotations;
67
+ /**
68
+ * Normalizes annotation input for a fresh parse run.
69
+ *
70
+ * When callers feed a protected annotation view returned by `getAnnotations()`
71
+ * back into a new parse entrypoint, Optique unwraps it to the caller-owned
72
+ * record first so the new run gets its own protected views.
73
+ *
74
+ * @param annotations The caller-supplied annotations input.
75
+ * @returns The raw annotation record to inject for the new run.
76
+ * @internal
77
+ */
78
+ declare function normalizeRunAnnotationInput(annotations: AnnotationInput): AnnotationInput;
67
79
  /**
68
80
  * Options for parse functions.
69
81
  * @since 0.10.0
@@ -76,7 +88,7 @@ interface ParseOptions {
76
88
  * Optique treats these values as immutable input and exposes them back to
77
89
  * parsers only through protected read-only views.
78
90
  */
79
- annotations?: Annotations;
91
+ annotations?: Annotations | ReadonlyAnnotations;
80
92
  }
81
93
  /**
82
94
  * Extracts annotations from parser state.
@@ -169,4 +181,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
169
181
  */
170
182
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
171
183
  //#endregion
172
- export { Annotations, ParseOptions, ReadonlyAnnotations, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
184
+ export { Annotations, ParseOptions, ReadonlyAnnotations, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, normalizeRunAnnotationInput, unwrapInjectedAnnotationWrapper };
@@ -80,6 +80,29 @@ function defineProtectedDataProperty(context, target, key, descriptor) {
80
80
  set: () => throwReadonlyAnnotationMutation()
81
81
  });
82
82
  }
83
+ function copyRegExpMetadata(source, target, transformValue) {
84
+ const sourcePrototype = Object.getPrototypeOf(source);
85
+ if (Object.getPrototypeOf(target) !== sourcePrototype) Object.setPrototypeOf(target, sourcePrototype);
86
+ for (const key of Reflect.ownKeys(source)) {
87
+ if (key === "lastIndex") continue;
88
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
89
+ if (descriptor == null) continue;
90
+ if ("value" in descriptor && transformValue != null) {
91
+ Object.defineProperty(target, key, {
92
+ ...descriptor,
93
+ value: transformValue(descriptor.value)
94
+ });
95
+ continue;
96
+ }
97
+ Object.defineProperty(target, key, descriptor);
98
+ }
99
+ target.lastIndex = source.lastIndex;
100
+ }
101
+ function cloneRegExpShape(source) {
102
+ const cloned = new RegExp(source);
103
+ copyRegExpMetadata(source, cloned);
104
+ return cloned;
105
+ }
83
106
  function createProtectedObjectView(target, context) {
84
107
  if (Array.isArray(target)) {
85
108
  const view$1 = new Array(target.length);
@@ -230,12 +253,13 @@ function createProtectedDateView(target, context) {
230
253
  function createProtectedRegExpView(target, context) {
231
254
  const methodCache = /* @__PURE__ */ new Map();
232
255
  const cloned = new RegExp(target);
233
- cloned.lastIndex = target.lastIndex;
234
256
  const view = new Proxy(cloned, {
235
257
  get(clonedTarget, key) {
236
- const value = Reflect.get(clonedTarget, key, clonedTarget);
237
258
  if (key === "compile") return cacheProtectedMethod(methodCache, key, () => (..._args) => throwReadonlyAnnotationMutation());
238
- return typeof value === "function" ? value.bind(clonedTarget) : value;
259
+ const ownDescriptor = Object.getOwnPropertyDescriptor(clonedTarget, key);
260
+ if (ownDescriptor != null && "value" in ownDescriptor) return ownDescriptor.value;
261
+ const value = Reflect.get(clonedTarget, key, clonedTarget);
262
+ return typeof value === "function" ? value.bind(clonedTarget) : protectAnnotationValue(value, context);
239
263
  },
240
264
  set() {
241
265
  throwReadonlyAnnotationMutation();
@@ -253,7 +277,9 @@ function createProtectedRegExpView(target, context) {
253
277
  throwReadonlyAnnotationMutation();
254
278
  }
255
279
  });
256
- return registerProtectedAnnotationView(context, target, view);
280
+ registerProtectedAnnotationView(context, target, view);
281
+ copyRegExpMetadata(target, cloned, (value) => protectAnnotationValue(value, context));
282
+ return view;
257
283
  }
258
284
  function createProtectedURLSearchParamsView(target, context) {
259
285
  const methodCache = /* @__PURE__ */ new Map();
@@ -334,6 +360,20 @@ function protectAnnotationValue(value, context) {
334
360
  return value;
335
361
  }
336
362
  /**
363
+ * Normalizes annotation input for a fresh parse run.
364
+ *
365
+ * When callers feed a protected annotation view returned by `getAnnotations()`
366
+ * back into a new parse entrypoint, Optique unwraps it to the caller-owned
367
+ * record first so the new run gets its own protected views.
368
+ *
369
+ * @param annotations The caller-supplied annotations input.
370
+ * @returns The raw annotation record to inject for the new run.
371
+ * @internal
372
+ */
373
+ function normalizeRunAnnotationInput(annotations) {
374
+ return isProtectedAnnotationView(annotations) ? unwrapProtectedAnnotationTarget(annotations) : annotations;
375
+ }
376
+ /**
337
377
  * Extracts annotations from parser state.
338
378
  *
339
379
  * @param state Parser state that may contain annotations
@@ -422,8 +462,7 @@ function inheritAnnotations(source, target) {
422
462
  return cloned$1;
423
463
  }
424
464
  if (target instanceof RegExp) {
425
- const cloned$1 = new RegExp(target);
426
- cloned$1.lastIndex = target.lastIndex;
465
+ const cloned$1 = cloneRegExpShape(target);
427
466
  cloned$1[annotationKey] = annotations;
428
467
  return cloned$1;
429
468
  }
@@ -516,8 +555,7 @@ function injectAnnotations(state, annotations) {
516
555
  return cloned$1;
517
556
  }
518
557
  if (state instanceof RegExp) {
519
- const cloned$1 = new RegExp(state);
520
- cloned$1.lastIndex = state.lastIndex;
558
+ const cloned$1 = cloneRegExpShape(state);
521
559
  cloned$1[annotationKey] = protectedAnnotations;
522
560
  return cloned$1;
523
561
  }
@@ -559,4 +597,4 @@ function isInjectedAnnotationWrapper(value) {
559
597
  }
560
598
 
561
599
  //#endregion
562
- export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
600
+ export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, normalizeRunAnnotationInput, unwrapInjectedAnnotationWrapper };
package/dist/parser.cjs CHANGED
@@ -69,7 +69,7 @@ function createParserContext(frame, exec) {
69
69
  function injectAnnotationsIntoState(state, options) {
70
70
  const annotations = options?.annotations;
71
71
  if (!require_annotations.hasMeaningfulAnnotations(annotations)) return state;
72
- return require_annotations.injectAnnotations(state, annotations);
72
+ return require_annotations.injectAnnotations(state, require_annotations.normalizeRunAnnotationInput(annotations));
73
73
  }
74
74
  /**
75
75
  * Parses an array of command-line arguments using the provided combined parser.
package/dist/parser.js CHANGED
@@ -1,4 +1,4 @@
1
- import { hasMeaningfulAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./annotations.js";
1
+ import { hasMeaningfulAnnotations, injectAnnotations, isInjectedAnnotationWrapper, normalizeRunAnnotationInput, unwrapInjectedAnnotationWrapper } from "./annotations.js";
2
2
  import { cloneMessage, message } from "./message.js";
3
3
  import { cloneUsage, normalizeUsage } from "./usage.js";
4
4
  import { cloneDocEntry, isDocEntryHidden } from "./doc.js";
@@ -69,7 +69,7 @@ function createParserContext(frame, exec) {
69
69
  function injectAnnotationsIntoState(state, options) {
70
70
  const annotations = options?.annotations;
71
71
  if (!hasMeaningfulAnnotations(annotations)) return state;
72
- return injectAnnotations(state, annotations);
72
+ return injectAnnotations(state, normalizeRunAnnotationInput(annotations));
73
73
  }
74
74
  /**
75
75
  * Parses an array of command-line arguments using the provided combined parser.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.1852+6dd8742f",
3
+ "version": "1.0.0-dev.1856+acef001b",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",