@optique/core 1.0.2 → 1.0.5

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.
@@ -516,6 +516,35 @@ function createExclusiveState(parentState, index, parser, result) {
516
516
  return require_annotations.annotateFreshArray(parentState, [index, annotatedResult]);
517
517
  }
518
518
  /**
519
+ * Detects a branch result that handled only the global options terminator.
520
+ * Such a result advances the shared parser context, but does not identify
521
+ * which exclusive branch matched.
522
+ * @internal
523
+ */
524
+ function isOptionsTerminatorOnlyResult(context, result) {
525
+ return !context.optionsTerminated && context.buffer[0] === "--" && result.success && result.next.optionsTerminated && result.consumed.length === 1 && result.consumed[0] === "--";
526
+ }
527
+ function isUnselectedBooleanOptionState(state) {
528
+ return state != null && typeof state === "object" && "success" in state && state.success === true && "value" in state && state.value === false;
529
+ }
530
+ function preserveExclusiveStateAfterOptionsTerminator(context, result) {
531
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, result.next.exec);
532
+ return {
533
+ success: true,
534
+ next: {
535
+ ...context,
536
+ buffer: result.next.buffer,
537
+ optionsTerminated: true,
538
+ state: context.state,
539
+ ...mergedExec != null ? {
540
+ exec: mergedExec,
541
+ dependencyRegistry: mergedExec.dependencyRegistry
542
+ } : {}
543
+ },
544
+ consumed: result.consumed
545
+ };
546
+ }
547
+ /**
519
548
  * Creates a complete() method shared by or() and longestMatch().
520
549
  * @internal
521
550
  */
