weml-monaco 0.5.1 → 0.6.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/CHANGELOG.md CHANGED
@@ -8,6 +8,28 @@ This package mirrors the language logic of the VS Code extension; entries below
8
8
  track the port catching up with the VS Code provider changes (see the root
9
9
  `CHANGELOG.md` for the extension).
10
10
 
11
+ ## [0.6.0] — 2026-10-06
12
+
13
+ ### Added
14
+ - `registerWemlWorker` (`weml-monaco/worker`) and the worker module
15
+ (`weml-monaco/weml.worker`): the same language with completion, hover, outline
16
+ and diagnostics computed in a Web Worker, so typing in a large document no
17
+ longer waits for a full parse per keystroke. The worker mirrors models from
18
+ their edits and answers only the current version of a model. `registerWeml`
19
+ and the global build are unchanged.
20
+
21
+ ## [0.5.2] — 2026-09-26
22
+
23
+ ### Added
24
+ - Support table `align`, hr `background`/`foreground`, paragraph `hash`,
25
+ `refcode-short`/`refcode-long`, and `original-id`/`hash` metadata in
26
+ completions, hover documentation and diagnostics.
27
+
28
+ ### Fixed
29
+ - Validate paragraph IDs as positive 32-bit integers and detect numerically
30
+ equivalent duplicate IDs, including leading zeros.
31
+ - Preserve multiline metadata descriptions and omit unspecified attribute defaults.
32
+
11
33
  ## [0.5.1] — 2026-09-26
12
34
 
13
35
  ### Changed
package/README.md CHANGED
@@ -99,6 +99,48 @@ formatter directly, call `formatWemlText(source)`.
99
99
  Structural validation failures are also available through
100
100
  `isWemlStructureValidationFailure(error)` and include a code, line and column.
101
101
 
102
+ ## Analysis in a Web Worker
103
+
104
+ `registerWeml` runs completion, hover, outline and diagnostics on the main
105
+ thread, and each of them parses the whole document for every new model version.
106
+ On a large file — a whole book, a megabyte and more — that is tens of
107
+ milliseconds per keystroke on the thread that handles the keystrokes, and typing
108
+ falls behind. `registerWemlWorker` registers the same language with that work in
109
+ a Web Worker:
110
+
111
+ ```ts
112
+ import * as monaco from 'monaco-editor/editor/editor.api.js';
113
+ import { registerWemlWorker } from 'weml-monaco/worker';
114
+ import WemlWorker from 'weml-monaco/weml.worker?worker'; // Vite
115
+
116
+ const disposable = registerWemlWorker(monaco, { worker: () => new WemlWorker() });
117
+ // Without Vite's `?worker`:
118
+ // registerWemlWorker(monaco, {
119
+ // worker: () => new Worker(new URL('weml-monaco/weml.worker', import.meta.url), { type: 'module' }),
120
+ // });
121
+ ```
122
+
123
+ It is an addition, not a replacement: `registerWeml` is unchanged, and an
124
+ application chooses one of the two (registering both doubles every provider).
125
+ The worker runs the very providers `registerWeml` registers, so suggestions,
126
+ hovers, outline and markers are the same; only where they are computed changes.
127
+
128
+ - The worker mirrors each `weml` model's text and keeps it current from the
129
+ edits Monaco reports — the main thread never sends the whole text again.
130
+ - A request is answered only for the model's current version: one overtaken by
131
+ further typing is answered empty without parsing, so holding a key down does
132
+ not build up a queue of parses.
133
+ - Markers computed for a version the model has since left are dropped.
134
+ - The tokenizer, language configuration and formatting stay on the main thread,
135
+ as with `registerWeml` — they are cheap or run on demand.
136
+ - `weml-monaco/weml.worker` imports nothing of Monaco at runtime; it needs a
137
+ bundler (or a module worker) to load, and is ESM only.
138
+
139
+ `registerWemlWorker(monaco, options)` takes the options of `registerWeml` plus
140
+ `worker`, a function that starts the worker (called once; the worker is
141
+ terminated on `dispose()`). The global `<script>` build (`index.global.js`) has
142
+ no worker variant.
143
+
102
144
  ## Toolbar & editor commands
103
145
 
104
146
  Monaco has no webview panels, so the VS Code toolbar is ported as a **DOM top
package/dist/index.cjs CHANGED
@@ -29473,8 +29473,19 @@ var TAGS = {
29473
29473
  },
29474
29474
  "hr": {
29475
29475
  "tag": "hr",
29476
- "description": "Represents a horizontal ruler. Has no attributes or other special meanings.",
29477
- "attributes": [],
29476
+ "description": "Represents a horizontal ruler with optional foreground and background colors.",
29477
+ "attributes": [
29478
+ {
29479
+ "name": "background",
29480
+ "required": false,
29481
+ "description": "Background color. See Colors."
29482
+ },
29483
+ {
29484
+ "name": "foreground",
29485
+ "required": false,
29486
+ "description": "Foreground color. See Colors."
29487
+ }
29488
+ ],
29478
29489
  "notes": "Usually displayed as an ornament or three centered asterisks.",
29479
29490
  "source": "blocks/hr.md"
29480
29491
  },
