@amritk/mjst 0.22.0 → 0.23.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.
package/AI.md CHANGED
@@ -8,7 +8,7 @@ reference is [README.md](./README.md); config options are in
8
8
 
9
9
  > Pre-alpha: generated output and flags change without notice pre-1.0. This
10
10
  > package ships **only a `mjst` binary** — there are no JS exports. For the
11
- > programmatic API import `@amritk/parsers` etc. instead.
11
+ > programmatic API import `@amritk/validation` etc. instead.
12
12
 
13
13
  ## The four commands
14
14
 
@@ -57,11 +57,19 @@ mjst markdown ./config.schema.json --table --readme ./README.md
57
57
  `--discriminator <prop>` when the document tags frames with something other
58
58
  than `type`; a channel carrying `x-mjst: { discriminator }` keeps its own.
59
59
 
60
+ ## Picking what gets emitted
61
+
62
+ Every run emits the type. `--types-only` stops there. A bare run adds a parser;
63
+ `--validators` adds `isX`/`validateX` beside it; `--validators-only` emits those
64
+ *without* a parser, which is the shape to reach for when the generated code only
65
+ ever judges input it did not produce. `--check`, `--coerce` and `--repair` each
66
+ add one more entry point to the validator half and work under either flag.
67
+
60
68
  ## Common flags
61
69
 
62
70
  `--schema` / `--schema-dir`, `--out-dir` / `--out-file`, `--input`,
63
- `--validators`, `--examples`, `--message-contracts`, `--discriminator`,
64
- `--types-only`, `--build`, `--strict`, `--strip-unknown`,
71
+ `--validators` / `--validators-only`, `--examples`, `--message-contracts`,
72
+ `--discriminator`, `--types-only`, `--build`, `--strict`, `--strip-unknown`,
65
73
  `--unknown-keys count-keys|count-enumerable`, `--readonly`,
66
74
  `--import-ext ts|js`, `--config <path>`, `--resolve-remote` /
67
75
  `--allowed-hosts` (SSRF-guarded remote `$ref`s).
package/README.md CHANGED
@@ -321,6 +321,10 @@ npx mjst markdown ./config.schema.json --table --readme ./README.md
321
321
  | `--layout` | Default layout for nested properties: `headings` (default), `table`, or `none`. |
322
322
  | `--sort` | Property order: `schema` (default) or `alphabetical`. |
323
323
  | `--heading-level` | Heading level of the page title, 1-6 (default: `1`). |
324
+ | `--type-column` | When a property table renders its **Type** column: `auto` (default — only when a row fills it with something a reader could act on), `always`, or `never`. |
325
+ | `--default-column` | When a property table renders its **Default** column: `auto` (default), `always`, or `never`. |
326
+ | `--required-style` | How a property table says which properties are required: `marker` (default — `_required_` beside the name) or `column` (a **Required** column). |
327
+ | `--required-first` | List the required properties at the top of every table, the rest under them. |
324
328
  | `--table` | Render the HTML config table instead of the prose pages. |
325
329
  | `--readme` | Markdown file the table is spliced into (default: `README.md`). Requires `--table`. |
326
330
 