@@ -752,9 +781,15 @@ function or(...args) {
752
781
  let zeroConsumedBranch = null;
753
782
  let zeroConsumedCount = 0;
754
783
  let provisionalConsuming = null;
784
+ let optionsTerminatorResult = null;
755
785
  let provisionalAmbiguous = false;
756
786
  for (const [parser, i] of orderedParsers) {
757
787
  const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
788
+ if (isOptionsTerminatorOnlyResult(context, result)) {
789
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
790
+ optionsTerminatorResult ??= result;
791
+ continue;
792
+ }
758
793
  if (result.success && result.consumed.length > 0) {
759
794
  if (result.provisional) {
760
795
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -935,6 +970,7 @@ function or(...args) {
935
970
  }
936
971
  }
937
972
  }
973
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
938
974
  return {
939
975
  ...error,
940
976
  success: false
@@ -948,10 +984,16 @@ function or(...args) {
948
984
  let zeroConsumedBranch = null;
949
985
  let zeroConsumedCount = 0;
950
986
  let provisionalConsuming = null;
987
+ let optionsTerminatorResult = null;
951
988
  let provisionalAmbiguous = false;
952
989
  for (const [parser, i] of orderedParsers) {
953
990
  const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
954
991
  const result = await resultOrPromise;
992
+ if (isOptionsTerminatorOnlyResult(context, result)) {
993
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
994
+ optionsTerminatorResult ??= result;
995
+ continue;
996
+ }
955
997
  if (result.success && result.consumed.length > 0) {
956
998
  if (result.provisional) {
957
999
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1134,6 +1176,7 @@ function or(...args) {
1134
1176
  }
1135
1177
  }
1136
1178
  }
1179
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1137
1180
  return {
1138
1181
  ...error,
1139
1182
  success: false
@@ -1221,82 +1264,122 @@ function longestMatch(...args) {
1221
1264
  return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
1222
1265
  })()
1223
1266
  });
1224
- const parseSync = (context) => {
1267
+ const commitLongestMatch = (context, match, optionsTerminatorResult) => {
1268
+ const selectedResult = optionsTerminatorResult == null ? match.result : {
1269
+ ...match.result,
1270
+ next: {
1271
+ ...match.result.next,
1272
+ buffer: optionsTerminatorResult.next.buffer,
1273
+ optionsTerminated: true
1274
+ },
1275
+ consumed: [...optionsTerminatorResult.consumed, ...match.result.consumed]
1276
+ };
1277
+ const parser = parsers[match.index];
1278
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, selectedResult.next.exec);
1279
+ return {
1280
+ success: true,
1281
+ next: {
1282
+ ...context,
1283
+ buffer: selectedResult.next.buffer,
1284
+ optionsTerminated: selectedResult.next.optionsTerminated,
1285
+ state: createExclusiveState(context.state, match.index, parser, selectedResult),
1286
+ ...mergedExec != null ? {
1287
+ exec: mergedExec,
1288
+ dependencyRegistry: mergedExec.dependencyRegistry
1289
+ } : {}
1290
+ },
1291
+ consumed: selectedResult.consumed
1292
+ };
1293
+ };
1294
+ const resolveLongestMatchOptionsTerminator = (context, bestMatch, optionsTerminatorMatches) => {
1295
+ if (optionsTerminatorMatches.length < 1) return null;
1296
+ if (bestMatch != null && bestMatch.consumed > 0) return null;
1297
+ const activeState = normalizeExclusiveState(context.state);
1298
+ if (activeState != null && activeState[1].success && activeState[1].consumed.length > 0) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1299
+ let selected = bestMatch == null ? null : {
1300
+ match: bestMatch,
1301
+ fromTerminator: false
1302
+ };
1303
+ for (const match of optionsTerminatorMatches) {
1304
+ if (!match.selectedAfterTerminator && (extractRequiredUsage(parsers[match.index].usage).length > 0 || isUnselectedBooleanOptionState(match.result.next.state))) continue;
1305
+ const selectedIsProvisional = selected != null && !!selected.match.result.provisional;
1306
+ const matchIsProvisional = !!match.result.provisional;
1307
+ if (selected == null || selectedIsProvisional && !matchIsProvisional || selectedIsProvisional === matchIsProvisional && match.index < selected.match.index) selected = {
1308
+ match,
1309
+ fromTerminator: true
1310
+ };
1311
+ }
1312
+ if (selected != null) return commitLongestMatch(context, selected.match, selected.fromTerminator ? void 0 : optionsTerminatorMatches[0].result);
1313
+ return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1314
+ };
1315
+ const parseSyncBranches = (context) => {
1225
1316
  let bestMatch = null;
1317
+ const optionsTerminatorMatches = [];
1226
1318
  let error = getInitialError(context);
1227
1319
  const activeState = normalizeExclusiveState(context.state);
1228
1320
  for (let i = 0; i < syncParsers.length; i++) {
1229
1321
  const parser = syncParsers[i];
1230
- const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1322
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1323
+ const result = parser.parse(childContext);
1324
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1325
+ optionsTerminatorMatches.push({
1326
+ index: i,
1327
+ result,
1328
+ consumed: 1,
1329
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1330
+ });
1331
+ continue;
1332
+ }
1231
1333
  if (result.success) {
1232
1334
  const consumed = context.buffer.length - result.next.buffer.length;
1233
1335
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1234
1336
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1235
1337
  index: i,
1236
- parser,
1237
1338
  result,
1238
1339
  consumed
1239
1340
  };
1240
1341
  } else if (error.consumed < result.consumed) error = result;
1241
1342
  }
1242
- if (bestMatch && bestMatch.result.success) {
1243
- const mergedExec = require_execution_context.mergeChildExec(context.exec, bestMatch.result.next.exec);
1244
- return {
1245
- success: true,
1246
- next: {
1247
- ...context,
1248
- buffer: bestMatch.result.next.buffer,
1249
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1250
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1251
- ...mergedExec != null ? {
1252
- exec: mergedExec,
1253
- dependencyRegistry: mergedExec.dependencyRegistry
1254
- } : {}
1255
- },
1256
- consumed: bestMatch.result.consumed
1257
- };
1258
- }
1343
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1344
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1345
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1259
1346
  return {
1260
1347
  ...error,
1261
1348
  success: false
1262
1349
  };
1263
1350
  };
1264
- const parseAsync = async (context) => {
1351
+ const parseAsyncBranches = async (context) => {
1265
1352
  let bestMatch = null;
1353
+ const optionsTerminatorMatches = [];
1266
1354
  let error = getInitialError(context);
1267
1355
  const activeState = normalizeExclusiveState(context.state);
1268
1356
  for (let i = 0; i < parsers.length; i++) {
1269
1357
  const parser = parsers[i];
1270
- const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1358
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1359
+ const resultOrPromise = parser.parse(childContext);
1271
1360
  const result = await resultOrPromise;
1361
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1362
+ optionsTerminatorMatches.push({
1363
+ index: i,
1364
+ result,
1365
+ consumed: 1,
1366
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1367
+ });
1368
+ continue;
1369
+ }
1272
1370
  if (result.success) {
1273
1371
  const consumed = context.buffer.length - result.next.buffer.length;
1274
1372
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1275
1373
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1276
1374
  index: i,
1277
- parser,
1278
1375
  result,
1279
1376
  consumed
1280
1377
  };
1281
1378
  } else if (error.consumed < result.consumed) error = result;
1282
1379
  }
1283
- if (bestMatch && bestMatch.result.success) {
1284
- const mergedExec = require_execution_context.mergeChildExec(context.exec, bestMatch.result.next.exec);
1285
- return {
1286
- success: true,
1287
- next: {
1288
- ...context,
1289
- buffer: bestMatch.result.next.buffer,
1290
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1291
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1292
- ...mergedExec != null ? {
1293
- exec: mergedExec,
1294
- dependencyRegistry: mergedExec.dependencyRegistry
1295
- } : {}
1296
- },
1297
- consumed: bestMatch.result.consumed
1298
- };
1299
- }
1380
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1381
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1382
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1300
1383
  return {
1301
1384
  ...error,
1302
1385
  success: false
@@ -1319,7 +1402,7 @@ function longestMatch(...args) {
1319
1402
  return extractExclusivePhase2Seed(parsers, state, exec, combinedMode);
1320
1403
  },
1321
1404
  parse(context) {
1322
- return require_mode_dispatch.dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
1405
+ return require_mode_dispatch.dispatchByMode(combinedMode, () => parseSyncBranches(context), () => parseAsyncBranches(context));
1323
1406
  },
1324
1407
  getSuggestRuntimeNodes(state, path) {
1325
1408
  return getExclusiveSuggestRuntimeNodes(parsers, state, path);
@@ -516,6 +516,35 @@ function createExclusiveState(parentState, index, parser, result) {
516
516
  return annotateFreshArray(parentState, [index, annotatedResult]);
517
517
  }
518
518
  /**
519
+ * Detects a branch result that handled only the global options terminator.
520
+ * Such a result advances the shared parser context, but does not identify
521
+ * which exclusive branch matched.
522
+ * @internal
523
+ */
524
+ function isOptionsTerminatorOnlyResult(context, result) {
525
+ return !context.optionsTerminated && context.buffer[0] === "--" && result.success && result.next.optionsTerminated && result.consumed.length === 1 && result.consumed[0] === "--";
526
+ }
527
+ function isUnselectedBooleanOptionState(state) {
528
+ return state != null && typeof state === "object" && "success" in state && state.success === true && "value" in state && state.value === false;
529
+ }
530
+ function preserveExclusiveStateAfterOptionsTerminator(context, result) {
531
+ const mergedExec = mergeChildExec(context.exec, result.next.exec);
532
+ return {
533
+ success: true,
534
+ next: {
535
+ ...context,
536
+ buffer: result.next.buffer,
537
+ optionsTerminated: true,
538
+ state: context.state,
539
+ ...mergedExec != null ? {
540
+ exec: mergedExec,
541
+ dependencyRegistry: mergedExec.dependencyRegistry
542
+ } : {}
543
+ },
544
+ consumed: result.consumed
545
+ };
546
+ }
547
+ /**
519
548
  * Creates a complete() method shared by or() and longestMatch().
520
549
  * @internal
521
550
  */
@@ -752,9 +781,15 @@ function or(...args) {
752
781
  let zeroConsumedBranch = null;
753
782
  let zeroConsumedCount = 0;
754
783
  let provisionalConsuming = null;
784
+ let optionsTerminatorResult = null;
755
785
  let provisionalAmbiguous = false;
756
786
  for (const [parser, i] of orderedParsers) {
757
787
  const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
788
+ if (isOptionsTerminatorOnlyResult(context, result)) {
789
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
790
+ optionsTerminatorResult ??= result;
791
+ continue;
792
+ }
758
793
  if (result.success && result.consumed.length > 0) {
759
794
  if (result.provisional) {
760
795
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -935,6 +970,7 @@ function or(...args) {
935
970
  }
936
971
  }
937
972
  }
973
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
938
974
  return {
939
975
  ...error,
940
976
  success: false
@@ -948,10 +984,16 @@ function or(...args) {
948
984
  let zeroConsumedBranch = null;
949
985
  let zeroConsumedCount = 0;
950
986
  let provisionalConsuming = null;
987
+ let optionsTerminatorResult = null;
951
988
  let provisionalAmbiguous = false;
952
989
  for (const [parser, i] of orderedParsers) {
953
990
  const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
954
991
  const result = await resultOrPromise;
992
+ if (isOptionsTerminatorOnlyResult(context, result)) {
993
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
994
+ optionsTerminatorResult ??= result;
995
+ continue;
996
+ }
955
997
  if (result.success && result.consumed.length > 0) {
956
998
  if (result.provisional) {
957
999
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1134,6 +1176,7 @@ function or(...args) {
1134
1176
  }
1135
1177
  }
1136
1178
  }
1179
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1137
1180
  return {
1138
1181
  ...error,
1139
1182
  success: false
@@ -1221,82 +1264,122 @@ function longestMatch(...args) {
1221
1264
  return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
1222
1265
  })()
1223
1266
  });
1224
- const parseSync = (context) => {
1267
+ const commitLongestMatch = (context, match, optionsTerminatorResult) => {
1268
+ const selectedResult = optionsTerminatorResult == null ? match.result : {
1269
+ ...match.result,
1270
+ next: {
1271
+ ...match.result.next,
1272
+ buffer: optionsTerminatorResult.next.buffer,
1273
+ optionsTerminated: true
1274
+ },
1275
+ consumed: [...optionsTerminatorResult.consumed, ...match.result.consumed]
1276
+ };
1277
+ const parser = parsers[match.index];
1278
+ const mergedExec = mergeChildExec(context.exec, selectedResult.next.exec);
1279
+ return {
1280
+ success: true,
1281
+ next: {
1282
+ ...context,
1283
+ buffer: selectedResult.next.buffer,
1284
+ optionsTerminated: selectedResult.next.optionsTerminated,
1285
+ state: createExclusiveState(context.state, match.index, parser, selectedResult),
1286
+ ...mergedExec != null ? {
1287
+ exec: mergedExec,
1288
+ dependencyRegistry: mergedExec.dependencyRegistry
1289
+ } : {}
1290
+ },
1291
+ consumed: selectedResult.consumed
1292
+ };
1293
+ };
1294
+ const resolveLongestMatchOptionsTerminator = (context, bestMatch, optionsTerminatorMatches) => {
1295
+ if (optionsTerminatorMatches.length < 1) return null;
1296
+ if (bestMatch != null && bestMatch.consumed > 0) return null;
1297
+ const activeState = normalizeExclusiveState(context.state);
1298
+ if (activeState != null && activeState[1].success && activeState[1].consumed.length > 0) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1299
+ let selected = bestMatch == null ? null : {
1300
+ match: bestMatch,
1301
+ fromTerminator: false
1302
+ };
1303
+ for (const match of optionsTerminatorMatches) {
1304
+ if (!match.selectedAfterTerminator && (extractRequiredUsage(parsers[match.index].usage).length > 0 || isUnselectedBooleanOptionState(match.result.next.state))) continue;
1305
+ const selectedIsProvisional = selected != null && !!selected.match.result.provisional;
1306
+ const matchIsProvisional = !!match.result.provisional;
1307
+ if (selected == null || selectedIsProvisional && !matchIsProvisional || selectedIsProvisional === matchIsProvisional && match.index < selected.match.index) selected = {
1308
+ match,
1309
+ fromTerminator: true
1310
+ };
1311
+ }
1312
+ if (selected != null) return commitLongestMatch(context, selected.match, selected.fromTerminator ? void 0 : optionsTerminatorMatches[0].result);
1313
+ return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1314
+ };
1315
+ const parseSyncBranches = (context) => {
1225
1316
  let bestMatch = null;
1317
+ const optionsTerminatorMatches = [];
1226
1318
  let error = getInitialError(context);
1227
1319
  const activeState = normalizeExclusiveState(context.state);
1228
1320
  for (let i = 0; i < syncParsers.length; i++) {
1229
1321
  const parser = syncParsers[i];
1230
- const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1322
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1323
+ const result = parser.parse(childContext);
1324
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1325
+ optionsTerminatorMatches.push({
1326
+ index: i,
1327
+ result,
1328
+ consumed: 1,
1329
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1330
+ });
1331
+ continue;
1332
+ }
1231
1333
  if (result.success) {
1232
1334
  const consumed = context.buffer.length - result.next.buffer.length;
1233
1335
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1234
1336
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1235
1337
  index: i,
1236
- parser,
1237
1338
  result,
1238
1339
  consumed
1239
1340
  };
1240
1341
  } else if (error.consumed < result.consumed) error = result;
1241
1342
  }
1242
- if (bestMatch && bestMatch.result.success) {
1243
- const mergedExec = mergeChildExec(context.exec, bestMatch.result.next.exec);
1244
- return {
1245
- success: true,
1246
- next: {
1247
- ...context,
1248
- buffer: bestMatch.result.next.buffer,
1249
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1250
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1251
- ...mergedExec != null ? {
1252
- exec: mergedExec,
1253
- dependencyRegistry: mergedExec.dependencyRegistry
1254
- } : {}
1255
- },
1256
- consumed: bestMatch.result.consumed
1257
- };
1258
- }
1343
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1344
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1345
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1259
1346
  return {
1260
1347
  ...error,
1261
1348
  success: false
1262
1349
  };
1263
1350
  };
1264
- const parseAsync = async (context) => {
1351
+ const parseAsyncBranches = async (context) => {
1265
1352
  let bestMatch = null;
1353
+ const optionsTerminatorMatches = [];
1266
1354
  let error = getInitialError(context);
1267
1355
  const activeState = normalizeExclusiveState(context.state);
1268
1356
  for (let i = 0; i < parsers.length; i++) {
1269
1357
  const parser = parsers[i];
1270
- const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1358
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1359
+ const resultOrPromise = parser.parse(childContext);
1271
1360
  const result = await resultOrPromise;
1361
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1362
+ optionsTerminatorMatches.push({
1363
+ index: i,
1364
+ result,
1365
+ consumed: 1,
1366
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1367
+ });
1368
+ continue;
1369
+ }
1272
1370
  if (result.success) {
1273
1371
  const consumed = context.buffer.length - result.next.buffer.length;
1274
1372
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1275
1373
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1276
1374
  index: i,
1277
- parser,
1278
1375
  result,
1279
1376
  consumed
1280
1377
  };
1281
1378
  } else if (error.consumed < result.consumed) error = result;
1282
1379
  }
1283
- if (bestMatch && bestMatch.result.success) {
1284
- const mergedExec = mergeChildExec(context.exec, bestMatch.result.next.exec);
1285
- return {
1286
- success: true,
1287
- next: {
1288
- ...context,
1289
- buffer: bestMatch.result.next.buffer,
1290
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1291
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1292
- ...mergedExec != null ? {
1293
- exec: mergedExec,
1294
- dependencyRegistry: mergedExec.dependencyRegistry
1295
- } : {}
1296
- },
1297
- consumed: bestMatch.result.consumed
1298
- };
1299
- }
1380
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1381
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1382
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1300
1383
  return {
1301
1384
  ...error,
1302
1385
  success: false
@@ -1319,7 +1402,7 @@ function longestMatch(...args) {
1319
1402
  return extractExclusivePhase2Seed(parsers, state, exec, combinedMode);
1320
1403
  },
1321
1404
  parse(context) {
1322
- return dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
1405
+ return dispatchByMode(combinedMode, () => parseSyncBranches(context), () => parseAsyncBranches(context));
1323
1406
  },
1324
1407
  getSuggestRuntimeNodes(state, path) {
1325
1408
  return getExclusiveSuggestRuntimeNodes(parsers, state, path);
@@ -237,7 +237,7 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
237
237
  * Internal sync helper for option suggest functionality.
238
238
  * @internal
239
239
  */
240
- function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix) {
240
+ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
241
241
  if (hidden) return;
242
242
  const equalsIndex = prefix.indexOf("=");
243
243
  if (equalsIndex >= 0) {
@@ -265,7 +265,8 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
265
265
  if (prefix === "-" && optionName$1.length !== 2) continue;
266
266
  yield {
267
267
  kind: "literal",
268
- text: optionName$1
268
+ text: optionName$1,
269
+ ...description && { description }
269
270
  };
270
271
  }
271
272
  }
@@ -321,7 +322,7 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
321
322
  * Internal async helper for option suggest functionality.
322
323
  * @internal
323
324
  */
324
- async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context, prefix) {
325
+ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
325
326
  if (hidden) return;
326
327
  const equalsIndex = prefix.indexOf("=");
327
328
  if (equalsIndex >= 0) {
@@ -349,7 +350,8 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
349
350
  if (prefix === "-" && optionName$1.length !== 2) continue;
350
351
  yield {
351
352
  kind: "literal",
352
- text: optionName$1
353
+ text: optionName$1,
354
+ ...description && { description }
353
355
  };
354
356
  }
355
357
  }
@@ -615,8 +617,8 @@ function option(...args) {
615
617
  return require_mode_dispatch.dispatchByMode(mode, completeSync, completeAsync);
616
618
  },
617
619
  suggest(context, prefix) {
618
- if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), context, prefix);
619
- return suggestOptionSync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), context, prefix);
620
+ if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), options.description, context, prefix);
621
+ return suggestOptionSync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), options.description, context, prefix);
620
622
  },
