weml-monaco 0.3.2
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 +97 -0
- package/README.md +139 -0
- package/dist/formatter.d.ts +13 -0
- package/dist/generated/schema.d.ts +33 -0
- package/dist/index.d.ts +17 -0
- package/dist/language.d.ts +4 -0
- package/dist/providers/completion.d.ts +2 -0
- package/dist/providers/diagnostics.d.ts +3 -0
- package/dist/providers/documentSymbols.d.ts +2 -0
- package/dist/providers/hover.d.ts +2 -0
- package/dist/schema/docs.d.ts +13 -0
- package/dist/schema/entities.d.ts +35 -0
- package/dist/schema/snippets.d.ts +26 -0
- package/dist/schema/structureRules.d.ts +81 -0
- package/dist/toolbar/actions.d.ts +28 -0
- package/dist/toolbar/divRenumber.d.ts +12 -0
- package/dist/toolbar/toolbar.d.ts +27 -0
- package/dist/toolbar/wrap.d.ts +11 -0
- package/dist/weml-monaco.esm.js +31748 -0
- package/dist/weml-monaco.esm.js.map +7 -0
- package/dist/weml-monaco.js +31760 -0
- package/dist/weml-monaco.js.map +7 -0
- package/dist/wemlDocument.d.ts +20 -0
- package/package.json +42 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Changelog — WEML Monaco
|
|
2
|
+
|
|
3
|
+
All notable changes to the **Monaco** contribution (`weml-monaco`) are documented
|
|
4
|
+
here. The format is based on [Keep a Changelog](https://keepachangelog.com/), and
|
|
5
|
+
this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
This package mirrors the language logic of the VS Code extension; entries below
|
|
8
|
+
track the port catching up with the VS Code provider changes (see the root
|
|
9
|
+
`CHANGELOG.md` for the extension).
|
|
10
|
+
|
|
11
|
+
## [0.3.2] — 2026-08-13
|
|
12
|
+
|
|
13
|
+
Synced with VS Code extension `0.7.7`.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Switched canonical formatting to the safe V2 normalizer. Structurally invalid
|
|
17
|
+
input now produces a typed validation failure and no model edit instead of a
|
|
18
|
+
replacement containing an empty `<body>`.
|
|
19
|
+
- The HTML/pretty half of the format cycle remains usable after canonical
|
|
20
|
+
formatting is rejected, allowing users to repair invalid documents safely.
|
|
21
|
+
- Added browser/Monaco regressions for unclosed WEML containers, lists, tables,
|
|
22
|
+
inline elements and half-typed tags.
|
|
23
|
+
|
|
24
|
+
## [0.3.1] — 2026-08-12
|
|
25
|
+
|
|
26
|
+
Synced with VS Code extension `0.7.6`.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **Canonical formatting of void HTML elements is more robust.** Known void
|
|
30
|
+
tags are normalized before parsing, preventing earlier non-self-closing tags
|
|
31
|
+
from corrupting later markup.
|
|
32
|
+
- **Inline whitespace handling now respects element boundaries and comments.**
|
|
33
|
+
Edge-space bleeding uses parser-compatible sibling insertion and stops at
|
|
34
|
+
block or void elements instead of crossing structural boundaries.
|
|
35
|
+
|
|
36
|
+
## [0.3.0] — 2026-07-01
|
|
37
|
+
|
|
38
|
+
Ports the VS Code extension's toolbar and editor commands to Monaco.
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- **WEML toolbar** (`createWemlToolbar(monaco, editor, options)`) — a DOM top
|
|
42
|
+
panel with the same controls as the VS Code toolbar webview: a (stub) search
|
|
43
|
+
row, a "wrap selection" dropdown (`w-format` per text-formatting value, plus
|
|
44
|
+
`w-lang`, `w-non-egw`, `w-entity`, `a`), snippet buttons (`w-para`,
|
|
45
|
+
`w-heading`, `w-note`, `table`, `list`, `figure`) and "Renumber div ids (1…n)".
|
|
46
|
+
Mount it anywhere around the editor.
|
|
47
|
+
- **Editor actions / keybindings** (`registerWemlEditorActions`, also wired by
|
|
48
|
+
the toolbar): `Ctrl+B` / `Ctrl+I` / `Ctrl+U` wrap the selection in
|
|
49
|
+
`<w-format type="bold|italic|underline">`, `Alt+Shift+F` cycles the document
|
|
50
|
+
between HTML and canonical WEML formatting, plus a "Renumber <div> ids"
|
|
51
|
+
action. All are available in the command palette.
|
|
52
|
+
- Exposed the underlying operations (`wrapSelection`, `insertSnippetById`,
|
|
53
|
+
`renumberDivIds`, `cycleFormat`) and pure helpers (`planDivIdRenumber`,
|
|
54
|
+
`buildWrapSnippet`) for host/toolbar reuse and testing.
|
|
55
|
+
|
|
56
|
+
`planDivIdRenumber`/`buildWrapSnippet` are kept byte-identical to the VS Code
|
|
57
|
+
extension's `src/toolbar/*`; snippet insertion uses Monaco's `snippetController2`
|
|
58
|
+
so `$1`/`$2` tab stops behave like `editor.insertSnippet` in VS Code.
|
|
59
|
+
|
|
60
|
+
## [0.2.1] — 2026-06-20
|
|
61
|
+
|
|
62
|
+
Synced with VS Code extension `0.7.4`.
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
- **Hover tooltips for HTML character references (entities)** — named
|
|
66
|
+
(`—`, `'`, …), decimal (`—`) and hexadecimal (`—`)
|
|
67
|
+
references show name, rendered character and Unicode code point, in text and
|
|
68
|
+
inside attribute values.
|
|
69
|
+
- **Entity autocomplete** — typing `&` in text content or an attribute value
|
|
70
|
+
suggests named character references.
|
|
71
|
+
|
|
72
|
+
## [0.2.0] — 2026-06-20
|
|
73
|
+
|
|
74
|
+
Synced the completion/hover providers with VS Code extension `0.7.3`.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
- Completion is **strict and structure-aware**: only the tags allowed at the current
|
|
78
|
+
structural position are offered, with no generic HTML fallback noise in plain text.
|
|
79
|
+
- Tag completion inserts **only the opening tag** (e.g. `<w-format type="$1">`) — no
|
|
80
|
+
child scaffold or line breaks.
|
|
81
|
+
- Attribute-name completion inserts `name=""` and re-triggers the suggest widget
|
|
82
|
+
(`editor.action.triggerSuggest`) when the attribute has known values.
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
- Typing a tag name after `<` (e.g. `<w`) no longer empties the suggestion list:
|
|
86
|
+
items carry a `<`-aware `filterText`. Same fix for closing tags after `</`.
|
|
87
|
+
- Half-typed `<w-` elements are no longer mistaken for their own parent, so the
|
|
88
|
+
structural tag list is offered correctly.
|
|
89
|
+
- Closing tags after `</` are suggested explicitly based on the nearest open element.
|
|
90
|
+
- Removed the (now unused) plain-text node hover.
|
|
91
|
+
|
|
92
|
+
## [0.1.x] — initial port
|
|
93
|
+
|
|
94
|
+
Initial Monaco port of the WEML language support: language registration + Monarch
|
|
95
|
+
tokenizer, autocomplete, hover docs, structure diagnostics, document outline and
|
|
96
|
+
canonical formatting, plus a CDN demo and a smoke test. Parsing reuses
|
|
97
|
+
`vscode-html-languageservice`; Monaco is passed into `registerWeml(monaco)`.
|
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# WEML language support for Monaco
|
|
2
|
+
|
|
3
|
+
A Monaco-editor port of the WEML (White Estate Markup Language) VS Code
|
|
4
|
+
extension. It provides, for models with language id `weml`:
|
|
5
|
+
|
|
6
|
+
- **Syntax highlighting** — a Monarch tokenizer (HTML-flavoured, since WEML is
|
|
7
|
+
HTML5-compatible).
|
|
8
|
+
- **Context-aware autocomplete** — tags / attributes / attribute values that
|
|
9
|
+
respect the WEML nesting rules, with element-scaffolding snippets and
|
|
10
|
+
composite snippets (`table`, `w-list`, `figure`, `div + w-heading`, …).
|
|
11
|
+
- **Hover tooltips** — documentation generated from `docs/` (tags, attributes,
|
|
12
|
+
enum values, `meta` fields, `<a href>` link types).
|
|
13
|
+
- **Structure diagnostics** — unknown tags/attributes, required attributes,
|
|
14
|
+
enum values, child cardinality, `<a href>`/`id` rules, duplicate `<div id>`,
|
|
15
|
+
required `<meta>` in `<head>`; surfaced as editor markers.
|
|
16
|
+
- **Document outline** — by `<w-heading level=…>` and top-level `<div>`s.
|
|
17
|
+
- **Formatting** — "Format Document" runs the safe V2 canonical normalizer.
|
|
18
|
+
It validates matching/closed tags and text preservation before returning an
|
|
19
|
+
edit; invalid documents remain unchanged.
|
|
20
|
+
- **Toolbar & editor commands** — an optional DOM toolbar (top panel) plus
|
|
21
|
+
keybindings that mirror the VS Code extension: wrap selection in
|
|
22
|
+
`<w-format>`/other inlines, snippet buttons, "Renumber div ids", and a
|
|
23
|
+
HTML ↔ canonical format cycle.
|
|
24
|
+
|
|
25
|
+
This package does **not** modify the original VS Code extension — it is a
|
|
26
|
+
standalone re-implementation living entirely under `monaco-editor/`.
|
|
27
|
+
|
|
28
|
+
## Install & build
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd monaco-editor
|
|
32
|
+
npm install
|
|
33
|
+
npm run build # → dist/weml-monaco.js (IIFE global), .esm.js (ESM), *.d.ts
|
|
34
|
+
npm run typecheck # tsc --noEmit
|
|
35
|
+
npm test # build the ESM bundle + run the Node smoke test
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
Monaco is **passed in** at registration time, so this works no matter how
|
|
41
|
+
Monaco itself is loaded (AMD/CDN, ESM bundle, or a global):
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import * as monaco from 'monaco-editor';
|
|
45
|
+
import { registerWeml } from 'weml-monaco'; // or the bundled dist/weml-monaco.esm.js
|
|
46
|
+
|
|
47
|
+
const disposable = registerWeml(monaco);
|
|
48
|
+
|
|
49
|
+
const model = monaco.editor.createModel(source, 'weml');
|
|
50
|
+
monaco.editor.create(document.getElementById('container'), { model });
|
|
51
|
+
|
|
52
|
+
// disposable.dispose(); // tears down every provider + diagnostics listener
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`registerWeml(monaco, options?)` accepts:
|
|
56
|
+
|
|
57
|
+
| option | default | meaning |
|
|
58
|
+
| ---------------------- | ----------- | -------------------------------------------------- |
|
|
59
|
+
| `extensions` | `['.weml']` | file extensions associated with the language |
|
|
60
|
+
| `diagnostics` | `true` | wire live validation → `setModelMarkers` |
|
|
61
|
+
| `diagnosticsDebounceMs`| `300` | debounce for re-validating after edits |
|
|
62
|
+
|
|
63
|
+
Diagnostics are attached to every `weml` model automatically (on creation,
|
|
64
|
+
content change, and language switch) and cleared on disposal. To validate a
|
|
65
|
+
model on demand instead, call `validateWemlModel(monaco, model)` and feed the
|
|
66
|
+
returned `IMarkerData[]` to `monaco.editor.setModelMarkers`. To run the
|
|
67
|
+
formatter directly, call `formatWemlText(source)`.
|
|
68
|
+
Structural validation failures are also available through
|
|
69
|
+
`isWemlStructureValidationFailure(error)` and include a code, line and column.
|
|
70
|
+
|
|
71
|
+
## Toolbar & editor commands
|
|
72
|
+
|
|
73
|
+
Monaco has no webview panels, so the VS Code toolbar is ported as a **DOM top
|
|
74
|
+
panel** you mount yourself, plus per-editor actions/keybindings. Button
|
|
75
|
+
behaviour is identical to the VS Code toolbar.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { registerWeml, createWemlToolbar } from 'weml-monaco';
|
|
79
|
+
|
|
80
|
+
registerWeml(monaco);
|
|
81
|
+
const editor = monaco.editor.create(container, { model });
|
|
82
|
+
|
|
83
|
+
const toolbar = createWemlToolbar(monaco, editor, {
|
|
84
|
+
container: document.getElementById('weml-toolbar'), // where to mount the panel
|
|
85
|
+
onStatus: (msg) => console.log(msg), // optional status sink
|
|
86
|
+
// includeSearchRow: true, // stub search row (as in VS Code); default true
|
|
87
|
+
// onSearch: (query, lang) => { ... },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// toolbar.element → the toolbar DOM node
|
|
91
|
+
// toolbar.dispose() → removes the panel and its actions
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`createWemlToolbar` also registers the editor actions (so they work without the
|
|
95
|
+
panel too, via keybindings and the command palette):
|
|
96
|
+
|
|
97
|
+
| action / command | keybinding | effect |
|
|
98
|
+
| ------------------------- | ------------- | -------------------------------------------------- |
|
|
99
|
+
| `weml.wrapFormat.bold` | `Ctrl+B` | wrap selection in `<w-format type="bold">` |
|
|
100
|
+
| `weml.wrapFormat.italic` | `Ctrl+I` | wrap selection in `<w-format type="italic">` |
|
|
101
|
+
| `weml.wrapFormat.underline`| `Ctrl+U` | wrap selection in `<w-format type="underline">` |
|
|
102
|
+
| `weml.cycleFormat` | `Alt+Shift+F` | cycle document: HTML ↔ canonical WEML formatting |
|
|
103
|
+
| `weml.renumberDivIds` | — | renumber every `<div>` id to a sequential 1…n |
|
|
104
|
+
|
|
105
|
+
To register the actions without a toolbar, call
|
|
106
|
+
`registerWemlEditorActions(monaco, editor, options)`. The underlying operations
|
|
107
|
+
(`wrapSelection`, `insertSnippetById`, `renumberDivIds`, `cycleFormat`) and the
|
|
108
|
+
pure helpers (`planDivIdRenumber`, `buildWrapSnippet`) are exported too.
|
|
109
|
+
|
|
110
|
+
Snippet insertion uses Monaco's `snippetController2`, so `$1`/`$2` tab stops
|
|
111
|
+
behave like `editor.insertSnippet` in VS Code.
|
|
112
|
+
|
|
113
|
+
## Demo
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm run demo # bundles src/index.ts → demo/weml-monaco.js
|
|
117
|
+
# then open demo/index.html in a browser
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`demo/index.html` loads Monaco from a CDN (AMD loader) and the WEML bundle as a
|
|
121
|
+
global, registers the language and opens a sample document. Try Ctrl+Space for
|
|
122
|
+
completions, hover a tag, "Format Document", Ctrl+Shift+O for the outline, or
|
|
123
|
+
introduce an error to see diagnostics.
|
|
124
|
+
|
|
125
|
+
## How it relates to the VS Code extension
|
|
126
|
+
|
|
127
|
+
The schema and rules are reused verbatim from the extension:
|
|
128
|
+
|
|
129
|
+
| reused as-is | adapted for Monaco |
|
|
130
|
+
| ------------------------------------ | ---------------------------------------- |
|
|
131
|
+
| `generated/schema.ts` | `schema/docs.ts` (plain `IMarkdownString`) |
|
|
132
|
+
| `schema/structureRules.ts` | `wemlDocument.ts` (model ↔ LSP positions) |
|
|
133
|
+
| `schema/snippets.ts` | `providers/*` (Monaco provider APIs) |
|
|
134
|
+
| `wemlContentNormalizeV2.js` | `index.ts` (registration + diagnostics) |
|
|
135
|
+
|
|
136
|
+
Parsing still uses `vscode-html-languageservice` (it is editor-agnostic and
|
|
137
|
+
runs in the browser); the only real work was swapping the `vscode.*` provider
|
|
138
|
+
APIs for `monaco.languages.*` and converting between Monaco's 1-based
|
|
139
|
+
line/column positions and the language service's 0-based LSP positions.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface WemlNormalizationFailure extends Error {
|
|
2
|
+
code: string;
|
|
3
|
+
line?: number;
|
|
4
|
+
column?: number;
|
|
5
|
+
expectedTag?: string | null;
|
|
6
|
+
actualTag?: string | null;
|
|
7
|
+
}
|
|
8
|
+
/** Normalises a WEML document string into its canonical, reproducible form. */
|
|
9
|
+
export declare function formatWemlText(input: string): string;
|
|
10
|
+
export declare function isWemlNormalizationFailure(error: unknown): error is WemlNormalizationFailure;
|
|
11
|
+
export declare function isWemlStructureValidationFailure(error: unknown): error is WemlNormalizationFailure;
|
|
12
|
+
/** User-facing reason shown when canonical formatting is deliberately skipped. */
|
|
13
|
+
export declare function canonicalFormattingFailureMessage(error: unknown): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface EnumValue {
|
|
2
|
+
value: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
export interface EnumSchema {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
values: EnumValue[];
|
|
10
|
+
}
|
|
11
|
+
export interface AttributeSchema {
|
|
12
|
+
name: string;
|
|
13
|
+
required: boolean;
|
|
14
|
+
default?: string;
|
|
15
|
+
description: string;
|
|
16
|
+
enumRef?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface TagSchema {
|
|
19
|
+
tag: string;
|
|
20
|
+
description: string;
|
|
21
|
+
attributes: AttributeSchema[];
|
|
22
|
+
notes: string;
|
|
23
|
+
source: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MetaFieldSchema {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
enumRef?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const ENUMS: Record<string, EnumSchema>;
|
|
31
|
+
export declare const TAGS: Record<string, TagSchema>;
|
|
32
|
+
export declare const META_FIELDS: MetaFieldSchema[];
|
|
33
|
+
export declare const TEXT_NODE_DESCRIPTION: string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type * as monaco from 'monaco-editor';
|
|
2
|
+
export { WEML_LANGUAGE_ID } from './language';
|
|
3
|
+
export { canonicalFormattingFailureMessage, formatWemlText, isWemlNormalizationFailure, isWemlStructureValidationFailure, type WemlNormalizationFailure, } from './formatter';
|
|
4
|
+
export { validateWemlModel } from './providers/diagnostics';
|
|
5
|
+
export { createWemlToolbar, type WemlToolbar, type WemlToolbarOptions, } from './toolbar/toolbar';
|
|
6
|
+
export { registerWemlEditorActions, wrapSelection, insertSnippetById, renumberDivIds, cycleFormat, type WemlActionOptions, } from './toolbar/actions';
|
|
7
|
+
export { planDivIdRenumber, type IdEdit } from './toolbar/divRenumber';
|
|
8
|
+
export { buildWrapSnippet } from './toolbar/wrap';
|
|
9
|
+
export interface RegisterWemlOptions {
|
|
10
|
+
/** File extensions to associate with the language (default: [".weml"]). */
|
|
11
|
+
extensions?: string[];
|
|
12
|
+
/** Debounce for re-validating a model after edits, in ms (default: 300). */
|
|
13
|
+
diagnosticsDebounceMs?: number;
|
|
14
|
+
/** Set to false to skip live diagnostics/markers entirely (default: true). */
|
|
15
|
+
diagnostics?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function registerWeml(m: typeof monaco, options?: RegisterWemlOptions): monaco.IDisposable;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AttributeSchema } from '../generated/schema';
|
|
2
|
+
/** Mirrors `monaco.IMarkdownString` without taking a hard dependency on it. */
|
|
3
|
+
export interface Markdown {
|
|
4
|
+
value: string;
|
|
5
|
+
isTrusted?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function tagMarkdown(tag: string): Markdown;
|
|
8
|
+
export declare function attributeMarkdown(tag: string, attr: AttributeSchema): Markdown;
|
|
9
|
+
export declare function enumValueMarkdown(enumRef: string, value: string): Markdown | undefined;
|
|
10
|
+
export declare function enumValuesSummary(enumRef: string): string;
|
|
11
|
+
export declare function metaFieldMarkdown(name: string): Markdown | undefined;
|
|
12
|
+
export declare function entityMarkdown(reference: string): Markdown | undefined;
|
|
13
|
+
export declare function textNodeMarkdown(): Markdown;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface EntityInfo {
|
|
2
|
+
/** The character(s) the reference resolves to. */
|
|
3
|
+
char: string;
|
|
4
|
+
/** Human-readable name. */
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const NAMED_ENTITIES: Record<string, EntityInfo>;
|
|
8
|
+
export interface ResolvedEntity {
|
|
9
|
+
/** The full reference text, e.g. "—". */
|
|
10
|
+
reference: string;
|
|
11
|
+
/** The resolved character, or undefined for unknown named references. */
|
|
12
|
+
char?: string;
|
|
13
|
+
/** Human-readable name, when known. */
|
|
14
|
+
name?: string;
|
|
15
|
+
/** Unicode code point, when resolvable. */
|
|
16
|
+
codePoint?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Resolves a character reference (with surrounding `&` and `;`) to its details. */
|
|
19
|
+
export declare function resolveEntity(reference: string): ResolvedEntity | undefined;
|
|
20
|
+
export declare const ENTITY_COMPLETION_PRIORITY: string[];
|
|
21
|
+
/**
|
|
22
|
+
* If the cursor sits inside a partial entity being typed (`&`, `&md`, `R` …),
|
|
23
|
+
* returns the range to replace, including a trailing `;` if already present.
|
|
24
|
+
* Returns undefined when there is no `&`-initiated token before the cursor.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPartialEntityRange(text: string, offset: number): {
|
|
27
|
+
start: number;
|
|
28
|
+
end: number;
|
|
29
|
+
} | undefined;
|
|
30
|
+
/** Finds the character reference whose span contains `offset` within `text`. */
|
|
31
|
+
export declare function findEntityAt(text: string, offset: number): {
|
|
32
|
+
reference: string;
|
|
33
|
+
start: number;
|
|
34
|
+
end: number;
|
|
35
|
+
} | undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a `<tag ...>...</tag>` snippet body (including the opening `<`) for
|
|
3
|
+
* the given tag, with required attributes and required descendants filled
|
|
4
|
+
* in as placeholders. The `a` tag is special-cased: use
|
|
5
|
+
* `buildAnchorLinkSnippet`/`buildAnchorIdSnippet` instead.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildElementSnippet(tag: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Opening tag only, with required attributes as placeholders and no children or
|
|
10
|
+
* line breaks (e.g. `<w-format type="$1">`). Used by tag completion so accepting
|
|
11
|
+
* a suggestion inserts just the start tag; the closing tag is offered separately
|
|
12
|
+
* by the `</` completion.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildOpeningTag(tag: string): string;
|
|
15
|
+
/** `<a href="...">` variant — a link to another resource, may contain inline content. */
|
|
16
|
+
export declare function buildAnchorLinkSnippet(): string;
|
|
17
|
+
/** `<a id="...">` variant — a named anchor, must be empty. */
|
|
18
|
+
export declare function buildAnchorIdSnippet(): string;
|
|
19
|
+
export interface CompositeSnippet {
|
|
20
|
+
label: string;
|
|
21
|
+
detail: string;
|
|
22
|
+
/** Parent tags whose child slot this snippet is offered for, in addition to the plain tag completion. */
|
|
23
|
+
parents: string[];
|
|
24
|
+
body: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const COMPOSITE_SNIPPETS: CompositeSnippet[];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type NodeCategory = 'container' | 'block' | 'inline';
|
|
2
|
+
export declare const CONTAINER_TAGS: readonly ["w-para", "w-heading", "w-para-group", "w-toc"];
|
|
3
|
+
export declare const BLOCK_TAGS: readonly ["w-text-block", "figure", "w-list", "table", "hr"];
|
|
4
|
+
export declare const INLINE_TAGS: readonly ["a", "br", "w-entity", "w-format", "w-lang", "w-non-egw", "w-note", "w-page", "w-sent"];
|
|
5
|
+
export declare function categoryOf(tag: string): NodeCategory | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* A group of sibling children that share the same allowed tags and count.
|
|
8
|
+
* Every element child of a node must match exactly one group of its
|
|
9
|
+
* StructureRule; a child that matches no group is "not allowed here".
|
|
10
|
+
*/
|
|
11
|
+
export interface ChildGroup {
|
|
12
|
+
tags: string[];
|
|
13
|
+
min: number;
|
|
14
|
+
/** `null` means unbounded. */
|
|
15
|
+
max: number | null;
|
|
16
|
+
description: string;
|
|
17
|
+
}
|
|
18
|
+
export interface StructureRule {
|
|
19
|
+
children: ChildGroup[];
|
|
20
|
+
/** Whether non-whitespace text nodes are allowed as direct children. */
|
|
21
|
+
allowText?: boolean;
|
|
22
|
+
description: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const STRUCTURE_RULES: Record<string, StructureRule>;
|
|
25
|
+
export interface AttributeConstraint {
|
|
26
|
+
tag: string;
|
|
27
|
+
attribute: string;
|
|
28
|
+
kind: 'integer-range' | 'integer-min' | 'pattern';
|
|
29
|
+
min?: number;
|
|
30
|
+
max?: number;
|
|
31
|
+
/** Used when `kind === 'pattern'`. Empty values are always allowed. */
|
|
32
|
+
pattern?: RegExp;
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
/** Matches an arabic (`12`) or roman (`iii`, `XIV`) number. */
|
|
36
|
+
export declare const ARABIC_OR_ROMAN: RegExp;
|
|
37
|
+
export declare const ATTRIBUTE_CONSTRAINTS: AttributeConstraint[];
|
|
38
|
+
export interface MetaConstraint {
|
|
39
|
+
/** meta[name=...] this rule applies to. */
|
|
40
|
+
name: string;
|
|
41
|
+
kind: 'digits' | 'isbn';
|
|
42
|
+
message: string;
|
|
43
|
+
}
|
|
44
|
+
export declare const META_CONSTRAINTS: MetaConstraint[];
|
|
45
|
+
/** True for an empty string or a string consisting only of arabic digits. */
|
|
46
|
+
export declare function isDigitsOnly(value: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Validates an ISBN-10 or ISBN-13 by format and checksum. Hyphens and spaces
|
|
49
|
+
* are ignored. An empty string is considered valid (field simply unset).
|
|
50
|
+
*/
|
|
51
|
+
export declare function isValidIsbn(value: string): boolean;
|
|
52
|
+
export interface HrefLinkType {
|
|
53
|
+
id: string;
|
|
54
|
+
label: string;
|
|
55
|
+
regex: RegExp;
|
|
56
|
+
description: string;
|
|
57
|
+
example: string;
|
|
58
|
+
}
|
|
59
|
+
export declare const HREF_LINK_TYPES: HrefLinkType[];
|
|
60
|
+
export declare function isValidHref(href: string): boolean;
|
|
61
|
+
export declare const DOCUMENT_RULES: {
|
|
62
|
+
html: {
|
|
63
|
+
requiredAttributes: string[];
|
|
64
|
+
dirEnumRef: string;
|
|
65
|
+
defaultDir: string;
|
|
66
|
+
};
|
|
67
|
+
head: {
|
|
68
|
+
requiredMeta: {
|
|
69
|
+
name: string;
|
|
70
|
+
description: string;
|
|
71
|
+
}[];
|
|
72
|
+
metaTypeName: string;
|
|
73
|
+
metaTypeEnumRef: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Verifies that every tag name referenced by the rules above exists in the
|
|
78
|
+
* generated TAGS map, so a docs rename that forgets to update this file is
|
|
79
|
+
* caught at activation time instead of silently breaking completions.
|
|
80
|
+
*/
|
|
81
|
+
export declare function checkStructureRules(): string[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type * as monaco from 'monaco-editor';
|
|
2
|
+
export interface WemlActionOptions {
|
|
3
|
+
/** Optional sink for the short status messages the VS Code extension shows in the status bar. */
|
|
4
|
+
onStatus?: (message: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Wraps the current selection in `<tag [type=...]>…</tag>` (toolbar dropdown / hotkeys). */
|
|
7
|
+
export declare function wrapSelection(editor: monaco.editor.ICodeEditor, tag: string, type?: string): void;
|
|
8
|
+
/** Inserts a snippet by its toolbar-button id (composite label or plain tag). */
|
|
9
|
+
export declare function insertSnippetById(editor: monaco.editor.ICodeEditor, id: string): void;
|
|
10
|
+
/** Renumbers every `<div>` id in document order to a sequential 1..n. */
|
|
11
|
+
export declare function renumberDivIds(editor: monaco.editor.ICodeEditor, options?: WemlActionOptions): void;
|
|
12
|
+
/**
|
|
13
|
+
* Cycles the whole document between the standard HTML formatting (even steps) and
|
|
14
|
+
* the canonical WEML normalizer (odd steps). The step counter advances on every
|
|
15
|
+
* invocation, even when the formatter produces no change, so the cycle stays in
|
|
16
|
+
* sync — matching the VS Code `weml.cycleFormat` command.
|
|
17
|
+
*/
|
|
18
|
+
export declare function cycleFormat(editor: monaco.editor.ICodeEditor, options?: WemlActionOptions): void;
|
|
19
|
+
/**
|
|
20
|
+
* Registers the WEML editor actions on a specific editor instance: cycle-format
|
|
21
|
+
* (Alt+Shift+F), renumber div ids, and wrap-format bold/italic/underline
|
|
22
|
+
* (Ctrl+B / Ctrl+I / Ctrl+U). Returns an `IDisposable` that removes them.
|
|
23
|
+
*
|
|
24
|
+
* `editor.addAction` is per-editor (Monaco has no global command registry akin
|
|
25
|
+
* to the VS Code extension host), so call this for every WEML editor — or just
|
|
26
|
+
* use `createWemlToolbar`, which calls it for you.
|
|
27
|
+
*/
|
|
28
|
+
export declare function registerWemlEditorActions(m: typeof monaco, editor: monaco.editor.IStandaloneCodeEditor, options?: WemlActionOptions): monaco.IDisposable;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface IdEdit {
|
|
2
|
+
/** Replacement range in the source text (start === end means a pure insertion). */
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
newText: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Computes the edits needed to renumber every `<div>` id to its 1-based position
|
|
9
|
+
* in document order. Divs that already carry the right id produce no edit; a div
|
|
10
|
+
* without an `id` attribute gets one inserted right after the tag name.
|
|
11
|
+
*/
|
|
12
|
+
export declare function planDivIdRenumber(text: string): IdEdit[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as monaco from 'monaco-editor';
|
|
2
|
+
import { WemlActionOptions } from './actions';
|
|
3
|
+
export interface WemlToolbarOptions extends WemlActionOptions {
|
|
4
|
+
/** If given, the toolbar element is appended here. Otherwise it is only returned. */
|
|
5
|
+
container?: HTMLElement;
|
|
6
|
+
/** Include the (stub) search row, matching the VS Code toolbar. Default: true. */
|
|
7
|
+
includeSearchRow?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Handler for the search row. When omitted the row is a no-op stub (as in the
|
|
10
|
+
* VS Code extension). Receives the query text and the language code.
|
|
11
|
+
*/
|
|
12
|
+
onSearch?: (query: string, lang: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface WemlToolbar extends monaco.IDisposable {
|
|
15
|
+
/** The toolbar's root DOM element. */
|
|
16
|
+
element: HTMLElement;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Builds the WEML toolbar for a Monaco editor and wires every button to the same
|
|
20
|
+
* operations as the VS Code toolbar (wrap selection, snippet insertion, renumber
|
|
21
|
+
* div ids). Also registers the editor actions/keybindings (Ctrl+B/I/U,
|
|
22
|
+
* Alt+Shift+F, renumber) via `registerWemlEditorActions`.
|
|
23
|
+
*
|
|
24
|
+
* Returns the root element plus a `dispose()` that removes the toolbar and its
|
|
25
|
+
* actions.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createWemlToolbar(m: typeof monaco, editor: monaco.editor.IStandaloneCodeEditor, options?: WemlToolbarOptions): WemlToolbar;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Escapes text so it is inserted literally inside a SnippetString. */
|
|
2
|
+
export declare function escapeSnippet(text: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Builds a `<tag ...>SELECTION</tag>` snippet body for wrapping `selection`.
|
|
5
|
+
* - `type` (e.g. for `w-format`) fills `type="..."` directly.
|
|
6
|
+
* - `a` gets only `href="$1"` (it lists both href and id as required, but a
|
|
7
|
+
* wrapped selection is a link).
|
|
8
|
+
* - otherwise the tag's required attributes become `name="$1"` placeholders.
|
|
9
|
+
* An empty selection leaves a tab stop where the content goes.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildWrapSnippet(tag: string, type: string | undefined, selection: string): string;
|