@metanorma/mirror

TypeScript library and Vue components for the Metanorma Mirror document format
12,868
Install
npm install @metanorma/mirror
Latest Version:0.1.1
Vue:3
License:BSD-3-Clause
Last Updated:Jul 20, 2026
Links: GitHub  ·  npm
Maintainer: riboseops

@metanorma/mirror

TypeScript library and optional Vue 3 components for the Metanorma Mirror document format — a JSON tree representation of standards documents (clauses, terms, tables, formulas, lists, etc.).

The library is framework-agnostic. The Vue layer is opt-in via a separate subpath export.

Install

npm install @metanorma/mirror

For the Vue components, Vue 3 (>=3.4) is a peer dependency:

npm install @metanorma/mirror vue

Entry points

Subpath Description
@metanorma/mirror Core types, traversal, mark registry, math helpers
@metanorma/mirror/vue <MirrorNode> and <MirrorText> Vue 3 components

Core usage

import {
  buildToc,
  findNodes,
  getNodeText,
  type MirrorDocument,
} from '@metanorma/mirror'

const doc: MirrorDocument = {
  type: 'doc',
  content: [
    {
      type: 'clause',
      attrs: { id: 'scope', title: 'Scope', number: '1' },
      content: [
        {
          type: 'paragraph',
          content: [
            { type: 'text', text: 'Hello ' },
            { type: 'text', text: 'world', marks: [{ type: 'strong' }] },
          ],
        },
      ],
    },
  ],
}

buildToc(doc)
// => [{ id: 'scope', title: '1 Scope', depth: 0 }]

findNodes(doc, n => n.type === 'paragraph').length
// => 1

getNodeText(doc)
// => 'Hello world'

Mark registry

Inline marks (strong, emphasis, link, xref, footnote, stem, …) are resolved through a registry. Built-ins can be overridden and custom marks can be added via registerMark:

import { registerMark, resolveMark } from '@metanorma/mirror'

registerMark('highlight', { tag: 'mark', classes: 'hl' })
resolveMark({ type: 'highlight' })
// => { tag: 'mark', classes: 'hl' }

getMarkHref extracts the URL from link and xref marks (reads attrs.target, falls back to attrs.href for link).

Math formulas

Formula nodes may carry pre-computed MathML in attrs.mathml, or AsciiMath in attrs.asciimath / attrs.math_text. renderFormula returns MathML when available, otherwise lazily converts AsciiMath → MathML via @plurimath/plurimath, falling back to the raw AsciiMath string if conversion fails.

import { renderFormula } from '@metanorma/mirror'

await renderFormula({ type: 'formula', attrs: { asciimath: 'E = mc^2' } })

Vue usage

<script setup lang="ts">
import { MirrorNode } from '@metanorma/mirror/vue'
import type { MirrorDocument } from '@metanorma/mirror'

const doc: MirrorDocument = /* … */
</script>

<template>
  <MirrorNode :node="doc" :depth="0" />
</template>

<MirrorNode> walks the node tree recursively and emits semantic HTML with mirror-<type> class names (e.g. mirror-paragraph, mirror-section, mirror-table). <MirrorText> renders a text node with the first matching mark as the appropriate HTML element (<strong>, <em>, <a>, <sub>, <sup>, etc.).

CSS is intentionally not bundled — apply your own styles to the .mirror-* classes, or override the component templates.

Node model

Every node shares the shape { type, attrs?, content?, marks?, text? }. Node types are partitioned into disjoint categories exported from the core:

  • STRUCTURAL_TYPES — doc, preface, sections, bibliography
  • SECTION_TYPES — clause, annex, terms, definitions, references, …
  • BLOCK_TYPES — paragraph, note, admonition, example, quote, formula, sourcecode, review
  • LIST_TYPES, TABLE_TYPES, MEDIA_TYPES, FOOTNOTE_TYPES, LEAF_TYPES

SECTION_TYPES is used by buildToc to decide which nodes become TOC entries.

Development

npm install
npm run build          # vite build → dist + .d.ts via vite-plugin-dts
npm run lint           # eslint
npm test               # vitest unit tests
npm run test:e2e       # puppeteer e2e
npm run test:all       # both suites

Requires Node.js 20+.

Releases

Releases are automated through .github/workflows/release.yml. A v* tag push, or a workflow_dispatch run with a version input, runs npm publish --provenance --access public --tag <dist-tag> and creates a GitHub release. The dist-tag is derived from the version (0.1.0 → latest, 0.1.0-beta.1 → beta, 0.9.0-rc.2 → rc).

Publishing uses npm's Trusted Publisher (OIDC) — no NPM_TOKEN secret is required. The npm package lists this repository's release.yml workflow as a Trusted Publisher, and the workflow carries permissions.id-token: write, which is what npm's OIDC exchange needs.

License

BSD-3-Clause — see LICENSE.

Related Packages

@enso-ui/documents

Document list widgets and card wrappers for Enso UI.

9,354 0
trinity-formula-editor

基于mirror的公式编辑器

1,612
vue-flext

A technology for building reliable document templates

3,963 1
vue-flag-icon

vue flag icon component

342,604 62
vue-flag-icon-2

vue flag icon component

4,441 63

Version History

Version Released License
0.1.1 BSD-3-Clause
0.1.0 BSD-3-Clause
Pre-releases (1)
Version Released License
0.1.0-beta.1 BSD-3-Clause