621
623
  getDocFragments(_state, defaultValue) {
622
624
  if (require_usage.isDocHidden(options.hidden)) return {
@@ -893,7 +895,8 @@ function flag(...args) {
893
895
  if (prefix === "-" && optionName$1.length !== 2) continue;
894
896
  suggestions.push({
895
897
  kind: "literal",
896
- text: optionName$1
898
+ text: optionName$1,
899
+ ...options.description && { description: options.description }
897
900
  });
898
901
  }
899
902
  }
@@ -1157,11 +1160,14 @@ function* suggestCommandSync(context, prefix, name, parser, options) {
1157
1160
  if (require_usage.isSuggestionHidden(options.hidden)) return;
1158
1161
  const state = normalizeCommandState(context.state);
1159
1162
  if (state === void 0) {
1160
- if (name.startsWith(prefix)) yield {
1161
- kind: "literal",
1162
- text: name,
1163
- ...options.description && { description: options.description }
1164
- };
1163
+ if (name.startsWith(prefix)) {
1164
+ const description = options.brief ?? options.description;
1165
+ yield {
1166
+ kind: "literal",
1167
+ text: name,
1168
+ ...description && { description }
1169
+ };
1170
+ }
1165
1171
  } else if (state[0] === "matched") yield* parser.suggest(require_execution_context.withChildContext(context, name, getCommandChildState(context.state, parser.initialState, parser), parser.usage), prefix);
1166
1172
  else if (state[0] === "parsing") yield* parser.suggest(require_execution_context.withChildContext(context, name, getCommandChildState(context.state, state[1], parser), parser.usage), prefix);
1167
1173
  }
@@ -1169,11 +1175,14 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
1169
1175
  if (require_usage.isSuggestionHidden(options.hidden)) return;
1170
1176
  const state = normalizeCommandState(context.state);
1171
1177
  if (state === void 0) {
1172
- if (name.startsWith(prefix)) yield {
1173
- kind: "literal",
1174
- text: name,
1175
- ...options.description && { description: options.description }
1176
- };
1178
+ if (name.startsWith(prefix)) {
1179
+ const description = options.brief ?? options.description;
1180
+ yield {
1181
+ kind: "literal",
1182
+ text: name,
1183
+ ...description && { description }
1184
+ };
1185
+ }
1177
1186
  } else if (state[0] === "matched") {
1178
1187
  const suggestions = parser.suggest(require_execution_context.withChildContext(context, name, getCommandChildState(context.state, parser.initialState, parser), parser.usage), prefix);
1179
1188
  for await (const s of suggestions) yield s;
@@ -237,7 +237,7 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
237
237
  * Internal sync helper for option suggest functionality.
238
238
  * @internal
239
239
  */
240
- function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix) {
240
+ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
241
241
  if (hidden) return;
242
242
  const equalsIndex = prefix.indexOf("=");
243
243
  if (equalsIndex >= 0) {
@@ -265,7 +265,8 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
265
265
  if (prefix === "-" && optionName$1.length !== 2) continue;
266
266
  yield {
267
267
  kind: "literal",
268
- text: optionName$1
268
+ text: optionName$1,
269
+ ...description && { description }
269
270
  };
270
271
  }
271
272
  }
@@ -321,7 +322,7 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
321
322
  * Internal async helper for option suggest functionality.
322
323
  * @internal
323
324
  */
324
- async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context, prefix) {
325
+ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
325
326
  if (hidden) return;
326
327
  const equalsIndex = prefix.indexOf("=");
327
328
  if (equalsIndex >= 0) {
@@ -349,7 +350,8 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
349
350
  if (prefix === "-" && optionName$1.length !== 2) continue;
350
351
  yield {
351
352
  kind: "literal",
352
- text: optionName$1
353
+ text: optionName$1,
354
+ ...description && { description }
353
355
  };
354
356
  }
355
357
  }
