CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-emmet

Essential toolkit for web developers providing abbreviation expansion for HTML and CSS

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

configuration.mddocs/

Configuration Management

Comprehensive configuration system with syntax-specific options, output formatting, and behavior customization.

Capabilities

Configuration Resolution

Core function for resolving user configuration with defaults and syntax-specific settings.

/**
 * Resolves user configuration with built-in defaults and syntax-specific settings
 * @param config - User-provided partial configuration
 * @returns Complete resolved configuration object
 */
function resolveConfig(config?: UserConfig): Config;

interface Config {
  /** Type of abbreviation: 'markup' or 'stylesheet' */
  type: SyntaxType;
  /** Target syntax (html, css, jsx, pug, etc.) */
  syntax: string;
  /** Complete configuration options */
  options: Options;
  /** Variable substitutions */
  variables: SnippetsMap;
  /** Custom snippet definitions */
  snippets: SnippetsMap;
  /** Context information for abbreviation resolution */
  context?: AbbreviationContext;
  /** Text content to wrap with abbreviation */
  text?: string | string[];
  /** Maximum repetition count for safety */
  maxRepeat?: number;
  /** Cache object for performance optimization */
  cache?: Cache;
  /** Warning/error callback */
  warn?: (message: string, err?: Error) => void;
}

interface UserConfig {
  type?: SyntaxType;
  syntax?: string;
  options?: Partial<Options>;
  variables?: SnippetsMap;
  snippets?: SnippetsMap;
  context?: AbbreviationContext;
  text?: string | string[];
  maxRepeat?: number;
  cache?: Cache;
  warn?: (message: string, err?: Error) => void;
}

type SyntaxType = 'markup' | 'stylesheet';

Basic Usage Examples:

import { resolveConfig, expand } from "emmet";

// Use defaults
const defaultConfig = resolveConfig();
console.log(defaultConfig.syntax); // "html"
console.log(defaultConfig.type);   // "markup"

// Specify syntax
const cssConfig = resolveConfig({ 
  type: "stylesheet",
  syntax: "css" 
});

// Custom options
const customConfig = resolveConfig({
  syntax: "html",
  options: {
    "output.indent": "  ",
    "output.selfClosingStyle": "xhtml"
  }
});

expand("input[type=email]", customConfig);
// Result: <input type="email" />

Configuration Data Types

Core Configuration Interfaces

interface AbbreviationContext {
  /** Context name or scope identifier */
  name: string;
  /** Optional context attributes */
  attributes?: { [name: string]: string | null };
}

interface SnippetsMap {
  [name: string]: string;
}

interface Cache {
  /** Cached stylesheet snippets for performance */
  stylesheetSnippets?: CSSSnippet[];
  /** Cached markup snippets for performance */
  markupSnippets?: { [name: string]: Abbreviation | null };
}

interface GlobalConfig {
  /** Syntax-specific configuration overrides */
  [syntax: string]: Partial<BaseConfig>;
}

interface BaseConfig {
  type: SyntaxType;
  options: Partial<Options>;
  variables: SnippetsMap;
  snippets: SnippetsMap;
}

Function Types

type FieldOutput = (
  index: number, 
  placeholder: string, 
  offset: number, 
  line: number, 
  column: number
) => string;

type TextOutput = (
  text: string, 
  offset: number, 
  line: number, 
  column: number
) => string;

type StringCase = '' | 'lower' | 'upper';

Options Interface

The Options interface contains 200+ configuration properties organized by category:

interface Options {
  /////////////////////
  // Generic options //
  /////////////////////
  
  /** List of inline-level elements */
  inlineElements: string[];

  ////////////////////
  // Output options //
  ////////////////////

