@optique/man 0.10.7-dev.485 → 1.0.0-dev.1109

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/README.md CHANGED
@@ -26,12 +26,18 @@ Quick start
26
26
 
27
27
  ~~~~ typescript
28
28
  import { generateManPage } from "@optique/man";
29
- import { object, option, argument } from "@optique/core/primitives";
29
+ import { object } from "@optique/core/constructs";
30
+ import { option } from "@optique/core/primitives";
30
31
  import { string, integer } from "@optique/core/valueparser";
32
+ import { message } from "@optique/core/message";
31
33
 
32
34
  const parser = object({
33
- port: option("-p", "--port", integer(), { description: "Port to listen on" }),
34
- host: option("-h", "--host", string(), { description: "Host to bind to" }),
35
+ port: option("-p", "--port", integer(), {
36
+ description: message`Port to listen on`,
37
+ }),
38
+ host: option("-h", "--host", string(), {
39
+ description: message`Host to bind to`,
40
+ }),
35
41
  });
36
42
 
37
43
  const manPage = generateManPage(parser, {
@@ -66,8 +72,11 @@ formatMessageAsRoff(msg); // "Use \\fB\\-\\-help\\fR for more info."
66
72
 
67
73
  ~~~~ typescript
68
74
  import { formatDocPageAsMan } from "@optique/man/man";
75
+ import { message } from "@optique/core/message";
69
76
  import type { DocPage } from "@optique/core/doc";
70
77
 
78
+ declare const docPage: DocPage;
79
+
71
80
  const manPage = formatDocPageAsMan(docPage, {
72
81
  name: "myapp",
73
82
  section: 1,
package/dist/cli.cjs CHANGED
@@ -1,23 +1,23 @@
1
1
  #!/usr/bin/env node
2
- const require_generator = require('./generator-zoVk04OH.cjs');
3
- require('./roff-EpcecLXU.cjs');
4
- require('./man-DGnow1Jr.cjs');
5
- const __optique_core_constructs = require_generator.__toESM(require("@optique/core/constructs"));
6
- const __optique_core_primitives = require_generator.__toESM(require("@optique/core/primitives"));
7
- const __optique_core_valueparser = require_generator.__toESM(require("@optique/core/valueparser"));
8
- const __optique_core_modifiers = require_generator.__toESM(require("@optique/core/modifiers"));
9
- const __optique_core_message = require_generator.__toESM(require("@optique/core/message"));
10
- const __optique_core_program = require_generator.__toESM(require("@optique/core/program"));
11
- const __optique_run = require_generator.__toESM(require("@optique/run"));
12
- const node_fs = require_generator.__toESM(require("node:fs"));
13
- const node_fs_promises = require_generator.__toESM(require("node:fs/promises"));
14
- const node_path = require_generator.__toESM(require("node:path"));
15
- const node_process = require_generator.__toESM(require("node:process"));
16
- const node_url = require_generator.__toESM(require("node:url"));
2
+ const require_man = require('./man-CkvscTlM.cjs');
3
+ require('./roff-DJ-LkRXl.cjs');
4
+ const require_generator = require('./generator-RyVL5b_V.cjs');
5
+ const __optique_core_constructs = require_man.__toESM(require("@optique/core/constructs"));
6
+ const __optique_core_primitives = require_man.__toESM(require("@optique/core/primitives"));
7
+ const __optique_core_valueparser = require_man.__toESM(require("@optique/core/valueparser"));
8
+ const __optique_core_modifiers = require_man.__toESM(require("@optique/core/modifiers"));
9
+ const __optique_core_message = require_man.__toESM(require("@optique/core/message"));
10
+ const __optique_core_program = require_man.__toESM(require("@optique/core/program"));
11
+ const __optique_run = require_man.__toESM(require("@optique/run"));
12
+ const node_fs = require_man.__toESM(require("node:fs"));
13
+ const node_fs_promises = require_man.__toESM(require("node:fs/promises"));
14
+ const node_path = require_man.__toESM(require("node:path"));
15
+ const node_process = require_man.__toESM(require("node:process"));
16
+ const node_url = require_man.__toESM(require("node:url"));
17
17
 
18
18
  //#region deno.json
19
19
  var name = "@optique/man";
20
- var version = "0.10.7-dev.485+0a30b635";
20
+ var version = "1.0.0-dev.1109+fa132665";
21
21
  var license = "MIT";
22
22
  var exports$1 = {
23
23
  ".": "./src/index.ts",
@@ -56,6 +56,7 @@ var deno_default = {
56
56
 
57
57
  //#endregion
58
58
  //#region src/cli.ts
59
+ const jsxTsxPattern = /\.[mc]?[jt]sx$/;
59
60
  const EXIT_FILE_NOT_FOUND = 1;
60
61
  const EXIT_EXPORT_NOT_FOUND = 2;
61
62
  const EXIT_NOT_PROGRAM_OR_PARSER = 3;
@@ -89,15 +90,31 @@ a ${(0, __optique_core_message.metavar)("PROGRAM")} (from ${(0, __optique_core_m
89
90
  a ${(0, __optique_core_message.metavar)("PARSER")}. If not specified, the default export is used.` }), "default"),
90
91
  output: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("-o", "--output", (0, __optique_core_valueparser.string)({ metavar: "PATH" }), { description: __optique_core_message.message`Output file path. If not specified, the man page
91
92
  is written to stdout.` })),
92
- name: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--name", (0, __optique_core_valueparser.string)({ metavar: "NAME" }), { description: __optique_core_message.message`Program name to use in the man page header.
93
+ name: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--name", (0, __optique_core_valueparser.string)({
94
+ metavar: "NAME",
95
+ pattern: /.+/,
96
+ errors: { patternMismatch: __optique_core_message.message`Program name must not be empty.` }
97
+ }), { description: __optique_core_message.message`Program name to use in the man page header.
93
98
  If not specified, inferred from the ${(0, __optique_core_message.metavar)("PROGRAM")} metadata
94
99
  or the input file name.` })),
95
- date: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--date", (0, __optique_core_valueparser.string)({ metavar: "DATE" }), { description: __optique_core_message.message`Date to display in the man page footer.
100
+ date: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--date", (0, __optique_core_valueparser.string)({
101
+ metavar: "DATE",
102
+ pattern: /.+/,
103
+ errors: { patternMismatch: __optique_core_message.message`Date must not be empty.` }
104
+ }), { description: __optique_core_message.message`Date to display in the man page footer.
96
105
  Defaults to the current date.` })),
97
- versionString: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--version-string", (0, __optique_core_valueparser.string)({ metavar: "VERSION" }), { description: __optique_core_message.message`Version string for the man page footer
106
+ versionString: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--version-string", (0, __optique_core_valueparser.string)({
107
+ metavar: "VERSION",
108
+ pattern: /.+/,
109
+ errors: { patternMismatch: __optique_core_message.message`Version string must not be empty.` }
110
+ }), { description: __optique_core_message.message`Version string for the man page footer
98
111
  (e.g., ${"MyApp 1.0.0"}). Overrides the version from
99
112
  ${(0, __optique_core_message.metavar)("PROGRAM")} metadata if provided.` })),