@@ -29768,7 +29779,14 @@ var TAGS = {
29768
29779
  "table": {
29769
29780
  "tag": "table",
29770
29781
  "description": "",
29771
- "attributes": [],
29782
+ "attributes": [
29783
+ {
29784
+ "name": "align",
29785
+ "required": false,
29786
+ "description": "Horizontal alignment of the table. See corresponding page for possible values",
29787
+ "enumRef": "horizontal-alignment"
29788
+ }
29789
+ ],
29772
29790
  "notes": "Contains optional `<thead>` and `<tbody>` sections. Both of them, if specfied, must\nhave at least one table row.\n\n`THEAD` element includes cells from the table header and `TBODY` represents actual\ntabular data.\n\nIs displayed as a table. Borderless or bordered, is determined by the client",
29773
29791
  "source": "blocks/table.md"
29774
29792
  },
@@ -30031,7 +30049,22 @@ var TAGS = {
30031
30049
  {
30032
30050
  "name": "id",
30033
30051
  "required": true,
30034
- "description": "Unique numeric ID of the paragraph within the document. Should be preserved between imports."
30052
+ "description": "Positive 32-bit integer ID (1\u20132147483647), unique within the document. Should be preserved between imports."
30053
+ },
30054
+ {
30055
+ "name": "hash",
30056
+ "required": false,
30057
+ "description": "Paragraph hash. Preserved without calculation or verification."
30058
+ },
30059
+ {
30060
+ "name": "refcode-short",
30061
+ "required": false,
30062
+ "description": "Short reference code."
30063
+ },
30064
+ {
30065
+ "name": "refcode-long",
30066
+ "required": false,
30067
+ "description": "Long reference code."
30035
30068
  },
30036
30069
  {
30037
30070
  "name": "data-skip",
@@ -30048,6 +30081,10 @@ var META_FIELDS = [
30048
30081
  "name": "pubid",
30049
30082
  "description": "Publication id. Must be unique for each publication."
30050
30083
  },
30084
+ {
30085
+ "name": "original-id",
30086
+ "description": "Original publication ID for a translation. Optional 32-bit integer, represented by `WemlDocumentHeader.OriginalId` (`int?`). Missing or unparseable WEML values are read as `null`."
30087
+ },
30051
30088
  {
30052
30089
  "name": "code",
30053
30090
  "description": "Publication short code."
@@ -30091,11 +30128,15 @@ var META_FIELDS = [
30091
30128
  },
30092
30129
  {
30093
30130
  "name": "purchase-link",
30094
- "description": "Purchase link."
30131
+ "description": "Absolute purchase URI."
30095
30132
  },
30096
30133
  {
30097
30134
  "name": "version-id",
30098
30135
  "description": "Publication version GUID."
30136
+ },
30137
+ {
30138
+ "name": "hash",
30139
+ "description": "Publication version hash."
30099
30140
  }
30100
30141
  ];
30101
30142
 
@@ -30598,7 +30639,9 @@ var ATTRIBUTE_CONSTRAINTS = [
30598
30639
  { tag: "td", attribute: "rowspan", kind: "integer-min", min: 1, message: "`rowspan` must be an integer >= 1." },
30599
30640
  { tag: "th", attribute: "colspan", kind: "integer-min", min: 1, message: "`colspan` must be an integer >= 1." },
30600
30641
  { tag: "th", attribute: "rowspan", kind: "integer-min", min: 1, message: "`rowspan` must be an integer >= 1." },
30601
- { tag: "div", attribute: "id", kind: "integer-min", min: 0, message: "`id` must be a non-negative integer, unique within the document." }
30642
+ { tag: "hr", attribute: "background", kind: "pattern", pattern: COLOR_VALUE, allowEmpty: false, message: "`background` must be a color in #RGB, #RGBA, #RRGGBB or #RRGGBBAA format." },
30643
+ { tag: "hr", attribute: "foreground", kind: "pattern", pattern: COLOR_VALUE, allowEmpty: false, message: "`foreground` must be a color in #RGB, #RGBA, #RRGGBB or #RRGGBBAA format." },
30644
+ { tag: "div", attribute: "id", kind: "integer-range", min: 1, max: 2147483647, pattern: /^\+?\d+$/, message: "`id` must be a positive 32-bit integer (1\u20132147483647), unique within the document." }
30602
30645
  ];
30603
30646
  var META_CONSTRAINTS = [
30604
30647
  { name: "pubid", kind: "digits", message: 'meta[name="pubid"] content must contain only digits.' },
@@ -31318,9 +31361,10 @@ function validateWemlModel(m, model) {
31318
31361
  const id = stripQuotes2(node.attributes?.["id"]);
31319
31362
  const range = attrs.get("id")?.valueRange ?? tagRange;
31320
31363
  if (id !== void 0) {
31321
- const list = divIds.get(id) ?? [];
31364
+ const key = /^\+?\d+$/.test(id.trim()) ? String(Number(id)) : id;
31365
+ const list = divIds.get(key) ?? [];
31322
31366
  list.push(range);
31323
- divIds.set(id, list);
31367
+ divIds.set(key, list);
31324
31368
  }
31325
31369
  }
31326
31370
  }
@@ -31334,7 +31378,7 @@ function validateWemlModel(m, model) {
31334
31378
  return;
31335
31379
  }
31336
31380
  const n = Number(info.value);
31337
- if (!Number.isInteger(n)) {
31381
+ if (!Number.isInteger(n) || constraint.pattern && !constraint.pattern.test(info.value.trim())) {
31338
31382
  push(info.valueRange, constraint.message, "error");
31339
31383
  return;
31340
31384
  }