  /** String for one level of indentation */
  "output.indent": string;
  /** Base indentation to add to all lines */
  "output.baseIndent": string;
  /** Newline character sequence */
  "output.newline": string;
  /** Case transformation for tag names */
  "output.tagCase": StringCase;
  /** Case transformation for attribute names */
  "output.attributeCase": StringCase;
  /** Quotes style for attribute values */
  "output.attributeQuotes": "single" | "double";
  /** Format style for self-closing tags */
  "output.selfClosingStyle": "html" | "xhtml" | "xml";
  /** Whether to add extra newlines for readability */
  "output.format": boolean;
  /** Whether to skip formatting for specific tags */
  "output.formatSkip": string[];
  /** Whether to force attribute value quotes */
  "output.formatForce": string[];
  /** Whether to compact boolean attributes */
  "output.compactBoolean": boolean;
  /** Whether to reverse attribute order */
  "output.reverseAttributes": boolean;
  /** Function for field/tabstop output */
  "output.field": FieldOutput;
  /** Function for text output */
  "output.text": TextOutput;

  ///////////////////
  // Markup options //
  ///////////////////

  /** Whether to auto-add href attributes */
  "markup.href": boolean;
  /** Attributes for specific elements */
  "markup.attributes": { [element: string]: string };
  /** Value sources for attributes */
  "markup.valuePrefix": { [attr: string]: string };

  /////////////////
  // JSX options //
  /////////////////

  /** Whether JSX mode is enabled */
  "jsx.enabled": boolean;

  /////////////////
  // BEM options //
  /////////////////

  /** Whether BEM naming is enabled */
  "bem.enabled": boolean;
  /** Separator between block and element */
  "bem.element": string;
  /** Separator for modifiers */
  "bem.modifier": string;

  //////////////////////
  // Stylesheet options //
  //////////////////////

  /** String between property and value */
  "stylesheet.between": string;
  /** String after each property */
  "stylesheet.after": string;
  /** Default unit for integer values */
  "stylesheet.intUnit": string;
  /** Default unit for float values */
  "stylesheet.floatUnit": string;
  /** Unit aliases mapping */
  "stylesheet.unitAliases": { [alias: string]: string };
  /** Properties that shouldn't have units */
  "stylesheet.unitless": string[];
  /** Available CSS keywords */
  "stylesheet.keywords": string[];
  /** Minimum score for fuzzy matching */
  "stylesheet.fuzzySearchMinScore": number;
  /** Use short hex colors when possible */
  "stylesheet.shortHex": boolean;
  /** Strict property matching mode */
  "stylesheet.strictMatch": boolean;

  ///////////////////////////
  // Comment options //
  ///////////////////////////

  /** Whether to add comments */
  "comment.enabled": boolean;
  /** Comment trigger character */
  "comment.trigger": string;
  /** Comment format for opening tags */
  "comment.before": string;
  /** Comment format for closing tags */
  "comment.after": string;
}

Syntax-Specific Configuration

Emmet provides built-in configuration for different syntaxes:

HTML Configuration

import { resolveConfig } from "emmet";

const htmlConfig = resolveConfig({ syntax: "html" });
// Built-in settings:
// - Self-closing style: HTML
// - Attribute quotes: double
// - Boolean attribute compacting: true
// - Inline elements list: a, abbr, acronym, etc.

XHTML Configuration

import { resolveConfig } from "emmet";

const xhtmlConfig = resolveConfig({ syntax: "xhtml" });
// Built-in settings:
// - Self-closing style: XHTML
// - All tags must be properly closed
// - Attribute quotes: required

JSX Configuration

import { resolveConfig } from "emmet";

const jsxConfig = resolveConfig({ syntax: "jsx" });
// Built-in settings:
// - JSX mode enabled
// - className instead of class
// - Self-closing style: XML
// - Expression attribute values: {value}

CSS Configuration

import { resolveConfig } from "emmet";

const cssConfig = resolveConfig({ 
  type: "stylesheet",
  syntax: "css" 
});
// Built-in settings:
// - Between: ": "
// - After: ";"
// - Int unit: "px"
// - Float unit: "em"

Advanced Configuration Examples

Custom Output Formatting

import { resolveConfig, expand } from "emmet";