@@ -408,6 +412,15 @@ Under `--table` only the content between `<!-- config-table-start -->
408
412
  <td colspan="4">Also emit validation functions alongside the parsers. For every generated type X the CLI writes a validateX (returning a rich ValidationResult with JSON-Pointer error paths) and an isX boolean type guard. They share one directory and one declaration of X with the parser: the type and the validators land in x.ts, and the parser moves to x.parse.ts beside them, importing the type from there. Works with both schema and schemaDir. Incompatible with typesOnly and outFile, which produce no runtime code.</td>
409
413
  </tr>
410
414
  <tr>
415
+ <td>🛡️ <code>validatorsOnly</code></td>
416
+ <td><code>--validators-only</code></td>
417
+ <td><code>boolean</code></td>
418
+ <td align="center"><code>false</code></td>
419
+ </tr>
420
+ <tr>
421
+ <td colspan="4">Emit the validator half and no parser: the type, isX, validateX, and whichever of checkX, coerceX and repairX were asked for. Implies validators, so it does not need it as well. This is the mirror of typesOnly at the other end of the ladder — one run with nothing that rewrites a document, the other with nothing that executes at all — and it is what to reach for when the generated code only ever judges input it did not produce. Without it every run carries a parser. Incompatible with typesOnly and outFile.</td>
422
+ </tr>
423
+ <tr>
411
424
  <td>🔎 <code>check</code></td>
412
425
  <td><code>--check</code></td>
413
426
  <td><code>boolean</code></td>
@@ -41,6 +41,17 @@ export type CliConfig = {
41
41
  * Useful when you only need the type shapes and do not need runtime validation.
42
42
  */
43
43
  readonly typesOnly?: boolean;
44
+ /**
45
+ * When true, emit the validator half and no parser: the type, `isX`,
46
+ * `validateX`, and whichever of `checkX`/`coerceX`/`repairX` were asked for.
47
+ *
48
+ * Implies `validators`, and is the mirror of `typesOnly` at the other end of
49
+ * the ladder — one run with nothing that rewrites a document, the other with
50
+ * nothing that executes at all. Without it every run carries a parser, so the
51
+ * library's own default (a type and its validators, nothing that builds a
52
+ * value) had no spelling here.
53
+ */
54
+ readonly validatorsOnly?: boolean;
44
55
  /**
45
56
  * When true, also emit validation functions alongside the parsers. For every
46
57
  * generated type `X` the CLI writes a `validateX` (returning a rich
package/dist/cli.js CHANGED
@@ -377,19 +377,20 @@ const run = async () => {
377
377
  const fileConfig = configPath ? await loadConfig(configPath) : {};
378
378
  const cliConfig = parseCliArgs(args);
379
379
  const config = { ...fileConfig, ...cliConfig };
380
- if (config.coerce && !config.validators) {
380
+ const wantsValidators = config.validators === true || config.validatorsOnly === true;
381
+ if (config.coerce && !wantsValidators) {
381
382
  console.error("Error: --coerce shapes the generated validators, so it needs --validators too.");
382
383
  process.exit(1);
383
384
  }
384
- if (config.repair && !config.validators) {
385
+ if (config.repair && !wantsValidators) {
385
386
  console.error("Error: --repair shapes the generated validators, so it needs --validators too.");
386
387
  process.exit(1);
387
388
  }
388
- if (config.check && !config.validators) {
389
+ if (config.check && !wantsValidators) {
389
390
  console.error("Error: --check shapes the generated validators, so it needs --validators too.");
390
391
  process.exit(1);
391
392
  }
392
- if (config.branchErrors && !config.validators) {
393
+ if (config.branchErrors && !wantsValidators) {
393
394
  console.error("Error: --branch-errors shapes the generated validators, so it needs --validators too.");
394
395
  process.exit(1);
395
396
  }
@@ -413,10 +414,18 @@ const run = async () => {
413
414
  console.error("Error: --validators cannot be combined with --types-only, which emits no runtime code.");
414
415
  process.exit(1);
415
416
  }
417
+ if (config.validatorsOnly && config.typesOnly) {
418
+ console.error("Error: --validators-only cannot be combined with --types-only. Pick the one end you want: types alone, or types and validators.");
419
+ process.exit(1);
420
+ }
416
421
  if (config.validators && config.outFile) {
417
422
  console.error("Error: --validators cannot be combined with --out-file. Use --out-dir to emit validator files.");
418
423
  process.exit(1);
419
424
  }
425
+ if (config.validatorsOnly && config.outFile) {
426
+ console.error("Error: --validators-only cannot be combined with --out-file. Use --out-dir to emit validator files.");
427
+ process.exit(1);
428
+ }
420
429
  if (config.input === "asyncapi") {
421
430
  if (config.schemaDir) {
422
431
  console.error("Error: --input asyncapi reads a single document via --schema; it cannot be combined with --schema-dir.");
@@ -1,4 +1,4 @@
1
- import type { GeneratedFile } from '@amritk/parsers';
1
+ import type { GeneratedFile } from '@amritk/validation';
2
2
  /**
3
3
  * Merges the per-schema {@link GeneratedFile}s into a single self-contained
4
4
  * TypeScript module. Each generated file imports its sibling definitions via
@@ -1,4 +1,4 @@
1
- import { type GeneratedFile } from '@amritk/parsers';
1
+ import { type GeneratedFile } from '@amritk/validation';
2
2
  import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
3
3
  import type { CliConfig } from './cli-config.js';
4
4
  /** Where one schema's generated files reach their runtime helpers from. */
@@ -14,7 +14,7 @@ export type HelpersPlacement = {
14
14
  };
15
15
  /**
16
16
  * Generates one schema's files, translating the CLI's flags into the single
17
- * options object `@amritk/parsers` takes.
17
+ * options object `@amritk/validation` takes.
18
18
  *
19
19
  * All four generation flows come through here so none of them can quietly hold a
20
20
  * different opinion about what a flag means — which is exactly what happened
@@ -1,4 +1,4 @@
1
- import { generate } from "@amritk/parsers";
1
+ import { generate } from "@amritk/validation";
2
2
  import { resolveImportExt } from "./resolve-import-ext.js";
3
3
  import { resolveModes } from "./resolve-modes.js";
4
4
  const generateFiles = async (config, schema, rootTypeName, helpers) => generate(schema, rootTypeName, {
@@ -4,4 +4,4 @@
4
4
  * documents these flags (config.schema.json) is not shipped in the published
5
5
  * package; the help-text test cross-checks that every flag is listed.
6
6
  */
7
- export declare const HELP_TEXT = "mjst \u2014 generate TypeScript parsers and type definitions from JSON Schemas\n\nUsage:\n mjst --schema <path> --out-dir <dir> [options]\n mjst --schema-dir <dir> --out-dir <dir> [options]\n mjst --schema <path> --out-file <file> --types-only [options]\n\nSubcommands (each with its own flags and --help):\n mjst lint <files> Lint JSON/YAML documents against a ruleset\n mjst compile-api <module> --out <file> Compile @amritk/api route contracts into a fetch-handler module\n mjst markdown <schema> --out-dir <dir> Generate markdown documentation from a JSON Schema\n\nInput:\n --schema <path> Schema to process: a JSON Schema file, or a module when --input is set\n --schema-dir <dir> Directory of JSON Schemas, processed recursively (instead of --schema)\n --input <format> Schema source format: json (default), typebox, zod, valibot, effect, avro,\n or asyncapi (an AsyncAPI 2.x/3.0 document, JSON or YAML)\n --export <name> Which export of the schema module to use when --input names a module format\n\nOutput:\n --out-dir <dir> Output directory for the generated files\n --out-file <file> Single-file output instead of a directory (requires --types-only)\n --types-only Generate type definitions only, without parser functions\n --validators Also emit validateX/isX validators beside the parsers, over one\n shared declaration of each generated type\n --check Also emit checkX, the same result as validateX but stopped at the\n first violation (requires --validators)\n --coerce Also emit coerceX, which coerces scalars the way Ajv's coerceTypes\n does and then validates (requires --validators)\n --repair Also emit repairX, which coerces, validates, then repairs each\n rejected position to a schema-supplied value and reports the\n errors it repaired (implies --coerce; requires --validators)\n --branch-errors Explain a failing anyOf/oneOf with the errors of the branch it\n meant (requires --validators; costs a little on unions)\n --examples Also emit fast-check arbitraries + example values under examples/\n --message-contracts Also emit @amritk/api channel contracts under contracts/ (--input asyncapi only)\n --discriminator <p> Property naming which message a frame is, for --message-contracts (default: type)\n --build Compile the generated files to .js/.d.ts (implies --import-ext js)\n --force Deprecated; ignored (generated files always overwrite)\n --import-ext <ext> Extension on generated relative imports: ts (default) or js\n --helpers <mode> Runtime helpers: package or embedded (default: auto-detect from package.json)\n --root-type <name> Root type name for a single --schema run (default: schema title or filename)\n --type-suffix <s> Suffix appended to every $ref-derived type name\n --banner [text] Prepend a header comment to every generated file\n --readonly Emit deeply readonly type definitions\n\nValidation:\n --strict Throw on type/shape mismatches instead of coercing to defaults\n --strip-unknown Silently drop undeclared input keys at every nesting level\n --case-insensitive Normalize mis-cased enum/const strings to their exact casing\n --log-warnings console.warn on input keys not declared in the schema\n --unknown-keys <s> How closed objects are proven free of undeclared keys:\n count-keys (default, fastest on Bun) or count-enumerable (fastest on Node)\n --formats <f> String formats the generated validators enforce: \"all\", or a\n comma-separated list (e.g. uuid,date-time,email). Off by default,\n which leaves \"format\" an annotation as JSON Schema reads it.\n\nReference resolution:\n --resolve-remote Fetch http(s) $refs while resolving cross-file/remote refs (off by default)\n --allowed-hosts <h> Restrict remote $ref fetches to these hosts (comma-separated; implies --resolve-remote)\n --allow-private-hosts Permit remote $refs to private/loopback hosts (SSRF guard, off by default)\n --allowed-roots <d> Extra directories a local $ref may resolve into, on top of the schema's own\n (comma-separated; relative to the current directory)\n\nMisc:\n --config <path> JSON config file with the same keys; CLI flags take precedence\n --version, -v Print the CLI version\n --help, -h Print this help\n\nDocs: https://github.com/amritk/mjst/tree/main/packages/cli#readme\n";
7
+ export declare const HELP_TEXT = "mjst \u2014 generate TypeScript types, validators and parsers from JSON Schemas\n\nUsage:\n mjst --schema <path> --out-dir <dir> [options]\n mjst --schema-dir <dir> --out-dir <dir> [options]\n mjst --schema <path> --out-file <file> --types-only [options]\n\nSubcommands (each with its own flags and --help):\n mjst lint <files> Lint JSON/YAML documents against a ruleset\n mjst compile-api <module> --out <file> Compile @amritk/api route contracts into a fetch-handler module\n mjst markdown <schema> --out-dir <dir> Generate markdown documentation from a JSON Schema\n\nInput:\n --schema <path> Schema to process: a JSON Schema file, or a module when --input is set\n --schema-dir <dir> Directory of JSON Schemas, processed recursively (instead of --schema)\n --input <format> Schema source format: json (default), typebox, zod, valibot, effect, avro,\n or asyncapi (an AsyncAPI 2.x/3.0 document, JSON or YAML)\n --export <name> Which export of the schema module to use when --input names a module format\n\nOutput:\n --out-dir <dir> Output directory for the generated files\n --out-file <file> Single-file output instead of a directory (requires --types-only)\n --types-only Generate type definitions only, without parser functions\n --validators Also emit validateX/isX validators beside the parsers, over one\n shared declaration of each generated type\n --validators-only Emit the validator half and no parser: the type, isX, validateX and\n whichever of checkX/coerceX/repairX were asked for (implies\n --validators; the mirror of --types-only)\n --check Also emit checkX, the same result as validateX but stopped at the\n first violation (requires --validators)\n --coerce Also emit coerceX, which coerces scalars the way Ajv's coerceTypes\n does and then validates (requires --validators)\n --repair Also emit repairX, which coerces, validates, then repairs each\n rejected position to a schema-supplied value and reports the\n errors it repaired (implies --coerce; requires --validators)\n --branch-errors Explain a failing anyOf/oneOf with the errors of the branch it\n meant (requires --validators; costs a little on unions)\n --examples Also emit fast-check arbitraries + example values under examples/\n --message-contracts Also emit @amritk/api channel contracts under contracts/ (--input asyncapi only)\n --discriminator <p> Property naming which message a frame is, for --message-contracts (default: type)\n --build Compile the generated files to .js/.d.ts (implies --import-ext js)\n --force Deprecated; ignored (generated files always overwrite)\n --import-ext <ext> Extension on generated relative imports: ts (default) or js\n --helpers <mode> Runtime helpers: package or embedded (default: auto-detect from package.json)\n --root-type <name> Root type name for a single --schema run (default: schema title or filename)\n --type-suffix <s> Suffix appended to every $ref-derived type name\n --banner [text] Prepend a header comment to every generated file\n --readonly Emit deeply readonly type definitions\n\nValidation:\n --strict Throw on type/shape mismatches instead of coercing to defaults\n --strip-unknown Silently drop undeclared input keys at every nesting level\n --case-insensitive Normalize mis-cased enum/const strings to their exact casing\n --log-warnings console.warn on input keys not declared in the schema\n --unknown-keys <s> How closed objects are proven free of undeclared keys:\n count-keys (default, fastest on Bun) or count-enumerable (fastest on Node)\n --formats <f> String formats the generated validators enforce: \"all\", or a\n comma-separated list (e.g. uuid,date-time,email). Off by default,\n which leaves \"format\" an annotation as JSON Schema reads it.\n\nReference resolution:\n --resolve-remote Fetch http(s) $refs while resolving cross-file/remote refs (off by default)\n --allowed-hosts <h> Restrict remote $ref fetches to these hosts (comma-separated; implies --resolve-remote)\n --allow-private-hosts Permit remote $refs to private/loopback hosts (SSRF guard, off by default)\n --allowed-roots <d> Extra directories a local $ref may resolve into, on top of the schema's own\n (comma-separated; relative to the current directory)\n\nMisc:\n --config <path> JSON config file with the same keys; CLI flags take precedence\n --version, -v Print the CLI version\n --help, -h Print this help\n\nDocs: https://github.com/amritk/mjst/tree/main/packages/cli#readme\n";
package/dist/help-text.js CHANGED
@@ -1,4 +1,4 @@
1
- const HELP_TEXT = `mjst \u2014 generate TypeScript parsers and type definitions from JSON Schemas
1
+ const HELP_TEXT = `mjst \u2014 generate TypeScript types, validators and parsers from JSON Schemas
2
2
 
3
3
  Usage:
4
4
  mjst --schema <path> --out-dir <dir> [options]
@@ -23,6 +23,9 @@ Output:
23
23
  --types-only Generate type definitions only, without parser functions
24
24
  --validators Also emit validateX/isX validators beside the parsers, over one
25
25
  shared declaration of each generated type
26
+ --validators-only Emit the validator half and no parser: the type, isX, validateX and
27
+ whichever of checkX/coerceX/repairX were asked for (implies
28
+ --validators; the mirror of --types-only)
26
29
  --check Also emit checkX, the same result as validateX but stopped at the
27
30
  first violation (requires --validators)
28
31
  --coerce Also emit coerceX, which coerces scalars the way Ajv's coerceTypes
@@ -30,6 +30,7 @@ const loadConfig = async (configPath) => {
30
30
  ...typeof obj["export"] === "string" && { export: obj["export"] },
31
31
  ...typeof obj["validators"] === "boolean" && { validators: obj["validators"] },
32
32
  ...typeof obj["typesOnly"] === "boolean" && { typesOnly: obj["typesOnly"] },
33
+ ...typeof obj["validatorsOnly"] === "boolean" && { validatorsOnly: obj["validatorsOnly"] },
33
34
  ...typeof obj["examples"] === "boolean" && { examples: obj["examples"] },
34
35
  ...typeof obj["messageContracts"] === "boolean" && { messageContracts: obj["messageContracts"] },
35
36
  ...typeof obj["discriminator"] === "string" && { discriminator: obj["discriminator"] },
@@ -3,4 +3,4 @@
3
3
  * HELP_TEXT: the flag list is small and stable, and the test cross-checks that
4
4
  * every flag is listed.
5
5
  */
6
- export declare const MARKDOWN_HELP_TEXT = "mjst markdown \u2014 generate markdown documentation from a JSON Schema\n\nUsage:\n mjst markdown <schema> --out-dir <dir> [options]\n mjst markdown <schema> --table --readme <file>\n\nTwo shapes come out of the same schema. By default it writes the prose\nreference \u2014 a heading, a type, the description and an example per property,\nacross as many pages as the schema's x-doc keyword declares. With --table it\nrenders one HTML table instead and splices it into an existing markdown file\nbetween <!-- config-table-start --> and <!-- config-table-end -->, leaving the\nrest of that file alone.\n\nProse reference options:\n --out-dir <dir> Directory the pages are written to (default: the current directory)\n --file <path> Output path of the index page (default: the schema's x-doc.file, then index.md)\n --title <text> Page title (default: the schema's title)\n --language <lang> Fence language for derived examples and literals (default: json)\n --layout <mode> Default layout for nested properties: headings (default), table, or none\n --sort <order> Property order: schema (default) or alphabetical\n --heading-level <n> Heading level of the page title, 1-6 (default: 1)\n\nTable options:\n --table Render the HTML config table instead of the prose pages\n --readme <path> Markdown file the table is spliced into (default: README.md)\n\nMisc:\n --help, -h Print this help\n\nDocs: https://github.com/amritk/mjst/tree/main/packages/cli#readme\n";
6
+ export declare const MARKDOWN_HELP_TEXT = "mjst markdown \u2014 generate markdown documentation from a JSON Schema\n\nUsage:\n mjst markdown <schema> --out-dir <dir> [options]\n mjst markdown <schema> --table --readme <file>\n\nTwo shapes come out of the same schema. By default it writes the prose\nreference \u2014 a heading, a type, the description and an example per property,\nacross as many pages as the schema's x-doc keyword declares. With --table it\nrenders one HTML table instead and splices it into an existing markdown file\nbetween <!-- config-table-start --> and <!-- config-table-end -->, leaving the\nrest of that file alone.\n\nProse reference options:\n --out-dir <dir> Directory the pages are written to (default: the current directory)\n --file <path> Output path of the index page (default: the schema's x-doc.file, then index.md)\n --title <text> Page title (default: the schema's title)\n --language <lang> Fence language for derived examples and literals (default: json)\n --layout <mode> Default layout for nested properties: headings (default), table, or none\n --sort <order> Property order: schema (default) or alphabetical\n --heading-level <n> Heading level of the page title, 1-6 (default: 1)\n\nProperty table options (the root x-doc.table, for every table on every page):\n --type-column <when> Render the Type column: auto (default), always, or never\n --default-column <when> Render the Default column: auto (default), always, or never\n --required-style <how> Say which properties are required: marker (default, beside\n the name) or column (a Required column)\n --required-first List the required properties at the top of every table\n\nTable options:\n --table Render the HTML config table instead of the prose pages\n --readme <path> Markdown file the table is spliced into (default: README.md)\n\nMisc:\n --help, -h Print this help\n\nDocs: https://github.com/amritk/mjst/tree/main/packages/cli#readme\n";
@@ -20,6 +20,13 @@ Prose reference options:
20
20
  --sort <order> Property order: schema (default) or alphabetical
21
21
  --heading-level <n> Heading level of the page title, 1-6 (default: 1)
22
22
 
23
+ Property table options (the root x-doc.table, for every table on every page):
24
+ --type-column <when> Render the Type column: auto (default), always, or never
25
+ --default-column <when> Render the Default column: auto (default), always, or never
26
+ --required-style <how> Say which properties are required: marker (default, beside
27
+ the name) or column (a Required column)
28
+ --required-first List the required properties at the top of every table
29
+
23
30
  Table options:
24
31
  --table Render the HTML config table instead of the prose pages
25
32
  --readme <path> Markdown file the table is spliced into (default: README.md)
@@ -1,4 +1,4 @@
1
- import type { DocLayout, DocSort } from '@amritk/generate-markdown';
1
+ import type { DocLayout, DocSort, DocTableColumn, DocTableRequired } from '@amritk/generate-markdown';
2
2
  /** The flags and positional the `markdown` subcommand understands. */
3
3
  export type MarkdownArgs = {
4
4
  /** Path to the JSON Schema to document (the sole positional). */
@@ -17,6 +17,14 @@ export type MarkdownArgs = {
17
17
  sort?: DocSort;
18
18
  /** Heading level of the page title (`--heading-level`). */
19
19
  headingLevel?: number;
20
+ /** When property tables render their Type column (`--type-column`). */
21
+ typeColumn?: DocTableColumn;
22
+ /** When property tables render their Default column (`--default-column`). */
23
+ defaultColumn?: DocTableColumn;
24
+ /** How property tables say which properties are required (`--required-style`). */
25
+ requiredStyle?: DocTableRequired;
26
+ /** True when `--required-first` was passed: required properties head every table. */
27
+ requiredFirst?: boolean;
20
28
  /** True when `--table` was passed: render the HTML table instead of the pages. */
21
29
  table?: boolean;
22
30
  /** Markdown file the table is spliced into (`--readme`). */
@@ -1,7 +1,21 @@
1
- const VALUE_KEYS = /* @__PURE__ */ new Set(["outDir", "file", "title", "language", "layout", "sort", "headingLevel", "readme"]);
2
- const BOOLEAN_KEYS = /* @__PURE__ */ new Set(["table"]);
1
+ const VALUE_KEYS = /* @__PURE__ */ new Set([
2
+ "outDir",
3
+ "file",
4
+ "title",
5
+ "language",
6
+ "layout",
7
+ "sort",
8
+ "headingLevel",
9
+ "typeColumn",
10
+ "defaultColumn",
11
+ "requiredStyle",
12
+ "readme"
13
+ ]);
14
+ const BOOLEAN_KEYS = /* @__PURE__ */ new Set(["table", "requiredFirst"]);
3
15
  const LAYOUTS = ["headings", "table", "none"];
4
16
  const SORTS = ["schema", "alphabetical"];
17
+ const TABLE_COLUMNS = ["auto", "always", "never"];
18
+ const REQUIRED_STYLES = ["marker", "column"];
5
19
  const toCamelCase = (key) => key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
6
20
  const parseChoice = (flag, value, choices) => {
7
21
  const match = choices.find((choice) => choice === value);
@@ -40,6 +54,15 @@ const assignValue = (args, key, value) => {
40
54
  case "headingLevel":
41
55
  args.headingLevel = parseHeadingLevel(value);
42
56
  return;
57
+ case "typeColumn":
58
+ args.typeColumn = parseChoice("type-column", value, TABLE_COLUMNS);
59
+ return;
60
+ case "defaultColumn":
61
+ args.defaultColumn = parseChoice("default-column", value, TABLE_COLUMNS);
62
+ return;
63
+ case "requiredStyle":
64
+ args.requiredStyle = parseChoice("required-style", value, REQUIRED_STYLES);
65
+ return;
43
66
  case "readme":
44
67
  args.readme = value;
45
68
  return;
@@ -78,7 +101,10 @@ const parseMarkdownArgs = (argv) => {
78
101
  const flagName = arg.slice(2);
79
102
  const key = toCamelCase(flagName);
80
103
  if (BOOLEAN_KEYS.has(key)) {
81
- args.table = true;
104
+ if (key === "requiredFirst")
105
+ args.requiredFirst = true;
106
+ else
107
+ args.table = true;
82
108
  continue;
83
109
  }
84
110
  if (!VALUE_KEYS.has(key))
@@ -6,7 +6,19 @@ const usageError = (message) => ({ code: 2, stdout: "", stderr: `Error: ${messag
6
6
  ` });
7
7
  const failure = (message) => ({ code: 1, stdout: "", stderr: `Error: ${message}
8
8
  ` });
9
- const PAGE_FLAGS = ["outDir", "file", "title", "language", "layout", "sort", "headingLevel"];
9
+ const PAGE_FLAGS = [
10
+ "outDir",
11
+ "file",
12
+ "title",
13
+ "language",
14
+ "layout",
15
+ "sort",
16
+ "headingLevel",
17
+ "typeColumn",
18
+ "defaultColumn",
19
+ "requiredStyle",
20
+ "requiredFirst"
21
+ ];
10
22
  const run = async (argv) => {
11
23
  let args;
12
24
  try {
@@ -51,7 +63,15 @@ const run = async (argv) => {
51
63
  language: args.language,
52
64
  layout: args.layout,
53
65
  sort: args.sort,
54
- headingLevel: args.headingLevel
66
+ headingLevel: args.headingLevel,
67
+ // Always passed: every member is optional, so the schema's own
68
+ // `x-doc.table` still decides whatever the flags left alone.
69
+ table: {
70
+ type: args.typeColumn,
71
+ default: args.defaultColumn,
72
+ required: args.requiredStyle,
73
+ requiredFirst: args.requiredFirst
74
+ }
55
75
  };
56
76
  let files;
57
77
  try {
@@ -4,6 +4,7 @@ const LIST_KEYS = /* @__PURE__ */ new Set(["allowedHosts", "allowedRoots"]);
4
4
  const BOOLEAN_KEYS = /* @__PURE__ */ new Set([
5
5
  "typesOnly",
6
6
  "validators",
7
+ "validatorsOnly",
7
8
  "check",
8
9
  "coerce",
9
10
  "repair",
@@ -128,6 +129,9 @@ const assignBoolean = (config, key, value) => {
128
129
  case "typesOnly":
129
130
  config.typesOnly = value;
130
131
  return true;
132
+ case "validatorsOnly":
133
+ config.validatorsOnly = value;
134
+ return true;
131
135
  case "validators":
132
136
  config.validators = value;
133
137
  return true;
@@ -1,4 +1,4 @@
1
- import type { Mode } from '@amritk/parsers';
1
+ import type { Mode } from '@amritk/validation';
2
2
  import type { CliConfig } from './cli-config.js';
3
3
  /**
4
4
  * Turns the flags a run was given into the list of entry points `generate()`
@@ -11,7 +11,9 @@ import type { CliConfig } from './cli-config.js';
11
11
  *
12
12
  * `--types-only` is the one run with nothing to execute, so it stops at `types`
13
13
  * — asking for a parser there would emit runtime code the flag exists to avoid.
14
- * Everything else always carries a parser, because emitting one is what the CLI
15
- * does when you do not tell it otherwise.
14
+ * `--validators-only` is its mirror at the other end: everything that judges a
15
+ * document, and nothing that builds one. Between them, every run carries a
16
+ * parser, because emitting one is what the CLI does when you do not tell it
17
+ * otherwise.
16
18
  */
17
19
  export declare const resolveModes: (config: Partial<CliConfig>) => Mode[];
@@ -2,7 +2,7 @@ const resolveModes = (config) => {
2
2
  if (config.typesOnly === true)
3
3
  return ["types"];
4
4
  const modes = ["types"];
5
- if (config.validators === true) {
5
+ if (config.validators === true || config.validatorsOnly === true) {
6
6
  modes.push("guard", "validate");
7
7
  if (config.check === true)
8
8
  modes.push("check");
@@ -11,7 +11,9 @@ const resolveModes = (config) => {
11
11
  if (config.repair === true)
12
12
  modes.push("repair");
13
13
  }
14
- modes.push(config.strict === true ? "parseStrict" : "parse");
14
+ if (config.validatorsOnly !== true) {
15
+ modes.push(config.strict === true ? "parseStrict" : "parse");
16
+ }
15
17
  return modes;
16
18
  };
17
19
  export {
@@ -8,6 +8,7 @@ const CONFIG_KEYS = {
8
8
  outDir: { type: "string" },
9
9
  outFile: { type: "string" },
10
10
  typesOnly: { type: "boolean" },
11
+ validatorsOnly: { type: "boolean" },
11
12
  validators: { type: "boolean" },
12
13
  check: { type: "boolean" },
13
14
  coerce: { type: "boolean" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/mjst",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -49,14 +49,14 @@
49
49
  "./package.json": "./package.json"
50
50
  },
51
51
  "dependencies": {
52
- "@amritk/adapters": "^0.6.4",
52
+ "@amritk/adapters": "^0.6.5",
53
53
  "@amritk/api": "^0.16.5",
54
- "@amritk/asyncapi": "^0.3.2",
55
- "@amritk/generate-examples": "^0.8.6",
56
- "@amritk/generate-markdown": "^0.8.0",
57
- "@amritk/helpers": "^0.23.0",
54
+ "@amritk/asyncapi": "^0.3.3",
55
+ "@amritk/generate-examples": "^0.8.7",
56
+ "@amritk/generate-markdown": "^0.9.0",
57
+ "@amritk/helpers": "^0.23.1",
58
58
  "@amritk/lint": "^0.6.1",
59
- "@amritk/parsers": "^0.2.0",
59
+ "@amritk/validation": "^0.3.0",
60
60
  "@amritk/resolve-refs": "^0.7.1",
61
61
  "@amritk/yaml": "^0.7.2",
62
62
  "fast-glob": "^3.3.2",