npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

weml-monaco

v0.4.0

Published

WEML (White Estate Markup Language) language support for the Monaco editor: syntax highlighting, autocomplete, hover docs, structure diagnostics, outline and canonical formatting.

Readme

WEML language support for Monaco

A Monaco-editor port of the WEML (White Estate Markup Language) VS Code extension. It provides, for models with language id weml:

  • Syntax highlighting — a Monarch tokenizer (HTML-flavoured, since WEML is HTML5-compatible).
  • Context-aware autocomplete — tags / attributes / attribute values that respect the WEML nesting rules, with element-scaffolding snippets and composite snippets (table, w-list, figure, div + w-heading, …).
  • Hover tooltips — documentation generated from docs/ (tags, attributes, enum values, meta fields, <a href> link types).
  • Structure diagnostics — unknown tags/attributes, required attributes, enum values, child cardinality, <a href>/id rules, duplicate <div id>, required <meta> in <head>; surfaced as editor markers.
  • Document outline — by <w-heading level=…> and top-level <div>s.
  • Formatting — "Format Document" runs the safe V2 canonical normalizer. It validates matching/closed tags and text preservation before returning an edit; invalid documents remain unchanged.
  • Toolbar & editor commands — an optional DOM toolbar (top panel) plus keybindings that mirror the VS Code extension: wrap selection in <w-format>/other inlines, snippet buttons, "Renumber div ids", and a HTML ↔ canonical format cycle.

This package does not modify the original VS Code extension — it is a standalone re-implementation living entirely under monaco-editor/.

Install & build

npm install weml-monaco

The package has no runtime dependencies (node-html-parser and vscode-html-languageservice are bundled in) and monaco-editor is a peer dependency you already have.

| entry point | file | for | | ---------------------- | ----------------------- | -------------------------------------- | | weml-monaco | dist/index.mjs | ESM — bundlers, import | | weml-monaco | dist/index.cjs | CJS — require | | weml-monaco/global | dist/index.global.js | <script> / CDN → window.WemlMonaco |

Working on the package itself:

cd monaco-editor
npm install
npm run build          # tsup → dist/ (ESM + CJS + IIFE + declarations)
npm run typecheck      # tsc --noEmit
npm test               # build + Node smoke test
npm run check:package  # publint + arethetypeswrong on the packed tarball

Usage

Monaco is passed in at registration time, so this works no matter how Monaco itself is loaded (AMD/CDN, ESM bundle, or a global):

import * as monaco from 'monaco-editor';
import { registerWeml } from 'weml-monaco';

const disposable = registerWeml(monaco);

const model = monaco.editor.createModel(source, 'weml');
monaco.editor.create(document.getElementById('container'), { model });

// disposable.dispose();  // tears down every provider + diagnostics listener

registerWeml(monaco, options?) accepts:

| option | default | meaning | | ---------------------- | ----------- | -------------------------------------------------- | | extensions | ['.weml'] | file extensions associated with the language | | diagnostics | true | wire live validation → setModelMarkers | | diagnosticsDebounceMs| 300 | debounce for re-validating after edits |

Diagnostics are attached to every weml model automatically (on creation, content change, and language switch) and cleared on disposal. To validate a model on demand instead, call validateWemlModel(monaco, model) and feed the returned IMarkerData[] to monaco.editor.setModelMarkers. To run the formatter directly, call formatWemlText(source). Structural validation failures are also available through isWemlStructureValidationFailure(error) and include a code, line and column.

Toolbar & editor commands

Monaco has no webview panels, so the VS Code toolbar is ported as a DOM top panel you mount yourself, plus per-editor actions/keybindings. Button behaviour is identical to the VS Code toolbar.

import { registerWeml, createWemlToolbar } from 'weml-monaco';

registerWeml(monaco);
const editor = monaco.editor.create(container, { model });

const toolbar = createWemlToolbar(monaco, editor, {
  container: document.getElementById('weml-toolbar'), // where to mount the panel
  onStatus: (msg) => console.log(msg),                // optional status sink
  // includeSearchRow: true,   // stub search row (as in VS Code); default true
  // onSearch: (query, lang) => { ... },
});

// toolbar.element   → the toolbar DOM node
// toolbar.dispose()  → removes the panel and its actions

createWemlToolbar also registers the editor actions (so they work without the panel too, via keybindings and the command palette):

| action / command | keybinding | effect | | ------------------------- | ------------- | -------------------------------------------------- | | weml.wrapFormat.bold | Ctrl+B | wrap selection in <w-format type="bold"> | | weml.wrapFormat.italic | Ctrl+I | wrap selection in <w-format type="italic"> | | weml.wrapFormat.underline| Ctrl+U | wrap selection in <w-format type="underline"> | | weml.cycleFormat | Alt+Shift+F | cycle document: HTML ↔ canonical WEML formatting | | weml.renumberDivIds | — | renumber every <div> id to a sequential 1…n |

To register the actions without a toolbar, call registerWemlEditorActions(monaco, editor, options). The underlying operations (wrapSelection, insertSnippetById, renumberDivIds, cycleFormat) and the pure helpers (planDivIdRenumber, buildWrapSnippet) are exported too.

Snippet insertion uses Monaco's snippetController2, so $1/$2 tab stops behave like editor.insertSnippet in VS Code.

Demo

npm run demo        # builds dist/ and copies the IIFE bundle → demo/weml-monaco.js
# then open demo/index.html in a browser

demo/index.html loads Monaco from a CDN (AMD loader) and the WEML bundle as a global, registers the language and opens a sample document. Try Ctrl+Space for completions, hover a tag, "Format Document", Ctrl+Shift+O for the outline, or introduce an error to see diagnostics.

How it relates to the VS Code extension

The schema and rules are reused verbatim from the extension:

| reused as-is | adapted for Monaco | | ------------------------------------ | ---------------------------------------- | | generated/schema.ts | schema/docs.ts (plain IMarkdownString) | | schema/structureRules.ts | wemlDocument.ts (model ↔ LSP positions) | | schema/snippets.ts | providers/* (Monaco provider APIs) | | wemlContentNormalizeV2.js | index.ts (registration + diagnostics) |

Parsing still uses vscode-html-languageservice (it is editor-agnostic and runs in the browser); the only real work was swapping the vscode.* provider APIs for monaco.languages.* and converting between Monaco's 1-based line/column positions and the language service's 0-based LSP positions.