or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

abbreviation-extraction.mdconfiguration.mdcore-expansion.mdindex.mdmarkup-processing.mdstylesheet-processing.md
tile.json

markup-processing.mddocs/

Markup Processing

Specialized processing for markup abbreviations (HTML, XML, HAML, Pug, JSX) with comprehensive attribute handling and nested element support.

Capabilities

Markup Parsing and Expansion

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;

Core Data Structures

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>

Syntax-Specific Output

Emmet supports multiple markup syntaxes with syntax-specific formatting and conventions.

HTML Output

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" />

JSX Output

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} />

Pug Output

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 2

HAML Output

import { 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
//   .sidebar

Advanced Markup Features

BEM (Block Element Modifier) Support

import { 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>

Lorem Ipsum Generation

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>

Implicit Tag Names

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>

Text Content and Fields

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>

Parser Options and Behavior

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>