@optique/core 1.4.0-dev.2978 → 1.4.0-dev.2979

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.
@@ -39,7 +39,8 @@ function withChildContext(context, segment, state, usage) {
39
39
  const exec = withChildExecPath(context.exec, segment);
40
40
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
41
41
  return {
42
- ...require_short_option.withOptionScopeChild(context, segment),
42
+ ...context,
43
+ ...require_short_option.getChildOptionScope(context, segment, exec?.path),
43
44
  state,
44
45
  ...usage != null ? { usage } : {},
45
46
  ...exec != null ? {
@@ -1,5 +1,5 @@
1
1
  import { mergeCommandDocPolicy } from "./internal/command-doc-policy.js";
2
- import { withOptionScopeChild } from "./short-option.js";
2
+ import { getChildOptionScope } from "./short-option.js";
3
3
 
4
4
  //#region src/execution-context.ts
5
5
  /**
@@ -39,7 +39,8 @@ function withChildContext(context, segment, state, usage) {
39
39
  const exec = withChildExecPath(context.exec, segment);
40
40
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
41
41
  return {
42
- ...withOptionScopeChild(context, segment),
42
+ ...context,
43
+ ...getChildOptionScope(context, segment, exec?.path),
43
44
  state,
44
45
  ...usage != null ? { usage } : {},
45
46
  ...exec != null ? {
@@ -18,6 +18,16 @@ function getScopeBindings(selections) {
18
18
  }
19
19
  return bindings;
20
20
  }
21
+ function setSelection(selections, source, selected) {
22
+ if (selections.map.get(source) === selected) return;
23
+ if (!selections.owned) {
24
+ const previous = selections.map;
25
+ selections.map = new Map(previous);
26
+ scopeBindings.set(selections.map, getScopeBindings(previous));
27
+ selections.owned = true;
28
+ }
29
+ selections.map.set(source, selected);
30
+ }
21
31
  function bindScope(source, path, selections) {
22
32
  const boundScopes = getScopeBindings(selections);
23
33
  let node = boundScopes.get(source);
@@ -47,12 +57,9 @@ function bindScope(source, path, selections) {
47
57
  function scopePath(context) {
48
58
  return context.exec?.path ?? context[optionPathKey] ?? [];
49
59
  }
50
- /** Tracks child occurrences even for contexts without execution metadata. @internal */
51
- function withOptionScopeChild(context, segment) {
52
- return {
53
- ...context,
54
- [optionPathKey]: [...scopePath(context), segment]
55
- };
60
+ /** Supplies child occurrence metadata without copying the parent. @internal */
61
+ function getChildOptionScope(context, segment, path) {
62
+ return { [optionPathKey]: path ?? [...scopePath(context), segment] };
56
63
  }
57
64
  const primitiveScopes = /* @__PURE__ */ new WeakMap();
58
65
  function parserScope(parser) {
@@ -104,7 +111,7 @@ function selectableOptionScope(initial) {
104
111
  select(context, selected) {
105
112
  const selections = context[optionScopeKey]?.selections;
106
113
  if (selections == null) return;
107
- selections.set(bindScope(source, scopePath(context), selections), selected);
114
+ setSelection(selections, bindScope(source, scopePath(context), selections.map), selected);
108
115
  }
109
116
  };
110
117
  }
@@ -135,7 +142,7 @@ function conditionalOptionScope(discriminator, fallback, candidates = []) {
135
142
  /** Returns the names reachable in this parse scope. @internal */
136
143
  function getOptionScope(context) {
137
144
  const scoped = context[optionScopeKey];
138
- const names = scoped == null ? require_usage.extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections, void 0, context)])]);
145
+ const names = scoped == null ? require_usage.extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections.map, void 0, context)])]);
139
146
  return names;
140
147
  }
141
148
  /** Adds reachable names without consulting the flattened help tree. @internal */
