@optique/core 1.0.0-dev.908 → 1.0.0

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.
Files changed (109) hide show
  1. package/dist/annotation-state.cjs +425 -0
  2. package/dist/annotation-state.d.cts +24 -0
  3. package/dist/annotation-state.d.ts +24 -0
  4. package/dist/annotation-state.js +414 -0
  5. package/dist/annotations.cjs +2 -248
  6. package/dist/annotations.d.cts +2 -137
  7. package/dist/annotations.d.ts +2 -137
  8. package/dist/annotations.js +2 -238
  9. package/dist/completion.cjs +611 -100
  10. package/dist/completion.d.cts +1 -1
  11. package/dist/completion.d.ts +1 -1
  12. package/dist/completion.js +611 -100
  13. package/dist/constructs.cjs +3338 -827
  14. package/dist/constructs.d.cts +48 -7
  15. package/dist/constructs.d.ts +48 -7
  16. package/dist/constructs.js +3338 -827
  17. package/dist/context.cjs +0 -23
  18. package/dist/context.d.cts +119 -53
  19. package/dist/context.d.ts +119 -53
  20. package/dist/context.js +0 -22
  21. package/dist/dependency-metadata.cjs +139 -0
  22. package/dist/dependency-metadata.d.cts +112 -0
  23. package/dist/dependency-metadata.d.ts +112 -0
  24. package/dist/dependency-metadata.js +138 -0
  25. package/dist/dependency-runtime.cjs +698 -0
  26. package/dist/dependency-runtime.d.cts +149 -0
  27. package/dist/dependency-runtime.d.ts +149 -0
  28. package/dist/dependency-runtime.js +687 -0
  29. package/dist/dependency.cjs +7 -928
  30. package/dist/dependency.d.cts +2 -794
  31. package/dist/dependency.d.ts +2 -794
  32. package/dist/dependency.js +2 -899
  33. package/dist/displaywidth.cjs +44 -0
  34. package/dist/displaywidth.js +43 -0
  35. package/dist/doc.cjs +285 -23
  36. package/dist/doc.d.cts +57 -2
  37. package/dist/doc.d.ts +57 -2
  38. package/dist/doc.js +283 -25
  39. package/dist/execution-context.cjs +56 -0
  40. package/dist/execution-context.js +53 -0
  41. package/dist/extension.cjs +87 -0
  42. package/dist/extension.d.cts +97 -0
  43. package/dist/extension.d.ts +97 -0
  44. package/dist/extension.js +76 -0
  45. package/dist/facade.cjs +718 -523
  46. package/dist/facade.d.cts +87 -18
  47. package/dist/facade.d.ts +87 -18
  48. package/dist/facade.js +718 -523
  49. package/dist/index.cjs +14 -29
  50. package/dist/index.d.cts +10 -10
  51. package/dist/index.d.ts +10 -10
  52. package/dist/index.js +7 -7
  53. package/dist/input-trace.cjs +56 -0
  54. package/dist/input-trace.d.cts +77 -0
  55. package/dist/input-trace.d.ts +77 -0
  56. package/dist/input-trace.js +55 -0
  57. package/dist/internal/annotations.cjs +316 -0
  58. package/dist/internal/annotations.d.cts +140 -0
  59. package/dist/internal/annotations.d.ts +140 -0
  60. package/dist/internal/annotations.js +306 -0
  61. package/dist/internal/dependency.cjs +984 -0
  62. package/dist/internal/dependency.d.cts +539 -0
  63. package/dist/internal/dependency.d.ts +539 -0
  64. package/dist/internal/dependency.js +964 -0
  65. package/dist/{mode-dispatch.cjs → internal/mode-dispatch.cjs} +1 -3
  66. package/dist/{mode-dispatch.d.cts → internal/mode-dispatch.d.cts} +3 -7
  67. package/dist/{mode-dispatch.d.ts → internal/mode-dispatch.d.ts} +3 -7
  68. package/dist/{mode-dispatch.js → internal/mode-dispatch.js} +1 -3
  69. package/dist/internal/parser.cjs +728 -0
  70. package/dist/internal/parser.d.cts +947 -0
  71. package/dist/internal/parser.d.ts +947 -0
  72. package/dist/internal/parser.js +711 -0
  73. package/dist/message.cjs +84 -26
  74. package/dist/message.d.cts +49 -9
  75. package/dist/message.d.ts +49 -9
  76. package/dist/message.js +84 -27
  77. package/dist/modifiers.cjs +1023 -240
  78. package/dist/modifiers.d.cts +42 -1
  79. package/dist/modifiers.d.ts +42 -1
  80. package/dist/modifiers.js +1023 -240
  81. package/dist/parser.cjs +11 -463
  82. package/dist/parser.d.cts +3 -537
  83. package/dist/parser.d.ts +3 -537
  84. package/dist/parser.js +2 -433
  85. package/dist/phase2-seed.cjs +59 -0
  86. package/dist/phase2-seed.js +56 -0
  87. package/dist/primitives.cjs +557 -208
  88. package/dist/primitives.d.cts +10 -14
  89. package/dist/primitives.d.ts +10 -14
  90. package/dist/primitives.js +557 -208
  91. package/dist/program.cjs +5 -1
  92. package/dist/program.d.cts +5 -3
  93. package/dist/program.d.ts +5 -3
  94. package/dist/program.js +6 -1
  95. package/dist/suggestion.cjs +22 -8
  96. package/dist/suggestion.js +22 -8
  97. package/dist/usage-internals.cjs +3 -2
  98. package/dist/usage-internals.js +4 -2
  99. package/dist/usage.cjs +195 -40
  100. package/dist/usage.d.cts +92 -11
  101. package/dist/usage.d.ts +92 -11
  102. package/dist/usage.js +194 -41
  103. package/dist/validate.cjs +170 -0
  104. package/dist/validate.js +164 -0
  105. package/dist/valueparser.cjs +1278 -191
  106. package/dist/valueparser.d.cts +330 -20
  107. package/dist/valueparser.d.ts +330 -20
  108. package/dist/valueparser.js +1277 -192
  109. package/package.json +9 -9
