@optique/core 0.7.7 → 0.7.9

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright 2025 Hong Minhee
3
+ Copyright 2025–2026 Hong Minhee
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
@@ -372,15 +372,18 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
372
372
  parsers = labelOrParsers;
373
373
  options = maybeParsersOrOptions ?? {};
374
374
  }
375
- const parserPairs = Object.entries(parsers);
375
+ const parserKeys = Reflect.ownKeys(parsers);
376
+ const parserPairs = parserKeys.map((k) => [k, parsers[k]]);
376
377
  parserPairs.sort(([_, parserA], [__, parserB]) => parserB.priority - parserA.priority);
377
- const noMatchContext = analyzeNoMatchContext(Object.values(parsers));
378
+ const initialState = {};
379
+ for (const key of parserKeys) initialState[key] = parsers[key].initialState;
380
+ const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
378
381
  return {
379
382
  $valueType: [],
380
383
  $stateType: [],
381
- priority: Math.max(...Object.values(parsers).map((p) => p.priority)),
384
+ priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
382
385
  usage: parserPairs.flatMap(([_, p]) => p.usage),
383
- initialState: Object.fromEntries(Object.entries(parsers).map(([key, parser]) => [key, parser.initialState])),
386
+ initialState,
384
387
  parse(context) {
385
388
  if (!options.allowDuplicates) {
386
389
  const optionNameSources = /* @__PURE__ */ new Map();
@@ -394,7 +397,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
394
397
  for (const [name, sources] of optionNameSources) if (sources.length > 1) return {
395
398
  success: false,
396
399
  consumed: 0,
397
- error: require_message.message`Duplicate option name ${require_message.optionName(name)} found in fields: ${require_message.values(sources)}. Each option name must be unique within a parser combinator.`
400
+ error: require_message.message`Duplicate option name ${require_message.optionName(name)} found in fields: ${require_message.values(sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s))}. Each option name must be unique within a parser combinator.`
398
401
  };
399
402
  }
400
403
  let error = {
@@ -466,8 +469,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
466
469
  },
467
470
  complete(state) {
468
471
  const result = {};
469
- for (const field in state) {
470
- if (!(field in parsers)) continue;
472
+ for (const field of parserKeys) {
471
473
  const valueResult = parsers[field].complete(state[field]);
472
474
  if (valueResult.success) result[field] = valueResult.value;
473
475
  else return {
@@ -372,15 +372,18 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
372
372
  parsers = labelOrParsers;
373
373
  options = maybeParsersOrOptions ?? {};
374
374
  }
375
- const parserPairs = Object.entries(parsers);
375
+ const parserKeys = Reflect.ownKeys(parsers);
376
+ const parserPairs = parserKeys.map((k) => [k, parsers[k]]);
376
377
  parserPairs.sort(([_, parserA], [__, parserB]) => parserB.priority - parserA.priority);
377
- const noMatchContext = analyzeNoMatchContext(Object.values(parsers));
378
+ const initialState = {};
379
+ for (const key of parserKeys) initialState[key] = parsers[key].initialState;
380
+ const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
378
381
  return {
379
382
  $valueType: [],
380
383
  $stateType: [],
381
- priority: Math.max(...Object.values(parsers).map((p) => p.priority)),
384
+ priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
382
385
  usage: parserPairs.flatMap(([_, p]) => p.usage),
383
- initialState: Object.fromEntries(Object.entries(parsers).map(([key, parser]) => [key, parser.initialState])),
386
+ initialState,
384
387
  parse(context) {
385
388
  if (!options.allowDuplicates) {
386
389
  const optionNameSources = /* @__PURE__ */ new Map();
@@ -394,7 +397,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
394
397
  for (const [name, sources] of optionNameSources) if (sources.length > 1) return {
395
398
  success: false,
396
399
  consumed: 0,
397
- error: message`Duplicate option name ${optionName(name)} found in fields: ${values(sources)}. Each option name must be unique within a parser combinator.`
400
+ error: message`Duplicate option name ${optionName(name)} found in fields: ${values(sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s))}. Each option name must be unique within a parser combinator.`
398
401
  };
399
402
  }
400
403
  let error = {
@@ -466,8 +469,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
466
469
  },
467
470
  complete(state) {
468
471
  const result = {};
469
- for (const field in state) {
470
- if (!(field in parsers)) continue;
472
+ for (const field of parserKeys) {
471
473
  const valueResult = parsers[field].complete(state[field]);
472
474
  if (valueResult.success) result[field] = valueResult.value;
473
475
  else return {
@@ -333,10 +333,23 @@ function multiple(parser, options = {}) {
333
333
  },
334
334
  suggest(context, prefix) {
335
335
  const innerState = context.state.length > 0 ? context.state.at(-1) : parser.initialState;
336
- return parser.suggest({
336
+ const suggestions = parser.suggest({
337
337
  ...context,
338
338
  state: innerState
339
339
  }, prefix);
340
+ const selectedValues = /* @__PURE__ */ new Set();
341
+ for (const s of context.state) {
342
+ const completed = parser.complete(s);
343
+ if (completed.success) {
344
+ const valueStr = String(completed.value);
345
+ selectedValues.add(valueStr);
346
+ }
347
+ }
348
+ if (selectedValues.size > 0) return Array.from(suggestions).filter((suggestion) => {
349
+ if (suggestion.kind === "literal") return !selectedValues.has(suggestion.text);
350
+ return true;
351
+ });
352
+ return suggestions;
340
353
  },
341
354
  getDocFragments(state, defaultValue) {
342
355
  const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
package/dist/modifiers.js CHANGED
@@ -333,10 +333,23 @@ function multiple(parser, options = {}) {
333
333
  },
334
334
  suggest(context, prefix) {
335
335
  const innerState = context.state.length > 0 ? context.state.at(-1) : parser.initialState;
336
- return parser.suggest({
336
+ const suggestions = parser.suggest({
337
337
  ...context,
338
338
  state: innerState
339
339
  }, prefix);
340
+ const selectedValues = /* @__PURE__ */ new Set();
341
+ for (const s of context.state) {
342
+ const completed = parser.complete(s);
343
+ if (completed.success) {
344
+ const valueStr = String(completed.value);
345
+ selectedValues.add(valueStr);
346
+ }
347
+ }
348
+ if (selectedValues.size > 0) return Array.from(suggestions).filter((suggestion) => {
349
+ if (suggestion.kind === "literal") return !selectedValues.has(suggestion.text);
350
+ return true;
351
+ });
352
+ return suggestions;
340
353
  },
341
354
  getDocFragments(state, defaultValue) {
342
355
  const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",