@optique/core 1.0.0-dev.1766 → 1.0.0-dev.1776

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.
@@ -131,6 +131,21 @@ function inheritAnnotations(source, target) {
131
131
  return cloned;
132
132
  }
133
133
  /**
134
+ * Returns whether an annotations record carries at least one own symbol key.
135
+ *
136
+ * An annotations object with no own symbol keys is treated as a no-op by the
137
+ * injection pipeline: it should behave identically to omitting the
138
+ * `annotations` option entirely. `null` and `undefined` are accepted for
139
+ * call-site convenience and always return `false`.
140
+ *
141
+ * @param annotations The annotations record to check.
142
+ * @returns `true` when the record has at least one own symbol key.
143
+ * @internal
144
+ */
145
+ function hasMeaningfulAnnotations(annotations) {
146
+ return annotations != null && Object.getOwnPropertySymbols(annotations).length > 0;
147
+ }
148
+ /**
134
149
  * Injects annotations into parser state while preserving state shape.
135
150
  *
136
151
  * - Primitive, null, and undefined states are wrapped with internal metadata.
@@ -138,6 +153,8 @@ function inheritAnnotations(source, target) {
138
153
  * - Plain object states are shallow-cloned with annotations attached.
139
154
  * - Built-in object states (Date/Map/Set/RegExp) are cloned by constructor.
140
155
  * - Other non-plain object states are cloned via prototype/descriptors.
156
+ * - If the `annotations` record has no own symbol keys, the state is
157
+ * returned unchanged; an empty annotations object is a no-op.
141
158
  *
142
159
  * @param state The parser state to annotate.
143
160
  * @param annotations The annotations to inject.
@@ -145,6 +162,7 @@ function inheritAnnotations(source, target) {
145
162
  * @internal
146
163
  */