const customFormat = resolveConfig({
  syntax: "html",
  options: {
    "output.indent": "\t",
    "output.newline": "\r\n",
    "output.tagCase": "upper",
    "output.attributeCase": "upper",
    "output.attributeQuotes": "single",
    "output.selfClosingStyle": "xhtml"
  }
});

expand("div.container>input[type=email required]", customFormat);
// Result: <DIV CLASS='container'>\r\n\t<INPUT TYPE='email' REQUIRED='' />\r\n</DIV>

Field and Text Output Functions

import { resolveConfig, expand } from "emmet";

const editorConfig = resolveConfig({
  syntax: "html",
  options: {
    "output.field": (index, placeholder, offset, line, column) => {
      return placeholder ? `\${${index}:${placeholder}}` : `\${${index}}`;
    },
    "output.text": (text, offset, line, column) => {
      return `<!--[${line}:${column}]-->${text}`;
    }
  }
});

expand("div>{Click $}+input[placeholder=${1:Enter text}]", editorConfig);
// Result: <div><!--[0:5]-->Click 1</div><input placeholder="${1:Enter text}">

BEM Configuration

import { resolveConfig, expand } from "emmet";

const bemConfig = resolveConfig({
  syntax: "html",
  options: {
    "bem.enabled": true,
    "bem.element": "__",
    "bem.modifier": "--"
  }
});

expand("div.block>div.-element+div.-element--modifier", bemConfig);
// Result: <div class="block"><div class="block__element"></div><div class="block__element block__element--modifier"></div></div>

Stylesheet Customization

import { resolveConfig, expand } from "emmet";

const stylusConfig = resolveConfig({
  type: "stylesheet",
  syntax: "stylus",
  options: {
    "stylesheet.between": " ",
    "stylesheet.after": "",
    "stylesheet.intUnit": "rem",
    "stylesheet.unitAliases": {
      "r": "rem",
      "v": "vw"
    }
  }
});

expand("w100v+h50r+m10", stylusConfig);
// Result: width 100vw\nheight 50rem\nmargin 10rem

Global Configuration

You can set up global configuration that applies to multiple syntaxes:

import { resolveConfig } from "emmet";

const globalConfig: GlobalConfig = {
  // Default settings for all markup syntaxes
  markup: {
    options: {
      "output.indent": "  ",
      "output.format": true
    }
  },
  // Default settings for all stylesheet syntaxes  
  stylesheet: {
    options: {
      "stylesheet.intUnit": "rem",
      "stylesheet.shortHex": true
    }
  },
  // HTML-specific overrides
  html: {
    options: {
      "output.selfClosingStyle": "xhtml"
    }
  },
  // JSX-specific overrides
  jsx: {
    options: {
      "jsx.enabled": true,
      "markup.attributes": {
        "class": "className",
        "for": "htmlFor"
      }
    }
  }
};

// Apply global config to specific syntax
const htmlConfig = resolveConfig({
  syntax: "html",
  options: globalConfig.html?.options
});

Performance Optimization with Caching

import { resolveConfig, expand } from "emmet";

// Create cache object for reuse across multiple expansions
const cache: Cache = {};

const config = resolveConfig({
  syntax: "html",
  cache: cache
});

// First expansion populates cache
expand("div>p*3", config);

// Subsequent expansions reuse cached data
expand("ul>li*5", config);
expand("table>tr*3>td*4", config);

// Cache contains parsed snippets and computed data
console.log(cache.markupSnippets); // Cached abbreviation objects

Error Handling Configuration

import { resolveConfig, expand } from "emmet";

const config = resolveConfig({
  syntax: "html",
  warn: (message, error) => {
    console.warn(`Emmet warning: ${message}`, error);
    // Could log to external service, show user notification, etc.
  }
});

// Invalid abbreviations will trigger warning callback
expand("div[unclosed-attribute", config);

Install with Tessl CLI

npx tessl i tessl/npm-emmet

docs

abbreviation-extraction.md

configuration.md

core-expansion.md

index.md

markup-processing.md

stylesheet-processing.md

tile.json