|
| 1 | +# `jsonstat-validate` |
| 2 | + |
| 3 | +Command-line **semantic** validator for [JSON-stat](https://json-stat.org/) 2.0 — the CLI surface of the |
| 4 | +[`jsonstat-validator`](https://github.com/jsonstat/validator) family. It runs the |
| 5 | +[`@jsonstat-validator/ts`](https://www.npmjs.com/package/@jsonstat-validator/ts) engine under the hood: the |
| 6 | +official JSON Schema 2020-12 structural pass plus the cross-field cube invariants JSON Schema cannot express. |
| 7 | + |
| 8 | +> This CLI is one of four interchangeable surfaces (TS, Rust, Wasm, CLI) that all share **one** |
| 9 | +> [`rules-manifest.json`](https://github.com/jsonstat/validator/blob/main/rules-manifest.json) and **one** |
| 10 | +> [`corpus/cases.json`](https://github.com/jsonstat/validator/blob/main/corpus/cases.json), so they produce |
| 11 | +> identical findings on identical input. See the [monorepo README](https://github.com/jsonstat/validator#readme) |
| 12 | +> for the full architecture and [`DESIGN.md`](https://github.com/jsonstat/validator/blob/main/DESIGN.md) for the |
| 13 | +> design rationale. |
| 14 | +
|
| 15 | +--- |
| 16 | + |
| 17 | +## Why |
| 18 | + |
| 19 | +JSON Schema can validate *shape* (required properties, `oneOf`s, enums, the IANA link regex) but cannot express |
| 20 | +relationships like "`value` array length must equal the product of `size`". `jsonstat-validate` runs exactly those |
| 21 | +checks (the S/D/C catalogue) with a stable, versioned error-code vocabulary, and reports them in a CI-friendly |
| 22 | +text or JSON format. |
| 23 | + |
| 24 | +--- |
| 25 | + |
| 26 | +## Usage |
| 27 | + |
| 28 | +No install needed — run it once with `npx`: |
| 29 | + |
| 30 | +```bash |
| 31 | +# validate a file |
| 32 | +npx jsonstat-validate my-cube.json |
| 33 | + |
| 34 | +# validate JSON on stdin (note the `-`) |
| 35 | +echo '{"version":"2.0","class":"dataset","id":["x"],"size":[2],"dimension":{"x":{"category":{"index":["a","b"]}}},"value":[1]}' \ |
| 36 | + | npx jsonstat-validate - |
| 37 | + |
| 38 | +# machine-readable output for CI |
| 39 | +npx jsonstat-validate my-cube.json --format json |
| 40 | +``` |
| 41 | + |
| 42 | +``` |
| 43 | +$ npx jsonstat-validate my-cube.json |
| 44 | +valid: false |
| 45 | +summary: 1 errors, 0 warnings, 0 infos, 0 structural |
| 46 | + [error] VALUE_LEN_MISMATCH /value — Dense 'value' length 1 must equal product(size) = 2. |
| 47 | +``` |
| 48 | + |
| 49 | +**Exit code** is `0` when valid, `1` when invalid — drop it straight into a pipeline or pre-commit hook: |
| 50 | + |
| 51 | +```bash |
| 52 | +npx jsonstat-validate data/*.json || exit 1 |
| 53 | +``` |
| 54 | + |
| 55 | +### Or install globally |
| 56 | + |
| 57 | +```bash |
| 58 | +npm install -g jsonstat-validate |
| 59 | +jsonstat-validate my-cube.json |
| 60 | +``` |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Options |
| 65 | + |
| 66 | +``` |
| 67 | +jsonstat-validate <file|-> [options] |
| 68 | + --mode full|structural|semantic validation phases to run (default: full) |
| 69 | + --format json|text output format (default: text) |
| 70 | + --min-severity error|warning|info only show findings at/above this severity (default: info) |
| 71 | + --structural-only alias for --mode structural |
| 72 | + --semantic-only alias for --mode semantic |
| 73 | + -h, --help show usage |
| 74 | +``` |
| 75 | + |
| 76 | +| Flag | Values | Default | Notes | |
| 77 | +|---|---|---|---| |
| 78 | +| `<file\|->` | path or `-` | — | A path to a JSON file, or `-` to read JSON from stdin | |
| 79 | +| `--mode` | `full` \| `structural` \| `semantic` | `full` | Which passes to run | |
| 80 | +| `--format` | `json` \| `text` | `text` | `json` emits the full `ValidationResult` for scripting | |
| 81 | +| `--min-severity` | `error` \| `warning` \| `info` | `info` | Filters printed findings (does not affect the exit code) | |
| 82 | +| `--structural-only` | — | — | Shorthand for `--mode structural` | |
| 83 | +| `--semantic-only` | — | — | Shorthand for `--mode semantic` | |
| 84 | + |
| 85 | +`--min-severity` only affects which findings are *displayed*; it never changes the exit code, which is `0` iff the |
| 86 | +document has zero `error`-severity findings. |
| 87 | + |
| 88 | +### JSON output |
| 89 | + |
| 90 | +```bash |
| 91 | +npx jsonstat-validate my-cube.json --format json |
| 92 | +``` |
| 93 | + |
| 94 | +```jsonc |
| 95 | +{ |
| 96 | + "valid": false, |
| 97 | + "findings": [ |
| 98 | + { |
| 99 | + "code": "VALUE_LEN_MISMATCH", |
| 100 | + "ruleId": "S3", |
| 101 | + "severity": "error", |
| 102 | + "path": "/value", |
| 103 | + "message": "Dense 'value' length 1 must equal product(size) = 2.", |
| 104 | + "expected": 2, |
| 105 | + "actual": 1, |
| 106 | + "specRef": "wiki/format-specification.md" |
| 107 | + } |
| 108 | + ], |
| 109 | + "summary": { "errors": 1, "warnings": 0, "infos": 0, "structuralErrors": 0, "byCode": { "VALUE_LEN_MISMATCH": 1 } }, |
| 110 | + "meta": { "engineVersion": "0.1.1", "ruleSetVersion": "1.0.0", "schemaVersion": "1.05", "durationMs": 3 } |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +Structural (JSON Schema) violations are normalized into the **same** shape with `code: "STRUCTURAL_VIOLATION"` and |
| 115 | +the offending keyword kept in `meta` — so tooling only ever handles one finding shape. |
| 116 | + |
| 117 | +--- |
| 118 | + |
| 119 | +## Error codes |
| 120 | + |
| 121 | +See [`rules-manifest.json`](https://github.com/jsonstat/validator/blob/main/rules-manifest.json) for the |
| 122 | +authoritative, append-only catalogue. Codes include `VALUE_LEN_MISMATCH`, `SPARSE_KEY_OUT_OF_RANGE`, |
| 123 | +`STATUS_LEN_MISMATCH`, `DIM_KEY_ID_MISMATCH`, `ID_SIZE_LEN_MISMATCH`, `ROLE_ID_UNKNOWN`, |
| 124 | +`INDEX_COUNT_MISMATCH`, `INDEX_POSITIONS_INVALID`, `LABEL_KEY_UNKNOWN`, `LABEL_KEY_INCOMPLETE`, |
| 125 | +`UNIT_KEY_UNKNOWN`, `COORD_KEY_UNKNOWN`, `NOTE_KEY_UNKNOWN`, `CHILD_ID_UNKNOWN`, `CHILD_CYCLE`, |
| 126 | +`METRIC_UNIT_MISSING` (warning), `BUNDLE_DEPRECATED` (info), `RECURSION_LIMIT` (info), `CUBE_SIZE_OVERFLOW`, |
| 127 | +`BUDGET_EXCEEDED` (warning), `PARSE_ERROR`, and `STRUCTURAL_VIOLATION`. The vocabulary is versioned independently |
| 128 | +(`meta.ruleSetVersion`) from the package SemVer. |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +## Building from source |
| 133 | + |
| 134 | +```bash |
| 135 | +# from the monorepo root |
| 136 | +npm install # runs the `prepare` hook, which builds the CLI too |
| 137 | +npx jsonstat-validate --help |
| 138 | + |
| 139 | +# or, just this workspace |
| 140 | +cd cli |
| 141 | +npm run build # sync-license → esbuild bundle of src/cli.ts → dist/cli.js |
| 142 | +npm run dev # run directly from TypeScript: node --experimental-strip-types src/cli.ts |
| 143 | +``` |
| 144 | + |
| 145 | +The CLI is a thin wrapper around [`@jsonstat-validator/ts`](https://www.npmjs.com/package/@jsonstat-validator/ts); |
| 146 | +see [`src/cli.ts`](./src/cli.ts) for the argument parsing and output formatting. |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +## Related surfaces |
| 151 | + |
| 152 | +- **TypeScript / Node** — [`@jsonstat-validator/ts`](https://www.npmjs.com/package/@jsonstat-validator/ts) |
| 153 | +- **Rust** — [`jsonstat-validator`](https://crates.io/crates/jsonstat-validator) (`cargo add jsonstat-validator`) |
| 154 | +- **Wasm** — 🚧 in progress (see the monorepo [Roadmap](https://github.com/jsonstat/validator#roadmap)) |
| 155 | + |
| 156 | +--- |
| 157 | + |
| 158 | +## License |
| 159 | + |
| 160 | +Apache-2.0. |
0 commit comments