100
- manual: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--manual", (0, __optique_core_valueparser.string)({ metavar: "TITLE" }), { description: __optique_core_message.message`Manual name for the man page header
113
+ manual: (0, __optique_core_modifiers.optional)((0, __optique_core_primitives.option)("--manual", (0, __optique_core_valueparser.string)({
114
+ metavar: "TITLE",
115
+ pattern: /.+/,
116
+ errors: { patternMismatch: __optique_core_message.message`Manual name must not be empty.` }
117
+ }), { description: __optique_core_message.message`Manual name for the man page header
101
118
  (e.g., ${"User Commands"}).` }))
102
119
  }),
103
120
  metadata: {
@@ -187,7 +204,7 @@ an Optique parser (e.g., from ${(0, __optique_core_message.commandLine)("object(
187
204
  ${(0, __optique_core_message.commandLine)("command()")}, etc.).`, { exitCode: EXIT_NOT_PROGRAM_OR_PARSER });
188
205
  }
189
206
  /**
190
- * Error handler for missing tsx.
207
+ * Error handler for missing tsx for TypeScript files.
191
208
  */
192
209
  function tsxRequiredError(filePath) {
193
210
  const version$1 = getNodeMajorMinor();
@@ -200,6 +217,22 @@ Install tsx as a dev dependency:
200
217
 
201
218
  Or upgrade to Node.js 25.2.0 or later, which supports TypeScript natively.
202
219
 
220
+ Alternatively, use a pre-compiled JavaScript file instead.`, { exitCode: EXIT_TSX_REQUIRED });
221
+ }
222
+ /**
223
+ * Error handler for missing tsx for JSX/TSX files.
224
+ */
225
+ function jsxLoaderRequiredError(filePath) {
226
+ const version$1 = getNodeMajorMinor();
227
+ const versionStr = version$1 ? `${version$1[0]}.${version$1[1]}` : "unknown";
228
+ const isTsx = /\.[mc]?tsx$/.test(filePath);
229
+ const fileKind = isTsx ? "TSX" : "JSX";
230
+ (0, __optique_run.printError)(__optique_core_message.message`${fileKind} file ${filePath} cannot be loaded on Node.js ${versionStr}.
231
+
232
+ Install tsx as a dev dependency:
233
+
234
+ ${(0, __optique_core_message.commandLine)("npm install -D tsx")}
235
+
203
236
  Alternatively, use a pre-compiled JavaScript file instead.`, { exitCode: EXIT_TSX_REQUIRED });
204
237
  }
205
238
  /**
@@ -218,34 +251,100 @@ Make sure you have write permission and the parent directory exists.`, { exitCod
218
251
  }
219
252
  /**
220
253
  * Imports a module from the given file path.
221
- * Handles TypeScript files on Node.js by using tsx if needed.
254
+ * Handles TypeScript and JSX files on Node.js by using tsx if needed.
255
+ * @param filePath The path to the module file.
256
+ * @returns The imported module's exports.
257
+ * @throws If the module fails to import for reasons other than a missing
258
+ * tsx loader (which causes the process to exit instead).
222
259
  */
223
260
  async function importModule(filePath) {
224
261
  const absolutePath = (0, node_path.resolve)(filePath);
225
262
  if (!(0, node_fs.existsSync)(absolutePath)) fileNotFoundError(filePath);
226
- const isTypeScript = /\.[mc]?ts$/.test(filePath);
227
- const isDeno = typeof globalThis.Deno !== "undefined";
228
- const isBun = typeof globalThis.Bun !== "undefined";
229
- if (!isDeno && !isBun && isTypeScript && !nodeSupportsNativeTypeScript()) try {
263
+ const isPlainTs = /\.[mc]?ts$/.test(filePath);
264
+ const isJsxOrTsx = jsxTsxPattern.test(filePath);
265
+ const isDeno = "Deno" in globalThis;
266
+ const isBun = "Bun" in globalThis;
267
+ if (!isDeno && !isBun && (isJsxOrTsx || isPlainTs && !nodeSupportsNativeTypeScript())) await registerTsx(filePath, isJsxOrTsx);
268
+ else if (!isDeno && !isBun) await tryRegisterTsx();
269
+ const fileUrl = (0, node_url.pathToFileURL)(absolutePath).href;
270
+ try {
271
+ return await import(fileUrl);
272
+ } catch (error) {
273
+ if (!isDeno && !isBun && isNodeError(error) && error.code === "ERR_UNKNOWN_FILE_EXTENSION") {
274
+ const failedPath = extractPathFromExtensionError(error.message);
275
+ if (failedPath != null && jsxTsxPattern.test(failedPath)) jsxLoaderRequiredError(failedPath);
276
+ }
277
+ throw error;
278
+ }
279
+ }
280
+ /**
281
+ * Checks whether an error is a Node.js system error with a string `code`.
282
+ * @param error The value to check.
283
+ * @returns `true` if the error has a string `code` property.
284
+ */
285
+ function isNodeError(error) {
286
+ return error instanceof Error && "code" in error && typeof error.code === "string";
287
+ }
288
+ /**
289
+ * Extracts the file path from a Node.js `ERR_UNKNOWN_FILE_EXTENSION` error
290
+ * message, which has the format `Unknown file extension ".ext" for /path`.
291
+ * @param message The error message string.
292
+ * @returns The file path, or null if the message format is unexpected.
293
+ */
294
+ function extractPathFromExtensionError(message$1) {
295
+ const match = /^Unknown file extension "\.[^"]*" for (.+)$/.exec(message$1);
296
+ return match?.[1] ?? null;
297
+ }
298
+ /**
299
+ * Registers the tsx loader for TypeScript/JSX/TSX support on Node.js.
300
+ * @param filePath The file path being loaded (used for error messages).
301
+ * @param isJsxOrTsx Whether the file uses a JSX or TSX extension.
302
+ */
303
+ async function registerTsx(filePath, isJsxOrTsx) {
304
+ try {
230
305
  const tsx = await import("tsx/esm/api");
231
306
  tsx.register();
232
- } catch {
233
- tsxRequiredError(filePath);
307
+ } catch (error) {
308
+ if (!isNodeError(error) || error.code !== "ERR_MODULE_NOT_FOUND") throw error;
309
+ if (isJsxOrTsx) jsxLoaderRequiredError(filePath);
310
+ else tsxRequiredError(filePath);
234
311
  }
235
- const fileUrl = (0, node_url.pathToFileURL)(absolutePath).href;
236
- return await import(fileUrl);
312
+ }
313
+ /**
314
+ * Tries to register the tsx loader, silently ignoring all failures.
315
+ * Used on Node.js for entries that may have transitive JSX/TSX dependencies.
316
+ *
317
+ * All errors are suppressed because this is a best-effort preload: the
318
+ * entry file itself does not require tsx, and failing here would be a
319
+ * regression for environments where tsx is absent, incompatible, or
320
+ * broken. If a transitive JSX/TSX dependency is later encountered
321
+ * without a loader, the caller's catch block produces a helpful error.
322
+ */
323
+ async function tryRegisterTsx() {
324
+ try {
325
+ const tsx = await import("tsx/esm/api");
326
+ tsx.register();
327
+ } catch {}
237
328
  }
238
329
  /**
239
330
  * Checks if a value is a Program object.
240
331
  */
241
332
  function isProgram(value) {
242
- return value != null && typeof value === "object" && "parser" in value && "metadata" in value && typeof value.metadata === "object" && value.metadata != null;
333
+ try {
334
+ return value != null && typeof value === "object" && "parser" in value && "metadata" in value && typeof value.metadata === "object" && value.metadata != null && typeof value.metadata.name === "string" && isParser(value.parser);
335
+ } catch {
336
+ return false;
337
+ }
243
338
  }
244
339
  /**
245
340
  * Checks if a value is a Parser object.
246
341
  */
247
342
  function isParser(value) {
248
- return value != null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "$mode" in value && "usage" in value;
343
+ try {
344
+ return value != null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "$mode" in value && "usage" in value && "getDocFragments" in value && typeof value.getDocFragments === "function";
345
+ } catch {
346
+ return false;
347
+ }
249
348
  }
250
349
  /**
251
350
  * Infers the program name from a file path.
@@ -253,7 +352,7 @@ function isParser(value) {
253
352
  function inferNameFromPath(filePath) {
254
353
  const base = (0, node_path.basename)(filePath);
255
354
  const ext = (0, node_path.extname)(base);
256
- return base.slice(0, -ext.length);
355
+ return ext.length > 0 ? base.slice(0, -ext.length) : base;
257
356
  }
258
357
  /**
259
358
  * Gets available exports from a module.
@@ -278,7 +377,7 @@ async function main() {
278
377
  help: "option",
279
378
  version: {
280
379
  value: deno_default.version,
281
- mode: "option"
380
+ option: true
282
381
  }
283
382
  });
284
383
  const mod = await importModule(args.file);
@@ -286,19 +385,20 @@ async function main() {
286
385
  if (target === void 0) exportNotFoundError(args.file, args.exportName, getAvailableExports(mod));
287
386
  if (!isProgram(target) && !isParser(target)) notProgramOrParserError(args.file, args.exportName, describeType(target));
288
387
  const name$1 = args.name ?? (isProgram(target) ? target.metadata.name : null) ?? inferNameFromPath(args.file);
388
+ const date = args.date ?? /* @__PURE__ */ new Date();
289
389
  let manPage;
290
390
  try {
291
391
  if (isProgram(target)) manPage = await require_generator.generateManPageAsync(target, {
292
392
  section: args.section,
293
393
  name: args.name,
294
- date: args.date,
394
+ date,
295
395
  version: args.versionString,
296
396
  manual: args.manual
297
397
  });
298
398
  else manPage = await require_generator.generateManPageAsync(target, {
299
399
  name: name$1,
300
400
  section: args.section,
301
- date: args.date,
401
+ date,
302
402
  version: args.versionString,
303
403
  manual: args.manual
304
404
  });
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import "./roff-C_MiRXVS.js";
3
- import "./man-Leuf7kOn.js";
4
- import { generateManPageAsync } from "./generator-CCa36YC2.js";
2
+ import "./roff-CCdIQO7B.js";
3
+ import "./man-BE1OY_lJ.js";
4
+ import { generateManPageAsync } from "./generator-YM0drazb.js";
5
5
  import { object } from "@optique/core/constructs";
6
6
  import { argument, option } from "@optique/core/primitives";
7
7
  import { choice, string } from "@optique/core/valueparser";
@@ -17,7 +17,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
17
17
 
18
18
  //#region deno.json
19
19
  var name = "@optique/man";
20
- var version = "0.10.7-dev.485+0a30b635";
20
+ var version = "1.0.0-dev.1109+fa132665";
21
21
  var license = "MIT";
22
22
  var exports = {
23
23
  ".": "./src/index.ts",
@@ -56,6 +56,7 @@ var deno_default = {
56
56
 
57
57
  //#endregion
58
58
  //#region src/cli.ts
59
+ const jsxTsxPattern = /\.[mc]?[jt]sx$/;
59
60
  const EXIT_FILE_NOT_FOUND = 1;
60
61
  const EXIT_EXPORT_NOT_FOUND = 2;
61
62
  const EXIT_NOT_PROGRAM_OR_PARSER = 3;
@@ -89,15 +90,31 @@ a ${metavar("PROGRAM")} (from ${commandLine("defineProgram()")}) or
89
90
  a ${metavar("PARSER")}. If not specified, the default export is used.` }), "default"),
90
91
  output: optional(option("-o", "--output", string({ metavar: "PATH" }), { description: message`Output file path. If not specified, the man page
91
92
  is written to stdout.` })),
92
- name: optional(option("--name", string({ metavar: "NAME" }), { description: message`Program name to use in the man page header.
93
+ name: optional(option("--name", string({
94
+ metavar: "NAME",
95
+ pattern: /.+/,
96
+ errors: { patternMismatch: message`Program name must not be empty.` }
97
+ }), { description: message`Program name to use in the man page header.
93
98
  If not specified, inferred from the ${metavar("PROGRAM")} metadata
94
99
  or the input file name.` })),
95
- date: optional(option("--date", string({ metavar: "DATE" }), { description: message`Date to display in the man page footer.
100
+ date: optional(option("--date", string({
101
+ metavar: "DATE",
102
+ pattern: /.+/,
103
+ errors: { patternMismatch: message`Date must not be empty.` }
104
+ }), { description: message`Date to display in the man page footer.
96
105
  Defaults to the current date.` })),
97
- versionString: optional(option("--version-string", string({ metavar: "VERSION" }), { description: message`Version string for the man page footer
106
+ versionString: optional(option("--version-string", string({
107
+ metavar: "VERSION",
108
+ pattern: /.+/,
109
+ errors: { patternMismatch: message`Version string must not be empty.` }
110
+ }), { description: message`Version string for the man page footer
98
111
  (e.g., ${"MyApp 1.0.0"}). Overrides the version from
99
112
  ${metavar("PROGRAM")} metadata if provided.` })),
100
- manual: optional(option("--manual", string({ metavar: "TITLE" }), { description: message`Manual name for the man page header
113
+ manual: optional(option("--manual", string({
114
+ metavar: "TITLE",
115
+ pattern: /.+/,
116
+ errors: { patternMismatch: message`Manual name must not be empty.` }
117
+ }), { description: message`Manual name for the man page header
101
118
  (e.g., ${"User Commands"}).` }))
102
119
  }),
103
120
  metadata: {
@@ -187,7 +204,7 @@ an Optique parser (e.g., from ${commandLine("object()")},
187
204
  ${commandLine("command()")}, etc.).`, { exitCode: EXIT_NOT_PROGRAM_OR_PARSER });
188
205
  }
189
206
  /**
190
- * Error handler for missing tsx.
207
+ * Error handler for missing tsx for TypeScript files.
191
208
  */
192
209
  function tsxRequiredError(filePath) {
193
210
  const version$1 = getNodeMajorMinor();
@@ -200,6 +217,22 @@ Install tsx as a dev dependency:
200
217
 
201
218
  Or upgrade to Node.js 25.2.0 or later, which supports TypeScript natively.
202
219
 
220
+ Alternatively, use a pre-compiled JavaScript file instead.`, { exitCode: EXIT_TSX_REQUIRED });
221
+ }
222
+ /**
223
+ * Error handler for missing tsx for JSX/TSX files.
224
+ */
225
+ function jsxLoaderRequiredError(filePath) {
226
+ const version$1 = getNodeMajorMinor();
227
+ const versionStr = version$1 ? `${version$1[0]}.${version$1[1]}` : "unknown";
228
+ const isTsx = /\.[mc]?tsx$/.test(filePath);
229
+ const fileKind = isTsx ? "TSX" : "JSX";
230
+ printError(message`${fileKind} file ${filePath} cannot be loaded on Node.js ${versionStr}.
231
+
232
+ Install tsx as a dev dependency:
233
+
234
+ ${commandLine("npm install -D tsx")}
235
+
203
236
  Alternatively, use a pre-compiled JavaScript file instead.`, { exitCode: EXIT_TSX_REQUIRED });
204
237
  }
205
238
  /**
@@ -218,34 +251,100 @@ Make sure you have write permission and the parent directory exists.`, { exitCod
218
251
  }
219
252
  /**
220
253
  * Imports a module from the given file path.
221
- * Handles TypeScript files on Node.js by using tsx if needed.
254
+ * Handles TypeScript and JSX files on Node.js by using tsx if needed.
255
+ * @param filePath The path to the module file.
256
+ * @returns The imported module's exports.
257
+ * @throws If the module fails to import for reasons other than a missing
258
+ * tsx loader (which causes the process to exit instead).
222
259
  */
223
260
  async function importModule(filePath) {
224
261
  const absolutePath = resolve(filePath);
225
262
  if (!existsSync(absolutePath)) fileNotFoundError(filePath);
226
- const isTypeScript = /\.[mc]?ts$/.test(filePath);
227
- const isDeno = typeof globalThis.Deno !== "undefined";
228
- const isBun = typeof globalThis.Bun !== "undefined";
229
- if (!isDeno && !isBun && isTypeScript && !nodeSupportsNativeTypeScript()) try {
263
+ const isPlainTs = /\.[mc]?ts$/.test(filePath);
264
+ const isJsxOrTsx = jsxTsxPattern.test(filePath);
265
+ const isDeno = "Deno" in globalThis;
266
+ const isBun = "Bun" in globalThis;
267
+ if (!isDeno && !isBun && (isJsxOrTsx || isPlainTs && !nodeSupportsNativeTypeScript())) await registerTsx(filePath, isJsxOrTsx);
268
+ else if (!isDeno && !isBun) await tryRegisterTsx();
269
+ const fileUrl = pathToFileURL(absolutePath).href;
270
+ try {
271
+ return await import(fileUrl);
272
+ } catch (error) {
273
+ if (!isDeno && !isBun && isNodeError(error) && error.code === "ERR_UNKNOWN_FILE_EXTENSION") {
274
+ const failedPath = extractPathFromExtensionError(error.message);
275
+ if (failedPath != null && jsxTsxPattern.test(failedPath)) jsxLoaderRequiredError(failedPath);
276
+ }
277
+ throw error;
278
+ }
279
+ }
280
+ /**
281
+ * Checks whether an error is a Node.js system error with a string `code`.
282
+ * @param error The value to check.
283
+ * @returns `true` if the error has a string `code` property.
284
+ */
285
+ function isNodeError(error) {
286
+ return error instanceof Error && "code" in error && typeof error.code === "string";
287
+ }
288
+ /**
289
+ * Extracts the file path from a Node.js `ERR_UNKNOWN_FILE_EXTENSION` error
290
+ * message, which has the format `Unknown file extension ".ext" for /path`.
291
+ * @param message The error message string.
292
+ * @returns The file path, or null if the message format is unexpected.
293
+ */
294
+ function extractPathFromExtensionError(message$1) {
295
+ const match = /^Unknown file extension "\.[^"]*" for (.+)$/.exec(message$1);
296
+ return match?.[1] ?? null;
297
+ }
298
+ /**
299
+ * Registers the tsx loader for TypeScript/JSX/TSX support on Node.js.
300
+ * @param filePath The file path being loaded (used for error messages).
301
+ * @param isJsxOrTsx Whether the file uses a JSX or TSX extension.
302
+ */
303
+ async function registerTsx(filePath, isJsxOrTsx) {
304
+ try {
230
305
  const tsx = await import("tsx/esm/api");
231
306
  tsx.register();
232
- } catch {
233
- tsxRequiredError(filePath);
307
+ } catch (error) {
308
+ if (!isNodeError(error) || error.code !== "ERR_MODULE_NOT_FOUND") throw error;
309
+ if (isJsxOrTsx) jsxLoaderRequiredError(filePath);
310
+ else tsxRequiredError(filePath);
234
311
  }
235
- const fileUrl = pathToFileURL(absolutePath).href;
236
- return await import(fileUrl);
312
+ }
313
+ /**
314
+ * Tries to register the tsx loader, silently ignoring all failures.
315
+ * Used on Node.js for entries that may have transitive JSX/TSX dependencies.
316
+ *
317
+ * All errors are suppressed because this is a best-effort preload: the
318
+ * entry file itself does not require tsx, and failing here would be a
319
+ * regression for environments where tsx is absent, incompatible, or
320
+ * broken. If a transitive JSX/TSX dependency is later encountered
321
+ * without a loader, the caller's catch block produces a helpful error.
322
+ */
323
+ async function tryRegisterTsx() {
324
+ try {
325
+ const tsx = await import("tsx/esm/api");
326
+ tsx.register();
327
+ } catch {}
237
328
  }
238
329
  /**
239
330
  * Checks if a value is a Program object.
240
331
  */
241
332
  function isProgram(value) {
242
- return value != null && typeof value === "object" && "parser" in value && "metadata" in value && typeof value.metadata === "object" && value.metadata != null;
333
+ try {
334
+ return value != null && typeof value === "object" && "parser" in value && "metadata" in value && typeof value.metadata === "object" && value.metadata != null && typeof value.metadata.name === "string" && isParser(value.parser);
335
+ } catch {
336
+ return false;
337
+ }
243
338
  }
244
339
  /**
245
340
  * Checks if a value is a Parser object.
246
341
  */
247
342
  function isParser(value) {
248
- return value != null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "$mode" in value && "usage" in value;
343
+ try {
344
+ return value != null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "$mode" in value && "usage" in value && "getDocFragments" in value && typeof value.getDocFragments === "function";
345
+ } catch {
346
+ return false;
347
+ }
249
348
  }
250
349
  /**
251
350
  * Infers the program name from a file path.
@@ -253,7 +352,7 @@ function isParser(value) {
253
352
  function inferNameFromPath(filePath) {
254
353
  const base = basename(filePath);
255
354
  const ext = extname(base);
256
- return base.slice(0, -ext.length);
355
+ return ext.length > 0 ? base.slice(0, -ext.length) : base;
257
356
  }
258
357
  /**
259
358
  * Gets available exports from a module.
@@ -278,7 +377,7 @@ async function main() {
278
377
  help: "option",
279
378
  version: {
280
379
  value: deno_default.version,
281
- mode: "option"
380
+ option: true
282
381
  }
283
382
  });
284
383
  const mod = await importModule(args.file);
@@ -286,19 +385,20 @@ async function main() {
286
385
  if (target === void 0) exportNotFoundError(args.file, args.exportName, getAvailableExports(mod));
287
386
  if (!isProgram(target) && !isParser(target)) notProgramOrParserError(args.file, args.exportName, describeType(target));
288
387
  const name$1 = args.name ?? (isProgram(target) ? target.metadata.name : null) ?? inferNameFromPath(args.file);
388
+ const date = args.date ?? /* @__PURE__ */ new Date();
289
389
  let manPage;
290
390
  try {
291
391
  if (isProgram(target)) manPage = await generateManPageAsync(target, {
292
392
  section: args.section,
293
393
  name: args.name,
294
- date: args.date,
394
+ date,
295
395
  version: args.versionString,
296
396
  manual: args.manual
297
397
  });
298
398
  else manPage = await generateManPageAsync(target, {
299
399
  name: name$1,
300
400
  section: args.section,
301
- date: args.date,
401
+ date,
302
402
  version: args.versionString,
303
403
  manual: args.manual
304
404
  });
@@ -1,41 +1,42 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
24
- const require_man = require('./man-DGnow1Jr.cjs');
25
- const __optique_core_parser = __toESM(require("@optique/core/parser"));
1
+ const require_man = require('./man-CkvscTlM.cjs');
2
+ const __optique_core_parser = require_man.__toESM(require("@optique/core/parser"));
26
3
 
27
4
  //#region src/generator.ts
28
5
  /**
6
+ * Checks if the given value looks like a {@link Parser} at runtime.
7
+ */
8
+ function isParser(value) {
9
+ try {
10
+ if (value == null || typeof value !== "object") return false;
11
+ const p = value;
12
+ return "parse" in p && typeof p.parse === "function" && "complete" in p && typeof p.complete === "function" && "$mode" in p && (p.$mode === "sync" || p.$mode === "async") && "usage" in p && Array.isArray(p.usage) && "initialState" in p && "suggest" in p && typeof p.suggest === "function" && "getDocFragments" in p && typeof p.getDocFragments === "function";
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+ /**
29
18
  * Checks if the given value is a {@link Program} object.
30
19
  */
31
20
  function isProgram(value) {
32
- return typeof value === "object" && value !== null && "parser" in value && "metadata" in value;
21
+ try {
22
+ return typeof value === "object" && value !== null && "parser" in value && "metadata" in value && typeof value.metadata === "object" && value.metadata !== null && "name" in value.metadata && typeof value.metadata.name === "string";
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+ /**
28
+ * Validates that the extracted parser is a genuine Optique parser.
29
+ * @throws {TypeError} If the value is not a valid Parser.
30
+ */
31
+ function validateParser(value) {
32
+ if (!isParser(value)) throw new TypeError("The given value is not a valid Parser or Program.");
33
33
  }
34
34
  /**
35
35
  * Extracts parser and merged options from a parser or program.
36
36
  */
37
37
  function extractParserAndOptions(parserOrProgram, options) {
38
38
  if (isProgram(parserOrProgram)) {
39
+ validateParser(parserOrProgram.parser);
39
40
  const { metadata } = parserOrProgram;
40
41
  const programOptions = options;
41
42
  return {
@@ -49,6 +50,9 @@ function extractParserAndOptions(parserOrProgram, options) {
49
50
  author: programOptions.author ?? metadata.author,
50
51
  bugs: programOptions.bugs ?? metadata.bugs,
51
52
  examples: programOptions.examples ?? metadata.examples,
53
+ brief: programOptions.brief ?? metadata.brief,
54
+ description: programOptions.description ?? metadata.description,
55
+ footer: programOptions.footer ?? metadata.footer,
52
56
  seeAlso: programOptions.seeAlso,
53
57
  environment: programOptions.environment,
54
58
  files: programOptions.files,
@@ -56,6 +60,7 @@ function extractParserAndOptions(parserOrProgram, options) {
56
60
  }
57
61
  };
58
62
  }
63
+ validateParser(parserOrProgram);
59
64
  return {
60
65
  parser: parserOrProgram,
61
66
  mergedOptions: options
@@ -63,6 +68,7 @@ function extractParserAndOptions(parserOrProgram, options) {
63
68
  }
64
69
  function generateManPageSync(parserOrProgram, options) {
65
70
  const { parser, mergedOptions } = extractParserAndOptions(parserOrProgram, options);
71
+ if (parser.$mode === "async") throw new TypeError("Cannot use an async parser with generateManPageSync(). Use generateManPageAsync() or generateManPage() instead.");
66
72
  const docPage = (0, __optique_core_parser.getDocPageSync)(parser) ?? { sections: [] };
67
73
  return require_man.formatDocPageAsMan(docPage, mergedOptions);
68
74
  }
@@ -78,12 +84,6 @@ function generateManPage(parserOrProgram, options) {
78
84
  }
79
85
 
80
86
  //#endregion
81
- Object.defineProperty(exports, '__toESM', {
82
- enumerable: true,
83
- get: function () {
84
- return __toESM;
85
- }
86
- });
87
87
  Object.defineProperty(exports, 'generateManPage', {
88
88
  enumerable: true,
89
89
  get: function () {