@@ -146,19 +153,42 @@ function withOptionScope(context, names) {
146
153
  [optionScopeKey]: {
147
154
  names: new Set([...inherited?.names ?? [], ...names]),
148
155
  sources: inherited?.sources ?? /* @__PURE__ */ new Set(),
149
- selections: inherited?.selections ?? /* @__PURE__ */ new Map()
156
+ selections: inherited?.selections ?? {
157
+ map: /* @__PURE__ */ new Map(),
158
+ owned: true
159
+ }
150
160
  }
151
161
  };
152
162
  }
163
+ const scopeUnions = /* @__PURE__ */ new WeakMap();
164
+ function withScopeSource(sources, source) {
165
+ let unions = scopeUnions.get(sources);
166
+ if (unions == null) {
167
+ unions = /* @__PURE__ */ new WeakMap();
168
+ scopeUnions.set(sources, unions);
169
+ }
170
+ let combined = unions.get(source);
171
+ if (combined == null) {
172
+ combined = new Set([...sources, source]);
173
+ unions.set(source, combined);
174
+ }
175
+ return combined;
176
+ }
153
177
  /** Adds a parser's owned declarations, retaining modifier metadata. @internal */
154
178
  function withParserOptionScope(context, parser, segment) {
155
179
  const inherited = context[optionScopeKey];
156
- const selections = inherited?.selections ?? /* @__PURE__ */ new Map();
180
+ const selections = inherited?.selections ?? {
181
+ map: /* @__PURE__ */ new Map(),
182
+ owned: true
183
+ };
184
+ const source = bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment], selections.map);
185
+ if (inherited?.sources.has(source)) return context;
186
+ const sources = inherited == null ? new Set([source]) : withScopeSource(inherited.sources, source);
157
187
  return {
158
188
  ...context,
159
189
  [optionScopeKey]: {
160
190
  names: inherited?.names ?? /* @__PURE__ */ new Set(),
161
- sources: new Set([...inherited?.sources ?? [], bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment], selections)]),
191
+ sources,
162
192
  selections
163
193
  }
164
194
  };
