en Custom Tag Name Characters - chiba233/yumeDSL GitHub Wiki

Custom Tag Name Characters

Custom Syntax | Handler Helpers

Default tag name rules: a-z A-Z 0-9 _ -, first character can't be a digit or -. Want $$ui:button(...)$$ or $$v2.1(...)$$? Just tweak the tag name character rules.


What it looks like

Default rules:
  $$bold(ok)$$        ✅ works
  $$ui:button(ok)$$   ❌ colon not allowed → treated as plain text
  $$1tag(ok)$$        ❌ digit start not allowed → treated as plain text

With custom rules:
  $$ui:button(ok)$$   ✅ colon allowed
  $$1tag(ok)$$        ✅ digit start allowed

How to customize

Two functions tell the parser "which characters can appear in tag names":

Parser scans $$xxx( :
    │
    ├─ First char → isTagStartChar("x") → true? continue : skip
    │
    └─ Remaining chars → isTagChar("x") → true? continue : tag name ends here
interface TagNameConfig {
    isTagStartChar: (char: string) => boolean;  // what can start a tag name
    isTagChar: (char: string) => boolean;        // what can follow
}

Simplest approach: pass a partial object

Only specify what you want to change; unspecified functions use defaults:

const dsl = createParser({
    handlers,
    tagName: {
        isTagChar: (char) => /[A-Za-z0-9_-]/.test(char) || char === ":",
    },
});
// isTagStartChar not provided → uses default (a-z, A-Z, _)

Using createTagNameConfig wrapper

Exactly the same result, just an explicit merge:

import { createTagNameConfig } from "yume-dsl-rich-text";

tagName: createTagNameConfig({
    isTagChar: (char) => /[A-Za-z0-9_-]/.test(char) || char === ":",
})

Examples

Allow colon — namespaced tags ui:button

const dsl = createParser({
    handlers: {
        "ui:button": { inline: (value, ctx) => ({ type: "ui:button", value }) },
    },
    tagName: {
        isTagChar: (char) => /[A-Za-z0-9_-]/.test(char) || char === ":",
    },
});

dsl.parse("Click $$ui:button(Submit)$$");
// → [text("Click "), ui:button([text("Submit")])]

Allow digit start 1tag

parseRichText("$$1tag(hello)$$", {
    handlers: { "1tag": { inline: (v, ctx) => ({ type: "1tag", value: v }) } },
    tagName: { isTagStartChar: (char) => /[A-Za-z0-9_]/.test(char) },
});

Allow dots — version-style tags v2.1

const dsl = createParser({
    handlers: {
        "v2.1": { inline: (v, ctx) => ({ type: "version-note", version: "2.1", value: v }) },
    },
    tagName: createTagNameConfig({
        isTagStartChar: (char) => /[A-Za-z0-9_]/.test(char),
        isTagChar: (char) => /[A-Za-z0-9_.\-]/.test(char),
    }),
});

dsl.parse("See $$v2.1(release notes)$$");

Default values reference

Function Default accepts Role
isTagStartChar a-z A-Z _ First character of tag name
isTagChar a-z A-Z 0-9 _ - Remaining characters

Notes

  • tagName works on all parser entry points: createParser, parseRichText, stripRichText, parseStructural
  • Tag name validation only controls what the parser accepts. Unregistered tag names just degrade to plain text, no errors
  • createTagNameConfig is a pure function, no global state