Specialized processing for markup abbreviations (HTML, XML, HAML, Pug, JSX) with comprehensive attribute handling and nested element support.
Core functionality for parsing markup abbreviations into AST and converting to final output format.
/**
* Parses and expands markup abbreviation with specified configuration
* @param abbr - String abbreviation or pre-parsed Abbreviation object
* @param config - Complete configuration object with markup-specific settings
* @returns Expanded markup string in target format
*/
function markup(abbr: string | Abbreviation, config: Config): string;
/**
* Parses markup abbreviation into AST with transformations applied
* @param abbr - String abbreviation or pre-parsed Abbreviation object
* @param config - Configuration for parsing behavior
* @returns Processed abbreviation AST
*/
function parseMarkup(abbr: string | Abbreviation, config: Config): Abbreviation;
/**
* Converts abbreviation AST to string according to provided configuration
* @param abbr - Abbreviation AST to stringify
* @param config - Configuration for output formatting
* @returns Final markup string
*/
function stringifyMarkup(abbr: Abbreviation, config: Config): string;interface Abbreviation {
type: 'Abbreviation';
children: AbbreviationNode[];
}
interface AbbreviationNode {
type: 'AbbreviationNode';
/** Element tag name */
name?: string;
/** Text content values */
value?: Value[];
/** Repetition information */
repeat?: Repeater;
/** Element attributes */
attributes?: AbbreviationAttribute[];
/** Child elements */
children: AbbreviationNode[];
/** Whether element is self-closing */
selfClosing?: boolean;
}
interface AbbreviationAttribute {
/** Attribute name */
name?: string;
/** Attribute value components */
value?: Value[];
/** How the value should be quoted */
valueType: AttributeType;
/** Whether attribute is boolean (no value) */
boolean?: boolean;
/** Whether attribute was implied by snippet */
implied?: boolean;
/** Whether attribute accepts multiple values */
multiple?: boolean;
}
type AttributeType = 'raw' | 'singleQuote' | 'doubleQuote' | 'expression';
type Value = string | Field;
interface Field {
type: 'Field';
index: number;
name: string;
}
interface Repeater {
count: number;
value?: number;
text?: string;
}Basic Usage Examples:
import { markup, resolveConfig } from "emmet";
const config = resolveConfig({
syntax: "html",
type: "markup"
});
// Simple elements
markup("div", config);
// Result: <div></div>
markup("div>p*3", config);
// Result: <div><p></p><p></p><p></p></div>
// Elements with attributes
markup("input[type=email required]", config);
// Result: <input type="email" required="">
markup("a[href=# title='Link ${1:text}']", config);
// Result: <a href="#" title="Link text"></a>Emmet supports multiple markup syntaxes with syntax-specific formatting and conventions.
import { markup, resolveConfig } from "emmet";
const htmlConfig = resolveConfig({
syntax: "html",
options: {
"output.selfClosingStyle": "html", // or "xhtml"
"output.compactBoolean": false
}
});
markup("input[type=email required]", htmlConfig);
// Result: <input type="email" required="">
// With XHTML-style self-closing
const xhtmlConfig = resolveConfig({
syntax: "html",
options: { "output.selfClosingStyle": "xhtml" }
});
markup("input[type=email]", xhtmlConfig);
// Result: <input type="email" />import { markup, resolveConfig } from "emmet";
const jsxConfig = resolveConfig({
syntax: "jsx",
options: {
"jsx.enabled": true,
"markup.href": true
}
});
markup("div.container>h1{Hello}+input[type=text]", jsxConfig);
// Result: <div className="container"><h1>Hello</h1><input type="text" /></div>
// JSX with custom attributes
markup("CustomComponent[data-value={state.value} onClick={handler}]", jsxConfig);
// Result: <CustomComponent data-value={state.value} onClick={handler} />import { markup, resolveConfig } from "emmet";
const pugConfig = resolveConfig({
syntax: "pug",
options: {
"output.indent": " "
}
});
markup("div.container>h1{Title}+.content>p*2{Paragraph $}", pugConfig);
// Result:
// div.container
// h1 Title
// .content
// p Paragraph 1
// p Paragraph 2import { markup, resolveConfig } from "emmet";
const hamlConfig = resolveConfig({
syntax: "haml",
options: {
"output.indent": " "
}
});
markup("div#main.container>h1{Welcome}+.sidebar", hamlConfig);
// Result:
// #main.container
// %h1 Welcome
// .sidebarimport { markup, resolveConfig } from "emmet";
const bemConfig = resolveConfig({
syntax: "html",
options: {
"bem.enabled": true,
"bem.element": "__",
"bem.modifier": "_"
}
});
markup("div.block>div.-elem1+div.-elem2_mod", bemConfig);
// Result: <div class="block"><div class="block__elem1"></div><div class="block__elem2 block__elem2_mod"></div></div>import { markup, resolveConfig } from "emmet";
const config = resolveConfig({ syntax: "html" });
markup("p*3>lorem10", config);
// Result: Three paragraphs each with 10 lorem ipsum words
markup("div>h1{Title}+p>lorem", config);
// Result: <div><h1>Title</h1><p>Lorem ipsum dolor sit amet...</p></div>import { markup, resolveConfig } from "emmet";
const config = resolveConfig({ syntax: "html" });
// Implicit tag names based on parent context
markup("ul>.item*3", config);
// Result: <ul><li class="item"></li><li class="item"></li><li class="item"></li></ul>
markup("table>.row>.cell*3", config);
// Result: <table><tr class="row"><td class="cell"></td><td class="cell"></td><td class="cell"></td></tr></table>
markup("select>option[value=$]*3{Option $}", config);
// Result: <select><option value="1">Option 1</option><option value="2">Option 2</option><option value="3">Option 3</option></select>import { markup, resolveConfig } from "emmet";
const config = resolveConfig({
syntax: "html",
options: {
"output.field": (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`
}
});
// Text content with numbering
markup("ul>li*3{Item $}", config);
// Result: <ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
// Fields for editor integration
markup("form>input[name=${1:username}]+input[type=password name=${2:password}]", config);
// Result: <form><input name="${1:username}"><input type="password" name="${2:password}"></form>
// Text wrapping
const textConfig = resolveConfig({
syntax: "html",
text: ["Apple", "Banana", "Cherry"]
});
markup("ul>li*", textConfig);
// Result: <ul><li>Apple</li><li>Banana</li><li>Cherry</li></ul>interface ParserOptions {
/** Text to insert into abbreviation */
text?: string | string[];
/** Variable substitutions */
variables?: { [name: string]: string };
/** Maximum repetition count */
maxRepeat?: number;
/** Enable JSX mode */
jsx?: boolean;
/** Auto-add href attributes */
href?: boolean;
}Advanced Configuration Examples:
import { parseMarkup, stringifyMarkup, resolveConfig } from "emmet";
// Custom variables
const config = resolveConfig({
syntax: "html",
variables: {
charset: "utf-8",
lang: "en"
}
});
const abbr = parseMarkup("html[lang=${lang}]>head>meta[charset=${charset}]", config);
const result = stringifyMarkup(abbr, config);
// Result: <html lang="en"><head><meta charset="utf-8"></head></html>
// Custom snippets
const snippetConfig = resolveConfig({
syntax: "html",
snippets: {
"btn": "button.btn[type=button]{${1:Button}}",
"card": "div.card>div.card-header{${1:Header}}+div.card-body{${2:Content}}"
}
});
markup("card", snippetConfig);
// Result: <div class="card"><div class="card-header">Header</div><div class="card-body">Content</div></div>