Essential toolkit for web developers providing abbreviation expansion for HTML and CSS
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Intelligent extraction of Emmet abbreviations from source code at specified positions, with support for prefix matching and auto-completion scenarios.
Extracts Emmet abbreviation from a line of text at a specified position, searching backward from the position to find abbreviation boundaries.
/**
* Extracts Emmet abbreviation from given string
* @param line - Text line where abbreviation should be extracted
* @param pos - Caret position in line (defaults to end of line)
* @param options - Extraction configuration options
* @returns Extracted abbreviation data or undefined if no abbreviation found
*/
function extract(
line: string,
pos?: number,
options?: Partial<ExtractOptions>
): ExtractedAbbreviation | undefined;
interface ExtractOptions {
/** Look ahead for auto-closed characters like quotes and brackets */
lookAhead: boolean;
/** Type of syntax context ('markup' or 'stylesheet') */
type: SyntaxType;
/** Required prefix that must precede the abbreviation */
prefix: string;
}
interface ExtractedAbbreviation {
/** The extracted abbreviation string */
abbreviation: string;
/** Character position where abbreviation starts */
location: number;
/** Start position including any prefix */
start: number;
/** End position of the abbreviation */
end: number;
}Basic Usage Examples:
import { extract } from "emmet";
// Extract from end of line
const result1 = extract("Hello world ul.tabs>li");
console.log(result1);
// { abbreviation: "ul.tabs>li", location: 12, start: 12, end: 23 }
// Extract from specific position
const result2 = extract("div.container ul>li", 15);
console.log(result2);
// { abbreviation: "ul>li", location: 14, start: 14, end: 19 }
// No abbreviation found
const result3 = extract("Just plain text here");
console.log(result3); // undefinedHandles auto-inserted closing characters that editors commonly add when typing.
interface ExtractOptions {
/**
* Allow parser to look ahead of position for missing abbreviation parts.
* Enabled by default to handle auto-inserted closing braces, quotes, etc.
*/
lookAhead: boolean;
}Look Ahead Examples:
import { extract } from "emmet";
const source = 'ul>li[title="Foo"]'; // Cursor after "Foo", before closing quote
const pos = 15; // Position after "Foo"
// With lookAhead enabled (default)
const result1 = extract(source, pos);
console.log(result1);
// { abbreviation: 'ul>li[title="Foo"]', location: 0, start: 0, end: 17 }
// With lookAhead disabled
const result2 = extract(source, pos, { lookAhead: false });
console.log(result2);
// { abbreviation: 'Foo', location: 12, start: 12, end: 15 }Determines how to interpret bracket characters based on markup vs stylesheet context.
interface ExtractOptions {
/**
* Type of context syntax of expanded abbreviation.
* In 'stylesheet' syntax, brackets [] and {} are not supported
*/
type: SyntaxType;
}
type SyntaxType = 'markup' | 'stylesheet';Syntax Type Examples:
import { extract } from "emmet";
const source = 'a{b}';
const pos = 3; // After "b"
// Markup context (default) - includes braces as text content
const markupResult = extract(source, pos, { type: 'markup' });
console.log(markupResult);
// { abbreviation: 'a{b}', location: 0, start: 0, end: 4 }
// Stylesheet context - braces not part of abbreviation syntax
const cssResult = extract(source, pos, { type: 'stylesheet' });
console.log(cssResult);
// { abbreviation: 'b', location: 2, start: 2, end: 3 }Requires abbreviation to be preceded by a specific prefix string, useful for preventing false positives in JSX and similar contexts.
interface ExtractOptions {
/**
* String that should precede abbreviation for successful extraction.
* Useful for avoiding conflicts with variable names in JSX/JS contexts.
*/
prefix: string;
}Prefix Examples:
import { extract } from "emmet";
const jsxSource1 = '() => div'; // Variable name, not abbreviation
const jsxSource2 = '() => <div'; // JSX tag, valid abbreviation
// Without prefix - finds 'div' in both cases
extract(jsxSource1, jsxSource1.length);
// { abbreviation: 'div', location: 6, start: 6, end: 9 }
extract(jsxSource2, jsxSource2.length);
// { abbreviation: 'div', location: 7, start: 7, end: 10 }
// With prefix - only finds 'div' when preceded by '<'
extract(jsxSource1, jsxSource1.length, { prefix: '<' });
// undefined (no match)
extract(jsxSource2, jsxSource2.length, { prefix: '<' });
// { abbreviation: 'div', location: 7, start: 6, end: 10 }The extract function is designed to work seamlessly with the main expand function for editor integration scenarios.
Complete Workflow Example:
import expand, { extract } from "emmet";
function expandAbbreviationAtCursor(sourceCode: string, cursorPos: number) {
// Extract abbreviation at cursor position
const extracted = extract(sourceCode, cursorPos, {
lookAhead: true,
type: 'markup',
prefix: '' // No prefix required
});
if (!extracted) {
return null; // No abbreviation found
}
// Expand the extracted abbreviation
const expanded = expand(extracted.abbreviation);
// Return replacement info
return {
expanded,
start: extracted.start,
end: extracted.end,
original: extracted.abbreviation
};
}
// Usage in editor context
const code = "const template = ul.nav>li*3";
const cursor = code.length; // At end of line
const result = expandAbbreviationAtCursor(code, cursor);
if (result) {
console.log(`Replace "${result.original}" with:`);
console.log(result.expanded);
// Replace "ul.nav>li*3" with:
// <ul class="nav"><li></li><li></li><li></li></ul>
}The extract function returns undefined when no valid abbreviation is found rather than throwing errors.
import { extract } from "emmet";
// Various cases that return undefined
console.log(extract("")); // Empty string
console.log(extract("just text")); // No abbreviation pattern
console.log(extract("div", 0, { prefix: "<" })); // Prefix not found
console.log(extract("a{", 2)); // Incomplete abbreviation
// Always check for undefined before using result
const source = "Some code here";
const result = extract(source, source.length);
if (result) {
console.log(`Found: ${result.abbreviation}`);
} else {
console.log("No abbreviation found");
}Install with Tessl CLI
npx tessl i tessl/npm-emmet