package/dist/program.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ const require_validate = require('./validate.cjs');
1
2
 
2
3
  //#region src/program.ts
3
4
  /**
@@ -11,6 +12,8 @@
11
12
  * @template T - The type of value produced by the parser.
12
13
  * @param program - The program definition with parser and metadata.
13
14
  * @returns The same program object with inferred types.
15
+ * @throws {TypeError} If `program.metadata.name` is not a string, is empty,
16
+ * is whitespace-only, or contains control characters.
14
17
  *
15
18
  * @example
16
19
  * ```typescript
@@ -34,9 +37,10 @@
34
37
  * // Program<"sync", { readonly name: string }>
35
38
  * ```
36
39
  *
37
- * @since 0.11.0
40
+ * @since 1.0.0
38
41
  */
39
42
  function defineProgram(program) {
43
+ require_validate.validateProgramName(program.metadata.name);
40
44
  return program;
41
45
  }
42
46
 
@@ -1,5 +1,5 @@
1
1
  import { Message } from "./message.cjs";
2
- import { Mode, Parser } from "./parser.cjs";
2
+ import { Mode, Parser } from "./internal/parser.cjs";
3
3
 
4
4
  //#region src/program.d.ts
5
5
 
@@ -71,7 +71,7 @@ interface ProgramMetadata {
71
71
  * };
72
72
  * ```
73
73
  *
74
- * @since 0.11.0
74
+ * @since 1.0.0
75
75
  */
76
76
  interface Program<M extends Mode, T> {
77
77
  /**
@@ -94,6 +94,8 @@ interface Program<M extends Mode, T> {
94
94
  * @template T - The type of value produced by the parser.
95
95
  * @param program - The program definition with parser and metadata.
96
96
  * @returns The same program object with inferred types.
97
+ * @throws {TypeError} If `program.metadata.name` is not a string, is empty,
98
+ * is whitespace-only, or contains control characters.
97
99
  *
98
100
  * @example
99
101
  * ```typescript
