@gmb/bitmark-parser 7.2.0 → 7.3.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/README.md +155 -23
- package/config/bitmark-json.tsp +330 -0
- package/config/bitmark.json +83394 -0
- package/dist/browser/bitmark-parser.min.js +6 -4
- package/dist/browser/bitmark-parser.min.js.map +1 -1
- package/dist/browser/cjs/index.cjs +140 -72
- package/dist/browser/cjs/index.cjs.map +1 -1
- package/dist/browser/cjs/index.d.cts +6286 -6806
- package/dist/browser/esm/index.d.ts +6286 -6806
- package/dist/browser/esm/index.js +139 -72
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/browser/esm/worker-entry.js +86 -57
- package/dist/browser/esm/worker-entry.js.map +1 -1
- package/dist/browser/wasm/bitmark_browser_full_wasm_bg.wasm +0 -0
- package/dist/browser/wasm/bitmark_json_wasm_bg.wasm +0 -0
- package/dist/browser/wasm/bitmark_wasm_bg.wasm +0 -0
- package/dist/index.cjs +76 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6286 -6806
- package/dist/index.d.ts +6286 -6806
- package/dist/index.js +75 -29
- package/dist/index.js.map +1 -1
- package/dist/legacy.cjs +4 -3
- package/dist/legacy.cjs.map +1 -1
- package/dist/legacy.d.cts +2 -1
- package/dist/legacy.d.ts +2 -1
- package/dist/legacy.js +4 -3
- package/dist/legacy.js.map +1 -1
- package/dist/worker-entry.cjs +23 -15
- package/dist/worker-entry.cjs.map +1 -1
- package/package.json +11 -7
- package/schema/bitmark.schema.json +10427 -14051
- package/wasm/bitmark_wasm.d.ts +12 -3
- package/wasm/bitmark_wasm.js +34 -15
- package/wasm/bitmark_wasm_bg.wasm +0 -0
- package/wasm/bitmark_wasm_bg.wasm.d.ts +2 -2
- package/wasm/package.json +1 -1
- package/wasm-bitmark-json/bitmark_json_wasm.d.ts +12 -3
- package/wasm-bitmark-json/bitmark_json_wasm.js +34 -15
- package/wasm-bitmark-json/bitmark_json_wasm_bg.wasm +0 -0
- package/wasm-bitmark-json/bitmark_json_wasm_bg.wasm.d.ts +2 -2
- package/wasm-bitmark-json/package.json +1 -1
- package/wasm-browser-full/bitmark_browser_full_wasm.d.ts +12 -3
- package/wasm-browser-full/bitmark_browser_full_wasm.js +34 -15
- package/wasm-browser-full/bitmark_browser_full_wasm_bg.wasm +0 -0
- package/wasm-browser-full/bitmark_browser_full_wasm_bg.wasm.d.ts +2 -2
- package/wasm-browser-full/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,9 +69,9 @@ runtime — the API surface never changes:
|
|
|
69
69
|
|
|
70
70
|
| Feature | Contents | Size (approx.) |
|
|
71
71
|
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
|
|
72
|
-
| `full` (Node default) | everything: rich `info` metadata + built-in translations + the semantic `diff` | ~
|
|
73
|
-
| `browser-full` (browser default) | the same conversions and `diff`, without either | ~
|
|
74
|
-
| `bitmark-json` | bitmark ↔ JSON only: `convert`/`canonicalize`/`transform` (formats `auto`/`bitmark`/`json`, plus the `text`, `semantic-tokens` and `diagnostics` outputs), the editor services, `info` (JSON only), breakscape, text fragments — no `diff` | ~
|
|
72
|
+
| `full` (Node default) | everything: rich `info` metadata + built-in translations + the semantic `diff` | ~1044 KB (~410 KB gzip) |
|
|
73
|
+
| `browser-full` (browser default) | the same conversions and `diff`, without either | ~855 KB (~353 KB gzip) |
|
|
74
|
+
| `bitmark-json` | bitmark ↔ JSON only: `convert`/`canonicalize`/`transform` (formats `auto`/`bitmark`/`json`, plus the `text`, `semantic-tokens` and `diagnostics` outputs), the editor services, `info` (JSON only), breakscape, text fragments — no `diff` | ~629 KB (~256 KB gzip) |
|
|
75
75
|
|
|
76
76
|
**The rule.** _Every build includes every feature, except the two
|
|
77
77
|
browser-targeted variants, which each carry an explicit exclusion list._ That
|
|
@@ -82,7 +82,7 @@ below:
|
|
|
82
82
|
| -------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
83
83
|
| native CLI, daemon, docgen, schemagen, wasm `full` | **all** |
|
|
84
84
|
| wasm `browser-full` | all **except** `info-meta` (bit + tag prose) and `translations` (the baked table) |
|
|
85
|
-
| wasm `bitmark-json` | all **except** the above and `markup`, `mapping-report`, `diff`, `lex
|
|
85
|
+
| wasm `bitmark-json` | all **except** the above and `markup`, `mapping-report`, `diff`, `lex` (with `ast`), `info-text` |
|
|
86
86
|
|
|
87
87
|
So, not in `bitmark-json`: the markup formats (`html`, `xml`,
|
|
88
88
|
`xml-niso-iec`, …) as input or output (they throw an `unsupported` error), the
|
|
@@ -192,9 +192,10 @@ Convert between bitmark, JSON, and the mapped markup formats (html/xml/…).
|
|
|
192
192
|
|
|
193
193
|
A JSON input may be an array or a single value, each entry a `{ bit: {…} }`
|
|
194
194
|
envelope (the forward output) or a bare bit object. An entry that is not a
|
|
195
|
-
bit produces no bitmark: it is skipped and reported as
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
bit produces no bitmark: it is skipped and reported as a `bit-invalid` issue
|
|
196
|
+
(or `bit-type-invalid` when it has a `type` the registry does not know) naming
|
|
197
|
+
its JSON path (`$[2] is not a bit: expected a bit object with "type" —
|
|
198
|
+
ignored`) on the warnings channel of the CLI (`--warnings`) and the daemon; the bits beside it
|
|
198
199
|
still convert, and a document in which nothing is a bit converts to empty
|
|
199
200
|
output. This `convert` returns a bare string and so cannot show the skip.
|
|
200
201
|
Only malformed JSON *text* throws (`invalid-json`).
|
|
@@ -202,7 +203,7 @@ Only malformed JSON *text* throws (`invalid-json`).
|
|
|
202
203
|
Options:
|
|
203
204
|
|
|
204
205
|
- `inputFormat` — `"auto"` (default), `"bitmark"`, `"json"`, or a mapping id (`"html"`, `"xml"`, …)
|
|
205
|
-
- `outputFormat` — `"auto"` (default: the opposite direction), `"text"` (lossy plain-text extraction; output-only), `"semantic-tokens"` / `"diagnostics"` / `"lex"` (output-only, bitmark input only — see their sections), or as above
|
|
206
|
+
- `outputFormat` — `"auto"` (default: the opposite direction), `"text"` (lossy plain-text extraction; output-only), `"semantic-tokens"` / `"diagnostics"` / `"lex"` / `"ast"` (output-only, bitmark input only — see their sections), or as above
|
|
206
207
|
- `mode` — `"optimized"` (default) or `"full"`
|
|
207
208
|
- `warnings` — include validation warnings (default: `false`)
|
|
208
209
|
- `plainText` — output text as plain text (default: `false`)
|
|
@@ -255,7 +256,7 @@ Options:
|
|
|
255
256
|
For bitmark input, output is a JSON array of entries with:
|
|
256
257
|
|
|
257
258
|
- `bit` — serialized bit payload
|
|
258
|
-
- `parser` — parser metadata, `errors` / `warnings`, and `infos` (informational notices for recoveries that are not necessarily wrong: text kept as text because it only looks like an unclosed tag, `unclosed
|
|
259
|
+
- `parser` — parser metadata, `errors` / `warnings`, and `infos` (informational notices for recoveries that are not necessarily wrong: text kept as text because it only looks like an unclosed tag, `tag-unclosed`, or a formatting mark with no partner, `formatting-unclosed` — in bitmark malformed markup is text, not an error). Each issue carries a stable machine-readable `code` (`"tag-invalid"`, `"tag-missing"`, …) and a `scope` (`"bit"`, `"card"`, `"bit-chain"` or `"card-chain"` — where the issue sits) beside its human-readable `message`, plus `text` and `location`. **Branch on `code` and `scope`** — a shipped code never changes meaning, whereas the message text is not contractual and may be reworded in any release. `bitmark info error-codes` lists every code with its severity and message template (see `info` below)
|
|
259
260
|
- `bitmark` — source bitmark text (a convenience echo; every bit is fully described by `bit` alone)
|
|
260
261
|
|
|
261
262
|
A region the parser could not read — an unknown bit type, or non-blank text
|
|
@@ -266,6 +267,17 @@ commented-out bit and any `:format` / `&resource` suffix; absent when there
|
|
|
266
267
|
was no header) and `body` (the raw text after it, as a plain string), so
|
|
267
268
|
generating bitmark from it reproduces the original region.
|
|
268
269
|
|
|
270
|
+
The other direction reports too. Going **to** bitmark (from JSON or from
|
|
271
|
+
markup), an inline mark that has no bitmark form is dropped — the forward
|
|
272
|
+
parser would not read it back as that mark, so writing it would corrupt the
|
|
273
|
+
surrounding text. The text it decorated is always kept, and the loss is
|
|
274
|
+
reported: `mark-dropped` when the whole mark goes, `mark-reduced` when it
|
|
275
|
+
survives in a lesser form (its value cleared, or one of its segments dropped).
|
|
276
|
+
Both arrive on the conversion's warnings, like every other issue. In practice
|
|
277
|
+
they are rare — a `href` holding a line terminator, a mark kind the grammar has
|
|
278
|
+
no tag for — so treat either as a signal that the JSON holds something bitmark
|
|
279
|
+
cannot express, not as routine noise.
|
|
280
|
+
|
|
269
281
|
#### canonicalize(input: string, options?: CanonicalizeOptions): string
|
|
270
282
|
|
|
271
283
|
Re-emit input in its own format in canonical form — the single same-format surface. `mode`: `"optimized"` (default, omit natural defaults) or `"full"` (all keys).
|
|
@@ -277,7 +289,17 @@ Apply a patch document to a document, bit by bit, and re-emit it.
|
|
|
277
289
|
|
|
278
290
|
- `patch` — a `PatchDocument`, or the shorthand: a bare array of entries
|
|
279
291
|
applied to every bit (build entries with `patchEntry`). Either form may be
|
|
280
|
-
a JSON string
|
|
292
|
+
a JSON string. An entry's `path` is in one of two languages, told apart by
|
|
293
|
+
its first character (one language per call; a mixed call is refused):
|
|
294
|
+
- a **JSON path** addresses the bit JSON (`title`,
|
|
295
|
+
`quizzes[0].choices[1].choice`, `table.data[1][1]`, `id[-1]`) and the
|
|
296
|
+
value is a JSON value;
|
|
297
|
+
- a **bitmark path** addresses the bit as an author writes it and the value
|
|
298
|
+
is bitmark source (see *Bitmark paths* below). Bitmark paths need
|
|
299
|
+
bitmark input
|
|
300
|
+
- a skipped entry — a bad path, an index out of range, a value the engine
|
|
301
|
+
refuses — **throws `PatchError`** (`diagnostics: { path, kind, message }[]`)
|
|
302
|
+
rather than returning a document with the edit silently missing
|
|
281
303
|
- `preHook` / `postHook` — per-bit hooks; the pre-hook may return patches, an
|
|
282
304
|
output-format override or `drop`. Hooks see the original bits, in order,
|
|
283
305
|
before the document reshapes anything; a hook's patches apply after the
|
|
@@ -286,13 +308,14 @@ Apply a patch document to a document, bit by bit, and re-emit it.
|
|
|
286
308
|
`spacesAroundValues` — as for `convert`. `outputFormat` (default `"json"`)
|
|
287
309
|
takes every per-bit format: `"json"`, `"bitmark"`, `"text"` or a mapping id
|
|
288
310
|
such as `"html"` (per-bit text outputs are joined with newlines). The
|
|
289
|
-
whole-document outputs `"lex"`, `"semantic-tokens"` and
|
|
290
|
-
refused with an `unsupported` error in every driver —
|
|
291
|
-
explicit `inputFormat` is honoured as given, patch or
|
|
292
|
-
never re-detected from the content
|
|
311
|
+
whole-document outputs `"lex"`, `"ast"`, `"semantic-tokens"` and
|
|
312
|
+
`"diagnostics"` are refused with an `unsupported` error in every driver —
|
|
313
|
+
use `convert`. An explicit `inputFormat` is honoured as given, patch or
|
|
314
|
+
hooks or not; it is never re-detected from the content
|
|
293
315
|
|
|
294
316
|
A patch document addresses bits by their position (or id) in the input
|
|
295
|
-
**before** any entry is applied, so it reads like a diff
|
|
317
|
+
**before** any entry is applied, so it reads like a diff. An inserted `bit`
|
|
318
|
+
is a JSON bit, or a string holding one bit of bitmark source:
|
|
296
319
|
|
|
297
320
|
```json
|
|
298
321
|
{
|
|
@@ -319,6 +342,53 @@ or `-1` for the document start. A bit may be the target of at most one
|
|
|
319
342
|
and moving it are all rejected, naming the second of the conflicting entries.
|
|
320
343
|
`diff` produces such a document from two versions of a file (below).
|
|
321
344
|
|
|
345
|
+
#### Bitmark paths
|
|
346
|
+
|
|
347
|
+
A bitmark path spells the thing it names the way an author writes it, so the
|
|
348
|
+
same path works for every bit type and no JSON key name is needed:
|
|
349
|
+
|
|
350
|
+
| Path | Addresses |
|
|
351
|
+
| --- | --- |
|
|
352
|
+
| `[@id]`, `[!]`, `[#]`, `[&image]` | the bit's first such tag; `[@id][-1]` the last, `[-][1]` the second `[-…]` |
|
|
353
|
+
| `[&image][@width]` | `[@width]` in the run after `[&image]` — a chain is spelled like the chain |
|
|
354
|
+
| `$body` | the bit's own text (tags, cards and footer untouched) |
|
|
355
|
+
| `$raw` | everything after the bit header |
|
|
356
|
+
| `$card[1]` | the whole second card; `$card[1][0]` its first side, `$card[1][0][1]` a variant |
|
|
357
|
+
| `$card[1][!]`, `$card[1][-][1]` | tags inside a card, by occurrence |
|
|
358
|
+
| `$card[1]$body`, `$card[1]$raw` | a card's own text / whole content |
|
|
359
|
+
| `$footer` | the `==== footer ====` section |
|
|
360
|
+
|
|
361
|
+
Values are bitmark source, breakscaped as an author would write it (a bare
|
|
362
|
+
`]` or a trailing `^` in a tag value is refused — use `breakscapeText` with
|
|
363
|
+
`location: "tag"` for user data, and add `subLocation: "attrValue"` when the
|
|
364
|
+
value is an inline-attr chain value such as a `link:` href); `null` is a
|
|
365
|
+
valueless tag (`[@x]`). The
|
|
366
|
+
four ops are the JSON engine's: `set` replaces a tag's value, a section's
|
|
367
|
+
content or a scope's text; `create` sets only when absent; `delete` removes
|
|
368
|
+
a tag (**a run head takes its whole run** — `[&image:u][@width:1]` minus
|
|
369
|
+
`[&image]` leaves nothing behind), a section, a body; `append` adds another
|
|
370
|
+
occurrence after the last one on its own line (`$card[1][-]` twice gives
|
|
371
|
+
white, green, blue, red), a sibling section after `$card[c]`, or a new last
|
|
372
|
+
card for a bare `$card`.
|
|
373
|
+
|
|
374
|
+
Every edit is a splice of the bit's own source: the parser's tree is the
|
|
375
|
+
address map, the rest of the bit keeps its formatting, and an edit that
|
|
376
|
+
would change the structure outside the addressed scope — a `==== text ====`
|
|
377
|
+
or `==== footer ====` that would swallow the cards after it, a bit header in
|
|
378
|
+
a value — is refused with the bit untouched. `convert(…, { outputFormat:
|
|
379
|
+
"ast" })` shows the tree a path resolves against.
|
|
380
|
+
|
|
381
|
+
```js
|
|
382
|
+
transform(doc, {
|
|
383
|
+
outputFormat: "bitmark",
|
|
384
|
+
patch: [
|
|
385
|
+
{ path: "$card[1][-]", op: "append", value: "green" },
|
|
386
|
+
{ path: "$card[0][!]", op: "set", value: "Milk (cold)" },
|
|
387
|
+
{ path: "$body", op: "set", value: "Think **twice**." },
|
|
388
|
+
],
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
322
392
|
#### diff(a: string, b: string, options?: DiffOptions): string
|
|
323
393
|
|
|
324
394
|
Semantic diff of two documents. Both sides are re-canonicalized and
|
|
@@ -458,10 +528,10 @@ const { positionEncoding, diagnostics: list } = diagnostics(source);
|
|
|
458
528
|
// list[i] = {
|
|
459
529
|
// range: { start: { line, character }, end: { line, character } }, // 0-based, UTF-16 units
|
|
460
530
|
// severity: 2, // DiagnosticSeverity.Warning
|
|
461
|
-
// code: "
|
|
531
|
+
// code: "tag-invalid", // the contract — branch on this
|
|
462
532
|
// source: "bitmark",
|
|
463
|
-
// message: "[@nope] is
|
|
464
|
-
// data: { bit: 0 },
|
|
533
|
+
// message: "[@nope] is not valid for [.article]", // prose, may change
|
|
534
|
+
// data: { bit: 0, scope: "bit" }, // the bit's index in the JSON array; the issue's scope
|
|
465
535
|
// }
|
|
466
536
|
```
|
|
467
537
|
|
|
@@ -552,7 +622,7 @@ offers the bit types). The CLI has the same three services under one
|
|
|
552
622
|
command: `bitmark editor diagnostics|complete|resolve|hover`. The contract is
|
|
553
623
|
`.zen/specs/API-EDT-editor-services.tsp`.
|
|
554
624
|
|
|
555
|
-
#### The `lex` output
|
|
625
|
+
#### The `lex` and `ast` output formats
|
|
556
626
|
|
|
557
627
|
`convert(input, { inputFormat: "bitmark", outputFormat: "lex" })` returns the
|
|
558
628
|
lexer's token stream as a JSON array: one `{ kind, span, text }` per token
|
|
@@ -563,19 +633,59 @@ so a highlighter should use `semantic-tokens` instead. Bitmark input only; a
|
|
|
563
633
|
JSON or markup document has no source text to lex. The former `lex()` export
|
|
564
634
|
and `bitmark lex` command were removed in 7.0 (see the migration guide).
|
|
565
635
|
|
|
636
|
+
`convert(input, { inputFormat: "bitmark", outputFormat: "ast" })` returns the
|
|
637
|
+
parser's tree as JSON — bits, their blocks (tag runs, body text, dividers)
|
|
638
|
+
and inlines, every node with its byte `span`. Debug tooling like `lex`: the
|
|
639
|
+
shape follows the parser and is not a contract. It shows what a bitmark
|
|
640
|
+
patch path addresses (a run is one `TagChain`; a card is what sits between
|
|
641
|
+
divider blocks). Not to be confused with the legacy entry point's "ast",
|
|
642
|
+
which is bit JSON. Bitmark input only; in the same builds as `lex`.
|
|
643
|
+
|
|
566
644
|
#### breakscapeText(input: string, options?: BreakscapeOptions): string
|
|
567
645
|
|
|
568
646
|
Breakscape text (escape bitmark special characters).
|
|
569
647
|
|
|
570
648
|
- `format` — `"bitmark++"` (default) or `"plainText"`
|
|
571
|
-
- `location` — `"body"` (default) or `"tag"`
|
|
649
|
+
- `location` — `"body"` (default), `"cardBody"` or `"tag"`
|
|
650
|
+
- `subLocation` — `"text"` (default) or `"attrValue"`
|
|
651
|
+
|
|
652
|
+
`subLocation` REFINES `location`, it does not replace it. `"attrValue"` means
|
|
653
|
+
the string is the value half of an inline-attr chain segment
|
|
654
|
+
(`==t==|link:VALUE|`): it adds the chain delimiter `|` to the escaped set and
|
|
655
|
+
drops the running-text rules (inline doubles, block markers), while `location`
|
|
656
|
+
keeps deciding the tag rules — a `[`+trigger is escaped in `body` and inert in
|
|
657
|
+
`tag`, a `]` is inert in `body` and escaped in `tag`.
|
|
658
|
+
|
|
659
|
+
`"cardBody"` is a card side or variant body. It has the `body` rules plus the
|
|
660
|
+
card dividers `--` and `++`, which are markup only inside a card set and only
|
|
661
|
+
at the start of a line, where they break to `-^-` and `+^+`.
|
|
662
|
+
|
|
663
|
+
Reach for `subLocation: "attrValue"` when building a chain value for the patch
|
|
664
|
+
API by hand; without it, an href containing `[@` cannot be written correctly.
|
|
665
|
+
|
|
666
|
+
```ts
|
|
667
|
+
breakscapeText("http://x/a[@b]", { location: "body", subLocation: "attrValue" });
|
|
668
|
+
// → "http://x/a[^@b]"
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Carets themselves follow one rule: **a literal `^` is written `^^` except with
|
|
672
|
+
`format: "plainText"` and `location: "body"`, where it is written `^`.** Three
|
|
673
|
+
cases land on the `^^` side although they read as though they would not — a tag
|
|
674
|
+
value in a plain-format bit (the `:text` suffix switches the body only), an
|
|
675
|
+
inline `code` mark (ordinary bitmark text carrying a mark), and an attr value
|
|
676
|
+
or bare URL. A `|code` *block* body is raw, but it has no public `format`: the
|
|
677
|
+
parser and generator apply that rule themselves at the block boundary.
|
|
572
678
|
|
|
573
679
|
#### unbreakscapeText(input: string, options?: BreakscapeOptions): string
|
|
574
680
|
|
|
575
681
|
Unbreakscape text (unescape bitmark special characters).
|
|
576
682
|
|
|
577
683
|
- `format` — `"bitmark++"` (default) or `"plainText"`
|
|
578
|
-
- `location` — `"body"` (default) or `"tag"`
|
|
684
|
+
- `location` — `"body"` (default), `"cardBody"` or `"tag"`
|
|
685
|
+
- `subLocation` — accepted and **ignored**
|
|
686
|
+
|
|
687
|
+
For `bitmark++` the rule is "remove one caret from each run" whatever the
|
|
688
|
+
context, so a single inverse undoes every breakscape mode.
|
|
579
689
|
|
|
580
690
|
#### info(options?: InfoOptions): string
|
|
581
691
|
|
|
@@ -588,7 +698,10 @@ defaults), JSON keys, per-context overrides, and the card set structure. `"depre
|
|
|
588
698
|
version and (separately) any migration target.
|
|
589
699
|
|
|
590
700
|
- `infoType` — `"list"` (default), `"bit"`, `"all"`, `"deprecated"`,
|
|
591
|
-
`"bit-groups"`, `"resource-groups"`, or `"
|
|
701
|
+
`"bit-groups"`, `"resource-groups"`, `"languages"`, or `"error-codes"`
|
|
702
|
+
(every issue code the parser can emit, with its severity and its message
|
|
703
|
+
templates per scope — `ErrorCodesInfo`; read from the validator's own
|
|
704
|
+
message table, so it is what the envelope emits, in every variant)
|
|
592
705
|
- `format` — `"text"` (default) or `"json"`
|
|
593
706
|
- `bit` — filter to a specific bit type (when `infoType` is `"bit"`)
|
|
594
707
|
- `pretty` — prettify JSON output (default: `false`)
|
|
@@ -791,6 +904,21 @@ with each release (the site root hosts the bitmark language docs), or build
|
|
|
791
904
|
it locally with `npm run docs` (→ `docs/api/`) and preview it with
|
|
792
905
|
`npm run docs:serve` (http://localhost:8080, `--port` to change).
|
|
793
906
|
|
|
907
|
+
### Resolved config document
|
|
908
|
+
|
|
909
|
+
The package ships the resolved bitmark configuration its parser was compiled
|
|
910
|
+
against — every bit type, tag group and card set with descriptions, formats,
|
|
911
|
+
defaults and mapping keys — as `bitmark.json`, with its TypeSpec contract
|
|
912
|
+
beside it:
|
|
913
|
+
|
|
914
|
+
```ts
|
|
915
|
+
import config from "@gmb/bitmark-parser/bitmark.json" with { type: "json" };
|
|
916
|
+
// contract: node_modules/@gmb/bitmark-parser/config/bitmark-json.tsp
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
It is generated by the build (`bitmark-confgen`) from the repo's jsonc config
|
|
920
|
+
tree, never hand-edited, and its `label` is a content hash of that tree.
|
|
921
|
+
|
|
794
922
|
### JSON Schema
|
|
795
923
|
|
|
796
924
|
The package also ships a JSON Schema (Draft 2020-12) describing the parser's
|
|
@@ -827,7 +955,7 @@ A tag whose configured format is `number` accepts what JavaScript's
|
|
|
827
955
|
|
|
828
956
|
`NaN`, `Infinity`, an exponent beyond ±4000, and a radix literal past 64 bits
|
|
829
957
|
are **rejected**: the tag is dropped from the output and a
|
|
830
|
-
`
|
|
958
|
+
`tag-value-invalid` warning names it, exactly like any other value that
|
|
831
959
|
does not fit its format.
|
|
832
960
|
|
|
833
961
|
Accepted values print in JavaScript's `JSON.stringify` form — `0.5`, `1.5`,
|
|
@@ -953,6 +1081,10 @@ bitmark convert input.bitmark --input-format bitmark --output-format lex --prett
|
|
|
953
1081
|
# Breakscape / unbreakscape text
|
|
954
1082
|
bitmark breakscape input.txt
|
|
955
1083
|
bitmark breakscape input.txt --format plainText --location tag
|
|
1084
|
+
# a card side / variant body, where the card dividers are live
|
|
1085
|
+
bitmark breakscape input.txt --location cardBody
|
|
1086
|
+
# a value for an inline-attr chain segment (==t==|link:VALUE|)
|
|
1087
|
+
bitmark breakscape input.txt --location body --sub-location attrValue
|
|
956
1088
|
bitmark unbreakscape input.txt
|
|
957
1089
|
|
|
958
1090
|
# Query bit type information
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bitmark.json — the resolved bitmark configuration document.
|
|
3
|
+
*
|
|
4
|
+
* `bitmark-confgen` resolves the hand-edited jsonc config tree
|
|
5
|
+
* (`resources/bitmark-configurator/config`) plus `manifest.jsonc` into this
|
|
6
|
+
* one document at build time (PLAN-144, PLAN-207). The parser's lookup tables,
|
|
7
|
+
* the JSON Schema, the TypeScript types and the docs site are all generated
|
|
8
|
+
* from it, and the npm package ships the exact document its parser was
|
|
9
|
+
* compiled against as `@gmb/bitmark-parser/bitmark.json`, with this file
|
|
10
|
+
* beside it as `@gmb/bitmark-parser/bitmark-json.tsp`.
|
|
11
|
+
*
|
|
12
|
+
* Prose spec with the derivation algorithms: `.zen/specs/BITMARK-JSON-FORMAT.md`.
|
|
13
|
+
* Shape source of truth: `crates/app/bitmark_confgen/src/model.rs` — any change
|
|
14
|
+
* there updates this file in the same PR.
|
|
15
|
+
*
|
|
16
|
+
* Conventions:
|
|
17
|
+
* - Identity is text. Root entities are keyed by name in sorted maps; every
|
|
18
|
+
* single-parent construct nests inside its owner. There are no numeric ids.
|
|
19
|
+
* - Optional members are omitted when absent, never `null`. Two exceptions:
|
|
20
|
+
* flag booleans (`bodyRequired`, `alwaysEmit`, …) are present only when
|
|
21
|
+
* `true`, and `TagDef.default` is `null` to mean "omit".
|
|
22
|
+
* - Arrays are in semantic (declaration) order; maps are sorted by key.
|
|
23
|
+
* - Derived members (`allTags`, `usedBy`, `parentOverrides`, `resources`) are
|
|
24
|
+
* computed by confgen, never authored.
|
|
25
|
+
*/
|
|
26
|
+
namespace BitmarkConfig;
|
|
27
|
+
|
|
28
|
+
/** A mapping-id → key-pattern record. Ids are registered in `mappingTypes`;
|
|
29
|
+
* a pattern is the verbatim authored JSON value (string, object or array of
|
|
30
|
+
* predicate records — see `crates/lib/jsonkey_parser/doc/`). */
|
|
31
|
+
model MappingKeys is Record<unknown>;
|
|
32
|
+
|
|
33
|
+
/** The document. */
|
|
34
|
+
model BitmarkJson {
|
|
35
|
+
/** App semver, from `manifest.jsonc` (kept in lockstep with the packages). */
|
|
36
|
+
version: string;
|
|
37
|
+
|
|
38
|
+
/** Provenance: `fnv1a64:<16 hex>` over every input file keyed by its
|
|
39
|
+
* config-relative path, plus the manifest. Independent of where the tree
|
|
40
|
+
* lives on disk; no wall clock. */
|
|
41
|
+
label: string;
|
|
42
|
+
|
|
43
|
+
/** Manifest order, verbatim. */
|
|
44
|
+
locales: Locale[];
|
|
45
|
+
|
|
46
|
+
/** Manifest order, verbatim. */
|
|
47
|
+
mappingTypes: MappingType[];
|
|
48
|
+
|
|
49
|
+
/** Bits by technical name (sorted). Abstract base definitions are absent. */
|
|
50
|
+
bits: Record<Bit>;
|
|
51
|
+
|
|
52
|
+
/** Tag groups by name (sorted). */
|
|
53
|
+
groups: Record<Group>;
|
|
54
|
+
|
|
55
|
+
/** Card sets by key (sorted). */
|
|
56
|
+
cardSets: Record<CardSet>;
|
|
57
|
+
|
|
58
|
+
/** Resource catalog by resource type (sorted); derived from the
|
|
59
|
+
* `resource-<type>` groups minus the manifest's `resourceUtilityGroups`. */
|
|
60
|
+
resources: Record<Resource>;
|
|
61
|
+
|
|
62
|
+
/** Bit-group registry by key (sorted). Metadata only: membership lives on
|
|
63
|
+
* each bit's `bitGroups`. */
|
|
64
|
+
bitGroups: Record<BitGroup>;
|
|
65
|
+
|
|
66
|
+
/** Resource-group registry by key (sorted). Here the member list is
|
|
67
|
+
* authoritative. */
|
|
68
|
+
resourceGroups: Record<ResourceGroup>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
model Locale {
|
|
72
|
+
/** BCP-47 language code, e.g. "en". */
|
|
73
|
+
code: string;
|
|
74
|
+
isBase: boolean;
|
|
75
|
+
/** English label, e.g. "English". */
|
|
76
|
+
label: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A registered mapping id and its representation type. */
|
|
80
|
+
model MappingType {
|
|
81
|
+
/** Mapping id used as a key in every `mappingKeys` record, e.g. "json". */
|
|
82
|
+
id: string;
|
|
83
|
+
|
|
84
|
+
/** Representation type: "json" | "html" | "xml" (open set); informational. */
|
|
85
|
+
type: string;
|
|
86
|
+
|
|
87
|
+
/** Parent mapping id: key lookups under this id fall back to the base
|
|
88
|
+
* (publisher overrides). */
|
|
89
|
+
`extends`?: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
model Bit {
|
|
93
|
+
description: string;
|
|
94
|
+
|
|
95
|
+
/** English display name; other languages come from `translations.json`.
|
|
96
|
+
* Absent when unauthored. */
|
|
97
|
+
title?: string;
|
|
98
|
+
|
|
99
|
+
/** Bit-group memberships, sorted — the single home of that fact. Omitted
|
|
100
|
+
* when the bit is deliberately ungrouped. */
|
|
101
|
+
bitGroups?: string[];
|
|
102
|
+
|
|
103
|
+
/** Author-facing usage notes, one bullet per entry; docs-only. */
|
|
104
|
+
usageNotes?: string[];
|
|
105
|
+
|
|
106
|
+
/** "bitmark" | "text" | "latex" | "json" | "xml". */
|
|
107
|
+
bodyFormat: string;
|
|
108
|
+
|
|
109
|
+
/** Flag booleans: present only when `true`. */
|
|
110
|
+
bodyRequired?: true;
|
|
111
|
+
bodyForbidden?: true;
|
|
112
|
+
footerRequired?: true;
|
|
113
|
+
footerForbidden?: true;
|
|
114
|
+
|
|
115
|
+
/** Version string at which the bit was deprecated; docs-only. */
|
|
116
|
+
deprecated?: string;
|
|
117
|
+
|
|
118
|
+
/** Migration target: engines re-emit input using this (deprecated) bit
|
|
119
|
+
* type under the named bit. */
|
|
120
|
+
migrateTo?: string;
|
|
121
|
+
|
|
122
|
+
/** "all" | "none". */
|
|
123
|
+
resourceAttachmentAllowed: string;
|
|
124
|
+
|
|
125
|
+
/** Required resource type (a key of `resources`); omitted when none. */
|
|
126
|
+
resourceRequired?: string;
|
|
127
|
+
|
|
128
|
+
/** Key of `cardSets`; omitted when the bit has no card set. */
|
|
129
|
+
cardSet?: string;
|
|
130
|
+
|
|
131
|
+
/** Bit-level named element keys for markup import; omitted when empty. */
|
|
132
|
+
mappingKeys?: MappingKeys;
|
|
133
|
+
|
|
134
|
+
/** Ordered declaration list: inline tag definitions and group references. */
|
|
135
|
+
tags: TagRef[];
|
|
136
|
+
|
|
137
|
+
/** Computed transitive closure of tags, as scoped keys, in declaration-DFS
|
|
138
|
+
* order with name dedup (first position kept, later declaration wins).
|
|
139
|
+
* A scoped key is `<kind>:<ownerPath>.<tag>` — `bit:article.#`,
|
|
140
|
+
* `group:article.#`, `variant:flashcard.default.question.1.@example` —
|
|
141
|
+
* and a chain child appends to its parent's key. */
|
|
142
|
+
allTags: string[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** One entry of a `tags` / `chain` array: an inline definition or a group
|
|
146
|
+
* reference, told apart by which of `tag` / `group` is present. */
|
|
147
|
+
union TagRef {
|
|
148
|
+
TagDef,
|
|
149
|
+
GroupRef,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
model TagDef {
|
|
153
|
+
/** Config key including its sigil (`@example`, `#`, `&image`, `%`, …) —
|
|
154
|
+
* the identity within the owner scope. */
|
|
155
|
+
tag: string;
|
|
156
|
+
|
|
157
|
+
description: string;
|
|
158
|
+
|
|
159
|
+
/** "string" | "bitmark+" | "boolean" | "number" | "numberList4" | "enum". */
|
|
160
|
+
format: string;
|
|
161
|
+
|
|
162
|
+
/** Enum vocabulary: present (non-empty, unique) exactly when `format` is
|
|
163
|
+
* "enum". */
|
|
164
|
+
values?: string[];
|
|
165
|
+
|
|
166
|
+
min: int64;
|
|
167
|
+
|
|
168
|
+
/** -1 = unlimited. */
|
|
169
|
+
max: int64;
|
|
170
|
+
|
|
171
|
+
/** Always present. `null` means OMIT: absence is the canonical state and a
|
|
172
|
+
* present value is never stripped nor an absent one materialised.
|
|
173
|
+
* Otherwise the format's natural value ("false" / "0" / "") or an
|
|
174
|
+
* authored non-natural value, which requires `alwaysEmit`. */
|
|
175
|
+
default: string | null;
|
|
176
|
+
|
|
177
|
+
/** Flag boolean: pin the key even in optimised mode, materialising the
|
|
178
|
+
* default when absent. */
|
|
179
|
+
alwaysEmit?: true;
|
|
180
|
+
|
|
181
|
+
/** Version string at which the tag was deprecated; docs-only. */
|
|
182
|
+
deprecated?: string;
|
|
183
|
+
|
|
184
|
+
/** Omitted when none. A `json` member may be the string "@ignore": the
|
|
185
|
+
* tag takes no value. */
|
|
186
|
+
mappingKeys?: MappingKeys;
|
|
187
|
+
|
|
188
|
+
/** Ordered chain children; omitted when empty. */
|
|
189
|
+
chain?: TagRef[];
|
|
190
|
+
|
|
191
|
+
/** Computed: overrides this tag receives from each parent context, sorted
|
|
192
|
+
* by (parentType, parent). Omitted when empty. */
|
|
193
|
+
parentOverrides?: ParentOverride[];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** A reference to a group, with optional link overrides. */
|
|
197
|
+
model GroupRef {
|
|
198
|
+
/** A key of `groups`. */
|
|
199
|
+
group: string;
|
|
200
|
+
mappingKeys?: MappingKeys;
|
|
201
|
+
min?: int64;
|
|
202
|
+
max?: int64;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
model ParentOverride {
|
|
206
|
+
/** "bit" | "group" | "tag" | "variant" (never "cardSet"). */
|
|
207
|
+
parentType: string;
|
|
208
|
+
|
|
209
|
+
/** Name (bit / group), variant path, or — for `tag` — the parent tag's
|
|
210
|
+
* scoped key (`group:person.@partner`). */
|
|
211
|
+
parent: string;
|
|
212
|
+
|
|
213
|
+
/** At least one of the three is present. */
|
|
214
|
+
mappingKeys?: MappingKeys;
|
|
215
|
+
min?: int64;
|
|
216
|
+
max?: int64;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
model Group {
|
|
220
|
+
description: string;
|
|
221
|
+
tags: TagRef[];
|
|
222
|
+
allTags: string[];
|
|
223
|
+
|
|
224
|
+
/** Computed reverse references; omitted when nothing references the group. */
|
|
225
|
+
usedBy?: UsedBy;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Reverse references; each member sorted lexicographically and omitted when
|
|
229
|
+
* empty. */
|
|
230
|
+
model UsedBy {
|
|
231
|
+
bits?: string[];
|
|
232
|
+
cardSets?: string[];
|
|
233
|
+
/** `<cardSetKey>.<cardName>.<sideName>.<variantIndex>` (1-based). */
|
|
234
|
+
variants?: string[];
|
|
235
|
+
groups?: string[];
|
|
236
|
+
/** Scoped keys (`group:person.@partner`) of the tags whose chains
|
|
237
|
+
* reference the group. */
|
|
238
|
+
tags?: string[];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
model CardSet {
|
|
242
|
+
mappingKeys?: MappingKeys;
|
|
243
|
+
|
|
244
|
+
/** Card-set-level references; omitted when empty. */
|
|
245
|
+
tags?: TagRef[];
|
|
246
|
+
allTags?: string[];
|
|
247
|
+
|
|
248
|
+
/** Bits using this card set, sorted; omitted when none. */
|
|
249
|
+
usedBy?: UsedBy;
|
|
250
|
+
|
|
251
|
+
/** Ordered. */
|
|
252
|
+
cards: Card[];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
model Card {
|
|
256
|
+
name: string;
|
|
257
|
+
isDefault: boolean;
|
|
258
|
+
|
|
259
|
+
/** 0 = no lower bound. */
|
|
260
|
+
min: int64;
|
|
261
|
+
|
|
262
|
+
/** 0 = unbounded (cards use 0, not -1). */
|
|
263
|
+
max: int64;
|
|
264
|
+
|
|
265
|
+
mappingKeys?: MappingKeys;
|
|
266
|
+
|
|
267
|
+
/** Ordered. */
|
|
268
|
+
sides: Side[];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
model Side {
|
|
272
|
+
name: string;
|
|
273
|
+
|
|
274
|
+
/** -1 = repeat forever; omitted when none. */
|
|
275
|
+
repeatCount?: int64;
|
|
276
|
+
|
|
277
|
+
mappingKeys?: MappingKeys;
|
|
278
|
+
|
|
279
|
+
/** Ordered; a variant's identity is its 1-based index. */
|
|
280
|
+
variants: Variant[];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
model Variant {
|
|
284
|
+
bodyFormat: string;
|
|
285
|
+
bodyRequired?: true;
|
|
286
|
+
bodyForbidden?: true;
|
|
287
|
+
|
|
288
|
+
/** -1 = infinite; omitted when none. */
|
|
289
|
+
repeatCount?: int64;
|
|
290
|
+
|
|
291
|
+
mappingKeys?: MappingKeys;
|
|
292
|
+
tags: TagRef[];
|
|
293
|
+
allTags: string[];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
model Resource {
|
|
297
|
+
/** Name of the defining `resource-<type>` group. */
|
|
298
|
+
group: string;
|
|
299
|
+
|
|
300
|
+
/** Component resource types of a composed resource; omitted when empty. */
|
|
301
|
+
composedOf?: string[];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** A search/filter category over bit types. Deliberately no member list:
|
|
305
|
+
* membership is authored per bit (`Bit.bitGroups`). */
|
|
306
|
+
model BitGroup {
|
|
307
|
+
/** English display name; other languages come from `translations.json`. */
|
|
308
|
+
title: string;
|
|
309
|
+
description: string;
|
|
310
|
+
|
|
311
|
+
/** Alternative keys accepted by lookups; omitted when empty. */
|
|
312
|
+
aliases?: string[];
|
|
313
|
+
|
|
314
|
+
/** Informational parent group; never implies membership. */
|
|
315
|
+
subgroupOf?: string;
|
|
316
|
+
|
|
317
|
+
/** Flag boolean: the group is allowed to have no members. */
|
|
318
|
+
allowEmpty?: true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** A search/filter category over resource types. The member list is the
|
|
322
|
+
* single home of that fact. */
|
|
323
|
+
model ResourceGroup {
|
|
324
|
+
title: string;
|
|
325
|
+
description: string;
|
|
326
|
+
aliases?: string[];
|
|
327
|
+
|
|
328
|
+
/** Member resource types, sorted; each is a key of `resources`. */
|
|
329
|
+
resourceTypes: string[];
|
|
330
|
+
}
|