@@ -615,8 +617,8 @@ function option(...args) {
615
617
  return dispatchByMode(mode, completeSync, completeAsync);
616
618
  },
617
619
  suggest(context, prefix) {
618
- if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), context, prefix);
619
- return suggestOptionSync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), context, prefix);
620
+ if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), options.description, context, prefix);
621
+ return suggestOptionSync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), options.description, context, prefix);
620
622
  },
621
623
  getDocFragments(_state, defaultValue) {
622
624
  if (isDocHidden(options.hidden)) return {
@@ -893,7 +895,8 @@ function flag(...args) {
893
895
  if (prefix === "-" && optionName$1.length !== 2) continue;
894
896
  suggestions.push({
895
897
  kind: "literal",
896
- text: optionName$1
898
+ text: optionName$1,
899
+ ...options.description && { description: options.description }
897
900
  });
898
901
  }
899
902
  }
@@ -1157,11 +1160,14 @@ function* suggestCommandSync(context, prefix, name, parser, options) {
1157
1160
  if (isSuggestionHidden(options.hidden)) return;
1158
1161
  const state = normalizeCommandState(context.state);
1159
1162
  if (state === void 0) {
1160
- if (name.startsWith(prefix)) yield {
1161
- kind: "literal",
1162
- text: name,
1163
- ...options.description && { description: options.description }
1164
- };
1163
+ if (name.startsWith(prefix)) {
1164
+ const description = options.brief ?? options.description;
1165
+ yield {
1166
+ kind: "literal",
1167
+ text: name,
1168
+ ...description && { description }
1169
+ };
1170
+ }
1165
1171
  } else if (state[0] === "matched") yield* parser.suggest(withChildContext(context, name, getCommandChildState(context.state, parser.initialState, parser), parser.usage), prefix);
1166
1172
  else if (state[0] === "parsing") yield* parser.suggest(withChildContext(context, name, getCommandChildState(context.state, state[1], parser), parser.usage), prefix);
1167
1173
  }
@@ -1169,11 +1175,14 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
1169
1175
  if (isSuggestionHidden(options.hidden)) return;
1170
1176
  const state = normalizeCommandState(context.state);
1171
1177
  if (state === void 0) {
1172
- if (name.startsWith(prefix)) yield {
1173
- kind: "literal",
1174
- text: name,
1175
- ...options.description && { description: options.description }
1176
- };
1178
+ if (name.startsWith(prefix)) {
1179
+ const description = options.brief ?? options.description;
1180
+ yield {
1181
+ kind: "literal",
1182
+ text: name,
1183
+ ...description && { description }
1184
+ };
1185
+ }
1177
1186
  } else if (state[0] === "matched") {
1178
1187
  const suggestions = parser.suggest(withChildContext(context, name, getCommandChildState(context.state, parser.initialState, parser), parser.usage), prefix);
1179
1188
  for await (const s of suggestions) yield s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",