@@ -167,8 +197,11 @@ function withParserOptionScope(context, parser, segment) {
167
197
  function forkOptionScope(context) {
168
198
  const scoped = context[optionScopeKey];
169
199
  if (scoped == null) return context;
170
- const selections = new Map(scoped.selections);
171
- scopeBindings.set(selections, getScopeBindings(scoped.selections));
200
+ scoped.selections.owned = false;
201
+ const selections = {
202
+ map: scoped.selections.map,
203
+ owned: false
204
+ };
172
205
  return {
173
206
  ...context,
174
207
  [optionScopeKey]: {
@@ -181,7 +214,7 @@ function forkOptionScope(context) {
181
214
  function adoptOptionScope(context, next) {
182
215
  const own = context[optionScopeKey];
183
216
  const child = next[optionScopeKey];
184
- if (own != null && child != null) for (const [source, selected] of child.selections) own.selections.set(source, selected);
217
+ if (own != null && child != null && own.selections.map !== child.selections.map) for (const [source, selected] of child.selections.map) setSelection(own.selections, source, selected);
185
218
  return context;
186
219
  }
187
220
  /** Removes names reserved only for a speculative probe. @internal */
@@ -268,7 +301,7 @@ function attachedValuePrefix(context, prefix, optionNames) {
268
301
  };
269
302
  const scoped = context[optionScopeKey];
270
303
  if (scoped == null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(context.usage, names, false);
271
- else for (const source of scoped.sources) source(scoped.selections, names, context);
304
+ else for (const source of scoped.sources) source(scoped.selections.map, names, context);
272
305
  for (let index = 1; index < prefix.length;) {
273
306
  const character = String.fromCodePoint(prefix.codePointAt(index));
274
307
  const nextIndex = index + character.length;
@@ -305,6 +338,7 @@ exports.combinedOptionScope = combinedOptionScope;
305
338
  exports.conditionalOptionScope = conditionalOptionScope;
306
339
  exports.forkOptionScope = forkOptionScope;
307
340
  exports.fullNameOwnsToken = fullNameOwnsToken;
341
+ exports.getChildOptionScope = getChildOptionScope;
308
342
  exports.inheritOptionScope = inheritOptionScope;
309
343
  exports.prefixSuggestion = prefixSuggestion;
310
344
  exports.repeatedOptionScope = repeatedOptionScope;
@@ -312,5 +346,4 @@ exports.restoreOptionScope = restoreOptionScope;
312
346
  exports.scopeParser = scopeParser;
313
347
  exports.selectableOptionScope = selectableOptionScope;
314
348
  exports.withOptionScope = withOptionScope;
315
- exports.withOptionScopeChild = withOptionScopeChild;
316
349
  exports.withParserOptionScope = withParserOptionScope;
@@ -18,6 +18,16 @@ function getScopeBindings(selections) {
18
18
  }
19
19
  return bindings;
20
20
  }
21
+ function setSelection(selections, source, selected) {
22
+ if (selections.map.get(source) === selected) return;
23
+ if (!selections.owned) {
24
+ const previous = selections.map;
25
+ selections.map = new Map(previous);
26
+ scopeBindings.set(selections.map, getScopeBindings(previous));
27
+ selections.owned = true;
28
+ }
29
+ selections.map.set(source, selected);
30
+ }
21
31
  function bindScope(source, path, selections) {
22
32
  const boundScopes = getScopeBindings(selections);
23
33
  let node = boundScopes.get(source);
@@ -47,12 +57,9 @@ function bindScope(source, path, selections) {
47
57
  function scopePath(context) {
48
58
  return context.exec?.path ?? context[optionPathKey] ?? [];
49
59
  }
50
- /** Tracks child occurrences even for contexts without execution metadata. @internal */
51
- function withOptionScopeChild(context, segment) {
52
- return {
53
- ...context,
54
- [optionPathKey]: [...scopePath(context), segment]
55
- };
60
+ /** Supplies child occurrence metadata without copying the parent. @internal */
61
+ function getChildOptionScope(context, segment, path) {
62
+ return { [optionPathKey]: path ?? [...scopePath(context), segment] };
56
63
  }
57
64
  const primitiveScopes = /* @__PURE__ */ new WeakMap();
58
65
  function parserScope(parser) {
@@ -104,7 +111,7 @@ function selectableOptionScope(initial) {
104
111
  select(context, selected) {
105
112
  const selections = context[optionScopeKey]?.selections;
106
113
  if (selections == null) return;
107
- selections.set(bindScope(source, scopePath(context), selections), selected);
114
+ setSelection(selections, bindScope(source, scopePath(context), selections.map), selected);
108
115
  }
109
116
  };
110
117
  }
@@ -135,7 +142,7 @@ function conditionalOptionScope(discriminator, fallback, candidates = []) {
135
142
  /** Returns the names reachable in this parse scope. @internal */
136
143
  function getOptionScope(context) {
137
144
  const scoped = context[optionScopeKey];
138
- const names = scoped == null ? extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections, void 0, context)])]);
145
+ const names = scoped == null ? extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections.map, void 0, context)])]);
139
146
  return names;
140
147
  }
141
148
  /** Adds reachable names without consulting the flattened help tree. @internal */
@@ -146,19 +153,42 @@ function withOptionScope(context, names) {
146
153
  [optionScopeKey]: {
147
154
  names: new Set([...inherited?.names ?? [], ...names]),
148
155
  sources: inherited?.sources ?? /* @__PURE__ */ new Set(),
149
- selections: inherited?.selections ?? /* @__PURE__ */ new Map()
156
+ selections: inherited?.selections ?? {
157
+ map: /* @__PURE__ */ new Map(),
158
+ owned: true
159
+ }
150
160
  }
151
161
  };
152
162
  }
163
+ const scopeUnions = /* @__PURE__ */ new WeakMap();
164
+ function withScopeSource(sources, source) {
165
+ let unions = scopeUnions.get(sources);
166
+ if (unions == null) {
167
+ unions = /* @__PURE__ */ new WeakMap();
168
+ scopeUnions.set(sources, unions);
169
+ }
170
+ let combined = unions.get(source);
171
+ if (combined == null) {
172
+ combined = new Set([...sources, source]);
173
+ unions.set(source, combined);
174
+ }
175
+ return combined;
176
+ }
153
177
  /** Adds a parser's owned declarations, retaining modifier metadata. @internal */