147
164
  function injectAnnotations(state, annotations) {
165
+ if (!hasMeaningfulAnnotations(annotations)) return state;
148
166
  if (state == null || typeof state !== "object") {
149
167
  const wrapper = {};
150
168
  Object.defineProperties(wrapper, {
@@ -243,6 +261,7 @@ exports.annotationStateValueKey = annotationStateValueKey;
243
261
  exports.annotationWrapperKey = annotationWrapperKey;
244
262
  exports.firstPassAnnotationKey = firstPassAnnotationKey;
245
263
  exports.getAnnotations = getAnnotations;
264
+ exports.hasMeaningfulAnnotations = hasMeaningfulAnnotations;
246
265
  exports.inheritAnnotations = inheritAnnotations;
247
266
  exports.injectAnnotations = injectAnnotations;
248
267
  exports.isInjectedAnnotationWrapper = isInjectedAnnotationWrapper;
@@ -100,6 +100,19 @@ declare function annotateFreshArray<T>(source: unknown, target: readonly T[]): r
100
100
  * @internal
101
101
  */
102
102
  declare function inheritAnnotations<T>(source: unknown, target: T): T;
103
+ /**
104
+ * Returns whether an annotations record carries at least one own symbol key.
105
+ *
106
+ * An annotations object with no own symbol keys is treated as a no-op by the
107
+ * injection pipeline: it should behave identically to omitting the
108
+ * `annotations` option entirely. `null` and `undefined` are accepted for
109
+ * call-site convenience and always return `false`.
110
+ *
111
+ * @param annotations The annotations record to check.
112
+ * @returns `true` when the record has at least one own symbol key.
113
+ * @internal
114
+ */
115
+ declare function hasMeaningfulAnnotations(annotations: Annotations | null | undefined): annotations is Annotations;
103
116
  /**
104
117
  * Injects annotations into parser state while preserving state shape.
105
118
  *
@@ -108,6 +121,8 @@ declare function inheritAnnotations<T>(source: unknown, target: T): T;
108
121
  * - Plain object states are shallow-cloned with annotations attached.
109
122
  * - Built-in object states (Date/Map/Set/RegExp) are cloned by constructor.
110
123
  * - Other non-plain object states are cloned via prototype/descriptors.
124
+ * - If the `annotations` record has no own symbol keys, the state is
125
+ * returned unchanged; an empty annotations object is a no-op.
111
126
  *
112
127
  * @param state The parser state to annotate.
113
128
  * @param annotations The annotations to inject.
@@ -134,4 +149,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
134
149
  */
135
150
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
136
151
  //#endregion
137
- export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
152
+ export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
@@ -100,6 +100,19 @@ declare function annotateFreshArray<T>(source: unknown, target: readonly T[]): r
100
100
  * @internal
101
101
  */
102
102
  declare function inheritAnnotations<T>(source: unknown, target: T): T;
103
+ /**
104
+ * Returns whether an annotations record carries at least one own symbol key.
105
+ *
106
+ * An annotations object with no own symbol keys is treated as a no-op by the
107
+ * injection pipeline: it should behave identically to omitting the
108
+ * `annotations` option entirely. `null` and `undefined` are accepted for
109
+ * call-site convenience and always return `false`.
110
+ *
111
+ * @param annotations The annotations record to check.
112
+ * @returns `true` when the record has at least one own symbol key.
113
+ * @internal
114
+ */
115
+ declare function hasMeaningfulAnnotations(annotations: Annotations | null | undefined): annotations is Annotations;
103
116
  /**
104
117
  * Injects annotations into parser state while preserving state shape.
105
118
  *
@@ -108,6 +121,8 @@ declare function inheritAnnotations<T>(source: unknown, target: T): T;
108
121
  * - Plain object states are shallow-cloned with annotations attached.
109
122
  * - Built-in object states (Date/Map/Set/RegExp) are cloned by constructor.
110
123
  * - Other non-plain object states are cloned via prototype/descriptors.
124
+ * - If the `annotations` record has no own symbol keys, the state is
125
+ * returned unchanged; an empty annotations object is a no-op.
111
126
  *
112
127
  * @param state The parser state to annotate.
113
128
  * @param annotations The annotations to inject.
@@ -134,4 +149,4 @@ declare function unwrapInjectedAnnotationWrapper<T>(value: T): T;
134
149
  */
135
150
  declare function isInjectedAnnotationWrapper(value: unknown): boolean;
136
151
  //#endregion
137
- export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
152
+ export { Annotations, ParseOptions, annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
@@ -130,6 +130,21 @@ function inheritAnnotations(source, target) {
130
130
  return cloned;
131
131
  }
132
132
  /**
133
+ * Returns whether an annotations record carries at least one own symbol key.
134
+ *
135
+ * An annotations object with no own symbol keys is treated as a no-op by the
136
+ * injection pipeline: it should behave identically to omitting the
137
+ * `annotations` option entirely. `null` and `undefined` are accepted for
138
+ * call-site convenience and always return `false`.
139
+ *
140
+ * @param annotations The annotations record to check.
141
+ * @returns `true` when the record has at least one own symbol key.
142
+ * @internal
143
+ */
144
+ function hasMeaningfulAnnotations(annotations) {
145
+ return annotations != null && Object.getOwnPropertySymbols(annotations).length > 0;
146
+ }
147
+ /**
133
148
  * Injects annotations into parser state while preserving state shape.
134
149
  *
135
150
  * - Primitive, null, and undefined states are wrapped with internal metadata.
@@ -137,6 +152,8 @@ function inheritAnnotations(source, target) {
137
152
  * - Plain object states are shallow-cloned with annotations attached.
138
153
  * - Built-in object states (Date/Map/Set/RegExp) are cloned by constructor.
139
154
  * - Other non-plain object states are cloned via prototype/descriptors.
155
+ * - If the `annotations` record has no own symbol keys, the state is
156
+ * returned unchanged; an empty annotations object is a no-op.
140
157
  *
141
158
  * @param state The parser state to annotate.
142
159
  * @param annotations The annotations to inject.
@@ -144,6 +161,7 @@ function inheritAnnotations(source, target) {
144
161
  * @internal
145
162
  */
146
163
  function injectAnnotations(state, annotations) {
164
+ if (!hasMeaningfulAnnotations(annotations)) return state;
147
165
  if (state == null || typeof state !== "object") {
148
166
  const wrapper = {};
149
167
  Object.defineProperties(wrapper, {
@@ -236,4 +254,4 @@ function isInjectedAnnotationWrapper(value) {
236
254
  }
237
255
 
238
256
  //#endregion
239
- export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
257
+ export { annotateFreshArray, annotationKey, annotationStateValueKey, annotationWrapperKey, firstPassAnnotationKey, getAnnotations, hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper };
package/dist/parser.cjs CHANGED
@@ -68,7 +68,7 @@ function createParserContext(frame, exec) {
68
68
  }
69
69
  function injectAnnotationsIntoState(state, options) {
70
70
  const annotations = options?.annotations;
71
- if (annotations == null) return state;
71
+ if (!require_annotations.hasMeaningfulAnnotations(annotations)) return state;
72
72
  return require_annotations.injectAnnotations(state, annotations);
73
73
  }
74
74
  /**
@@ -97,7 +97,7 @@ function injectAnnotationsIntoState(state, options) {
97
97
  */
98
98
  function parseSync(parser, args, options) {
99
99
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
100
- const shouldUnwrapAnnotatedValue = options?.annotations != null || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
100
+ const shouldUnwrapAnnotatedValue = require_annotations.hasMeaningfulAnnotations(options?.annotations) || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
101
101
  const exec = {
102
102
  usage: parser.usage,
103
103
  phase: "parse",
@@ -169,7 +169,7 @@ function isBufferUnchanged(previous, current) {
169
169
  */
170
170
  async function parseAsync(parser, args, options) {
171
171
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
172
- const shouldUnwrapAnnotatedValue = options?.annotations != null || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
172
+ const shouldUnwrapAnnotatedValue = require_annotations.hasMeaningfulAnnotations(options?.annotations) || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
173
173
  const exec = {
174
174
  usage: parser.usage,
175
175
  phase: "parse",
package/dist/parser.js CHANGED
@@ -1,4 +1,4 @@
1
- import { injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./annotations.js";
1
+ import { hasMeaningfulAnnotations, injectAnnotations, isInjectedAnnotationWrapper, 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";
@@ -68,7 +68,7 @@ function createParserContext(frame, exec) {
68
68
  }
69
69
  function injectAnnotationsIntoState(state, options) {
70
70
  const annotations = options?.annotations;
71
- if (annotations == null) return state;
71
+ if (!hasMeaningfulAnnotations(annotations)) return state;
72
72
  return injectAnnotations(state, annotations);
73
73
  }
74
74
  /**
@@ -97,7 +97,7 @@ function injectAnnotationsIntoState(state, options) {
97
97
  */
98
98
  function parseSync(parser, args, options) {
99
99
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
100
- const shouldUnwrapAnnotatedValue = options?.annotations != null || isInjectedAnnotationWrapper(parser.initialState);
100
+ const shouldUnwrapAnnotatedValue = hasMeaningfulAnnotations(options?.annotations) || isInjectedAnnotationWrapper(parser.initialState);
101
101
  const exec = {
102
102
  usage: parser.usage,
103
103
  phase: "parse",
@@ -169,7 +169,7 @@ function isBufferUnchanged(previous, current) {
169
169
  */
170
170
  async function parseAsync(parser, args, options) {
171
171
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
172
- const shouldUnwrapAnnotatedValue = options?.annotations != null || isInjectedAnnotationWrapper(parser.initialState);
172
+ const shouldUnwrapAnnotatedValue = hasMeaningfulAnnotations(options?.annotations) || isInjectedAnnotationWrapper(parser.initialState);
173
173
  const exec = {
174
174
  usage: parser.usage,
175
175
  phase: "parse",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.0-dev.1766+87276239",
3
+ "version": "1.0.0-dev.1776+898f38af",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",