@@ -117,7 +119,7 @@ interface Program<M extends Mode, T> {
117
119
  * // Program<"sync", { readonly name: string }>
118
120
  * ```
119
121
  *
120
- * @since 0.11.0
122
+ * @since 1.0.0
121
123
  */
122
124
  declare function defineProgram<M extends Mode, T>(program: Program<M, T>): Program<M, T>;
123
125
  //#endregion
package/dist/program.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Message } from "./message.js";
2
- import { Mode, Parser } from "./parser.js";
2
+ import { Mode, Parser } from "./internal/parser.js";
3
3
 
4
4
  //#region src/program.d.ts
5
5
 
@@ -71,7 +71,7 @@ interface ProgramMetadata {
71
71
  * };
72
72
  * ```
73
73
  *
74
- * @since 0.11.0
74
+ * @since 1.0.0
75
75
  */
76
76
  interface Program<M extends Mode, T> {
77
77
  /**
@@ -94,6 +94,8 @@ interface Program<M extends Mode, T> {
94
94
  * @template T - The type of value produced by the parser.
95
95
  * @param program - The program definition with parser and metadata.
96
96
  * @returns The same program object with inferred types.
97
+ * @throws {TypeError} If `program.metadata.name` is not a string, is empty,
98
+ * is whitespace-only, or contains control characters.
97
99
  *
98
100
  * @example
99
101
  * ```typescript
@@ -117,7 +119,7 @@ interface Program<M extends Mode, T> {
117
119
  * // Program<"sync", { readonly name: string }>
118
120
  * ```
119
121
  *
120
- * @since 0.11.0
122
+ * @since 1.0.0
121
123
  */
122
124
  declare function defineProgram<M extends Mode, T>(program: Program<M, T>): Program<M, T>;
123
125
  //#endregion
package/dist/program.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { validateProgramName } from "./validate.js";
2
+
1
3
  //#region src/program.ts
2
4
  /**
3
5
  * Defines a CLI program with a parser and metadata.
@@ -10,6 +12,8 @@
10
12
  * @template T - The type of value produced by the parser.
11
13
  * @param program - The program definition with parser and metadata.
12
14
  * @returns The same program object with inferred types.
15
+ * @throws {TypeError} If `program.metadata.name` is not a string, is empty,
16
+ * is whitespace-only, or contains control characters.
13
17
  *
14
18
  * @example
15
19
  * ```typescript
@@ -33,9 +37,10 @@
33
37
  * // Program<"sync", { readonly name: string }>
34
38
  * ```
35
39
  *
36
- * @since 0.11.0
40
+ * @since 1.0.0
37
41
  */
38
42
  function defineProgram(program) {
43
+ validateProgramName(program.metadata.name);
39
44
  return program;
40
45
  }
41
46
 
@@ -81,8 +81,11 @@ function findSimilar(input, candidates, options = {}) {
81
81
  if (input.length === 0) return [];
82
82
  const normalizedInput = caseSensitive ? input : input.toLowerCase();
83
83
  const matches = [];
84
+ const seen = /* @__PURE__ */ new Set();
84
85
  for (const candidate of candidates) {
85
86
  const normalizedCandidate = caseSensitive ? candidate : candidate.toLowerCase();
87
+ if (seen.has(candidate)) continue;
88
+ seen.add(candidate);
86
89
  const distance = levenshteinDistance(normalizedInput, normalizedCandidate);
87
90
  if (distance === 0) return [candidate];
88
91
  const distanceRatio = distance / input.length;
@@ -192,7 +195,7 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
192
195
  */
193
196
  function getSuggestionKey(suggestion) {
194
197
  if (suggestion.kind === "literal") return suggestion.text;
195
- return `__FILE__:${suggestion.type}:${suggestion.extensions?.join(",") ?? ""}:${suggestion.pattern ?? ""}`;
198
+ return `__FILE__:${suggestion.type}:${suggestion.extensions?.toSorted().join(",") ?? ""}:${suggestion.pattern ?? ""}`;
196
199
  }
197
200
  /**
198
201
  * Removes duplicate suggestions from an array while preserving order.
@@ -201,7 +204,11 @@ function getSuggestionKey(suggestion) {
201
204
  * - Literal suggestions: same text
202
205
  * - File suggestions: same type, extensions, and pattern
203
206
  *
204
- * The first occurrence of each unique suggestion is kept.
207
+ * The first occurrence of each unique suggestion is kept. For file
208
+ * suggestions, `includeHidden` is merged across duplicates: if any
209
+ * duplicate has `includeHidden: true`, the kept suggestion is upgraded
210
+ * to `includeHidden: true` because it is a superset of the non-hidden
211
+ * variant.
205
212
  *
206
213
  * @param suggestions Array of suggestions that may contain duplicates
207
214
  * @returns A new array with duplicates removed, preserving order of first occurrences
@@ -220,13 +227,20 @@ function getSuggestionKey(suggestion) {
220
227
  * @since 0.9.0
221
228
  */
222
229
  function deduplicateSuggestions(suggestions) {
223
- const seen = /* @__PURE__ */ new Set();
224
- return suggestions.filter((suggestion) => {
230
+ const entries = /* @__PURE__ */ new Map();
231
+ const order = [];
232
+ for (const suggestion of suggestions) {
225
233
  const key = getSuggestionKey(suggestion);
226
- if (seen.has(key)) return false;
227
- seen.add(key);
228
- return true;
229
- });
234
+ const existing = entries.get(key);
235
+ if (existing == null) {
236
+ entries.set(key, suggestion);
237
+ order.push(key);
238
+ } else if (suggestion.kind === "file" && existing.kind === "file" && suggestion.includeHidden === true && existing.includeHidden !== true) entries.set(key, {
239
+ ...existing,
240
+ includeHidden: true
241
+ });
242
+ }
243
+ return order.map((key) => entries.get(key));
230
244
  }
231
245
 
232
246
  //#endregion
@@ -81,8 +81,11 @@ function findSimilar(input, candidates, options = {}) {
81
81
  if (input.length === 0) return [];
82
82
  const normalizedInput = caseSensitive ? input : input.toLowerCase();
83
83
  const matches = [];
84
+ const seen = /* @__PURE__ */ new Set();
84
85
  for (const candidate of candidates) {
85
86
  const normalizedCandidate = caseSensitive ? candidate : candidate.toLowerCase();
87
+ if (seen.has(candidate)) continue;
88
+ seen.add(candidate);
86
89
  const distance = levenshteinDistance(normalizedInput, normalizedCandidate);
87
90
  if (distance === 0) return [candidate];
88
91
  const distanceRatio = distance / input.length;
@@ -192,7 +195,7 @@ function createErrorWithSuggestions(baseError, invalidInput, usage, type = "both
192
195
  */
193
196
  function getSuggestionKey(suggestion) {
194
197
  if (suggestion.kind === "literal") return suggestion.text;
195
- return `__FILE__:${suggestion.type}:${suggestion.extensions?.join(",") ?? ""}:${suggestion.pattern ?? ""}`;
198
+ return `__FILE__:${suggestion.type}:${suggestion.extensions?.toSorted().join(",") ?? ""}:${suggestion.pattern ?? ""}`;
196
199
  }
197
200
  /**
198
201
  * Removes duplicate suggestions from an array while preserving order.
@@ -201,7 +204,11 @@ function getSuggestionKey(suggestion) {
201
204
  * - Literal suggestions: same text
202
205
  * - File suggestions: same type, extensions, and pattern
203
206
  *
204
- * The first occurrence of each unique suggestion is kept.
207
+ * The first occurrence of each unique suggestion is kept. For file
208
+ * suggestions, `includeHidden` is merged across duplicates: if any
209
+ * duplicate has `includeHidden: true`, the kept suggestion is upgraded
210
+ * to `includeHidden: true` because it is a superset of the non-hidden
211
+ * variant.
205
212
  *
206
213
  * @param suggestions Array of suggestions that may contain duplicates
207
214
  * @returns A new array with duplicates removed, preserving order of first occurrences
@@ -220,13 +227,20 @@ function getSuggestionKey(suggestion) {
220
227
  * @since 0.9.0
221
228
  */
222
229
  function deduplicateSuggestions(suggestions) {
223
- const seen = /* @__PURE__ */ new Set();
224
- return suggestions.filter((suggestion) => {
230
+ const entries = /* @__PURE__ */ new Map();
231
+ const order = [];
232
+ for (const suggestion of suggestions) {
225
233
  const key = getSuggestionKey(suggestion);
226
- if (seen.has(key)) return false;
227
- seen.add(key);
228
- return true;
229
- });
234
+ const existing = entries.get(key);
235
+ if (existing == null) {
236
+ entries.set(key, suggestion);
237
+ order.push(key);
238
+ } else if (suggestion.kind === "file" && existing.kind === "file" && suggestion.includeHidden === true && existing.includeHidden !== true) entries.set(key, {
239
+ ...existing,
240
+ includeHidden: true
241
+ });
242
+ }
243
+ return order.map((key) => entries.get(key));
230
244
  }
231
245
 
232
246
  //#endregion
@@ -1,3 +1,4 @@
1
+ const require_usage = require('./usage.cjs');
1
2
 
2
3
  //#region src/usage-internals.ts
3
4
  /**
@@ -19,11 +20,11 @@ function collectLeadingCandidates(terms, optionNames, commandNames) {
19
20
  if (!terms || !Array.isArray(terms)) return true;
20
21
  for (const term of terms) {
21
22
  if (term.type === "option") {
22
- for (const name of term.names) optionNames.add(name);
23
+ if (!require_usage.isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
23
24
  return false;
24
25
  }
25
26
  if (term.type === "command") {
26
- commandNames.add(term.name);
27
+ if (!require_usage.isSuggestionHidden(term.hidden)) commandNames.add(term.name);
27
28
  return false;
28
29
  }
29
30
  if (term.type === "argument") return false;
@@ -1,3 +1,5 @@
1
+ import { isSuggestionHidden } from "./usage.js";
2
+
1
3
  //#region src/usage-internals.ts
2
4
  /**
3
5
  * Collects option names and command names that are valid as the *immediate*
@@ -18,11 +20,11 @@ function collectLeadingCandidates(terms, optionNames, commandNames) {
18
20
  if (!terms || !Array.isArray(terms)) return true;
19
21
  for (const term of terms) {
20
22
  if (term.type === "option") {
21
- for (const name of term.names) optionNames.add(name);
23
+ if (!isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
22
24
  return false;
23
25
  }
24
26
  if (term.type === "command") {
25
- commandNames.add(term.name);
27
+ if (!isSuggestionHidden(term.hidden)) commandNames.add(term.name);
26
28
  return false;
27
29
  }
28
30
  if (term.type === "argument") return false;