154
178
  function withParserOptionScope(context, parser, segment) {
155
179
  const inherited = context[optionScopeKey];
156
- const selections = inherited?.selections ?? /* @__PURE__ */ new Map();
180
+ const selections = inherited?.selections ?? {
181
+ map: /* @__PURE__ */ new Map(),
182
+ owned: true
183
+ };
184
+ const source = bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment], selections.map);
185
+ if (inherited?.sources.has(source)) return context;
186
+ const sources = inherited == null ? new Set([source]) : withScopeSource(inherited.sources, source);
157
187
  return {
158
188
  ...context,
159
189
  [optionScopeKey]: {
160
190
  names: inherited?.names ?? /* @__PURE__ */ new Set(),
161
- sources: new Set([...inherited?.sources ?? [], bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment], selections)]),
191
+ sources,
162
192
  selections
163
193
  }
164
194
  };
@@ -167,8 +197,11 @@ function withParserOptionScope(context, parser, segment) {
167
197
  function forkOptionScope(context) {
168
198
  const scoped = context[optionScopeKey];
169
199
  if (scoped == null) return context;
170
- const selections = new Map(scoped.selections);
171
- scopeBindings.set(selections, getScopeBindings(scoped.selections));
200
+ scoped.selections.owned = false;
201
+ const selections = {
202
+ map: scoped.selections.map,
203
+ owned: false
204
+ };
172
205
  return {
173
206
  ...context,
174
207
  [optionScopeKey]: {
@@ -181,7 +214,7 @@ function forkOptionScope(context) {
181
214
  function adoptOptionScope(context, next) {
182
215
  const own = context[optionScopeKey];
183
216
  const child = next[optionScopeKey];
184
- if (own != null && child != null) for (const [source, selected] of child.selections) own.selections.set(source, selected);
217
+ if (own != null && child != null && own.selections.map !== child.selections.map) for (const [source, selected] of child.selections.map) setSelection(own.selections, source, selected);
185
218
  return context;
186
219
  }
187
220
  /** Removes names reserved only for a speculative probe. @internal */
@@ -268,7 +301,7 @@ function attachedValuePrefix(context, prefix, optionNames) {
268
301
  };
269
302
  const scoped = context[optionScopeKey];
270
303
  if (scoped == null) collectOptionNamesAtCurrentCommandDepth(context.usage, names, false);
271
- else for (const source of scoped.sources) source(scoped.selections, names, context);
304
+ else for (const source of scoped.sources) source(scoped.selections.map, names, context);
272
305
  for (let index = 1; index < prefix.length;) {
273
306
  const character = String.fromCodePoint(prefix.codePointAt(index));
274
307
  const nextIndex = index + character.length;
@@ -299,4 +332,4 @@ function prefixSuggestion(head, suggestion) {
299
332
  }
300
333
 
301
334
  //#endregion
302
- export { adoptOptionScope, attachedValuePrefix, combinedOptionScope, conditionalOptionScope, forkOptionScope, fullNameOwnsToken, inheritOptionScope, prefixSuggestion, repeatedOptionScope, restoreOptionScope, scopeParser, selectableOptionScope, withOptionScope, withOptionScopeChild, withParserOptionScope };
335
+ export { adoptOptionScope, attachedValuePrefix, combinedOptionScope, conditionalOptionScope, forkOptionScope, fullNameOwnsToken, getChildOptionScope, inheritOptionScope, prefixSuggestion, repeatedOptionScope, restoreOptionScope, scopeParser, selectableOptionScope, withOptionScope, withParserOptionScope };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.4.0-dev.2978",
3
+ "version": "1.4.0-dev.2979",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -269,7 +269,7 @@
269
269
  },
270
270
  "sideEffects": false,
271
271
  "devDependencies": {
272
- "@optique/env": "1.4.0-dev.2978+84f95710",
272
+ "@optique/env": "1.4.0-dev.2979+a175cdb7",
273
273
  "@types/node": "^24.0.0",
274
274
  "fast-check": "^4.7.0",
275
275
  "tsdown": "^0.13.0",