Socket
Socket
Sign inDemoInstall

lowlight

Package Overview
Dependencies
1
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.2.0 to 1.3.0

26

index.js

@@ -12,9 +12,7 @@ /**

/* eslint-env commonjs */
/* Expose. */
var low = module.exports = require('./lib/core.js');
var low = require('./lib/core.js');
/* jscs:disable maximumLineLength */
low.registerLanguage('1c', require('highlight.js/lib/languages/1c'));
low.registerLanguage('abnf', require('highlight.js/lib/languages/abnf'));
low.registerLanguage('accesslog', require('highlight.js/lib/languages/accesslog'));

@@ -34,2 +32,3 @@ low.registerLanguage('actionscript', require('highlight.js/lib/languages/actionscript'));

low.registerLanguage('avrasm', require('highlight.js/lib/languages/avrasm'));
low.registerLanguage('awk', require('highlight.js/lib/languages/awk'));
low.registerLanguage('axapta', require('highlight.js/lib/languages/axapta'));

@@ -47,2 +46,3 @@ low.registerLanguage('bash', require('highlight.js/lib/languages/bash'));

low.registerLanguage('coffeescript', require('highlight.js/lib/languages/coffeescript'));
low.registerLanguage('coq', require('highlight.js/lib/languages/coq'));
low.registerLanguage('cos', require('highlight.js/lib/languages/cos'));

@@ -63,4 +63,6 @@ low.registerLanguage('crmsh', require('highlight.js/lib/languages/crmsh'));

low.registerLanguage('dos', require('highlight.js/lib/languages/dos'));
low.registerLanguage('dsconfig', require('highlight.js/lib/languages/dsconfig'));
low.registerLanguage('dts', require('highlight.js/lib/languages/dts'));
low.registerLanguage('dust', require('highlight.js/lib/languages/dust'));
low.registerLanguage('ebnf', require('highlight.js/lib/languages/ebnf'));
low.registerLanguage('elixir', require('highlight.js/lib/languages/elixir'));

@@ -72,2 +74,3 @@ low.registerLanguage('elm', require('highlight.js/lib/languages/elm'));

low.registerLanguage('erlang', require('highlight.js/lib/languages/erlang'));
low.registerLanguage('excel', require('highlight.js/lib/languages/excel'));
low.registerLanguage('fix', require('highlight.js/lib/languages/fix'));

@@ -101,2 +104,3 @@ low.registerLanguage('fortran', require('highlight.js/lib/languages/fortran'));

low.registerLanguage('lasso', require('highlight.js/lib/languages/lasso'));
low.registerLanguage('ldif', require('highlight.js/lib/languages/ldif'));
low.registerLanguage('less', require('highlight.js/lib/languages/less'));

@@ -106,2 +110,3 @@ low.registerLanguage('lisp', require('highlight.js/lib/languages/lisp'));

low.registerLanguage('livescript', require('highlight.js/lib/languages/livescript'));
low.registerLanguage('lsl', require('highlight.js/lib/languages/lsl'));
low.registerLanguage('lua', require('highlight.js/lib/languages/lua'));

@@ -131,2 +136,3 @@ low.registerLanguage('makefile', require('highlight.js/lib/languages/makefile'));

low.registerLanguage('php', require('highlight.js/lib/languages/php'));
low.registerLanguage('pony', require('highlight.js/lib/languages/pony'));
low.registerLanguage('powershell', require('highlight.js/lib/languages/powershell'));

@@ -161,4 +167,7 @@ low.registerLanguage('processing', require('highlight.js/lib/languages/processing'));

low.registerLanguage('stylus', require('highlight.js/lib/languages/stylus'));
low.registerLanguage('subunit', require('highlight.js/lib/languages/subunit'));
low.registerLanguage('swift', require('highlight.js/lib/languages/swift'));
low.registerLanguage('taggerscript', require('highlight.js/lib/languages/taggerscript'));
low.registerLanguage('yaml', require('highlight.js/lib/languages/yaml'));
low.registerLanguage('tap', require('highlight.js/lib/languages/tap'));
low.registerLanguage('tcl', require('highlight.js/lib/languages/tcl'));

@@ -180,9 +189,2 @@ low.registerLanguage('tex', require('highlight.js/lib/languages/tex'));

low.registerLanguage('xquery', require('highlight.js/lib/languages/xquery'));
low.registerLanguage('yaml', require('highlight.js/lib/languages/yaml'));
low.registerLanguage('zephir', require('highlight.js/lib/languages/zephir'));
/*
* Expose.
*/
module.exports = low;

@@ -12,26 +12,28 @@ /**

/* eslint-env commonjs */
/* Dependencies. */
var high = require('highlight.js/lib/highlight.js');
/*
* Dependencies.
*/
/* The lowlight interface, which has to be compatible
* with highlight.js, as this object is passed to
* highlight.js syntaxes. */
var high = require('highlight.js/lib/highlight.js');
/** High constructor. */
function High() {}
/*
* Methods.
*/
High.prototype = high;
var inherit = high.inherit;
/* Expose. */
var low = new High(); // Ha!
/*
* Low - Populated later.
*/
module.exports = low;
var low;
low.highlight = highlight;
low.highlightAuto = autoHighlight;
low.registerLanguage = registerLanguage;
low.getLanguage = getLanguage;
/*
* Constants.
*/
/* Methods. */
var inherit = high.inherit;
/* Constants. */
var DEFAULT_PREFIX = 'hljs-';

@@ -41,13 +43,7 @@ var KEY_INSENSITIVE = 'case_insensitive';

/*
* Constant characters.
*/
/* Constant characters. */
var C_SPACE = ' ';
var C_PIPE = '|';
/*
* Constant types.
*/
/* Constant types. */
var T_ELEMENT = 'element';

@@ -57,6 +53,3 @@ var T_TEXT = 'text';

/*
* Maps of syntaxes.
*/
/* Maps of syntaxes. */
var languageNames = [];

@@ -66,229 +59,86 @@ var languages = {};

/**
* Get a language by `name`.
*
* @private
* @param {string} name - Name or alias of language.
* @return {Object?} - Syntax.
*/
function getLanguage(name) {
name = name.toLowerCase();
/* Methods. */
var own = {}.hasOwnProperty;
return languages[name] || languages[aliases[name]];
}
/**
* No-op exec.
* Highlighting with language detection. Accepts a string
* with the code to highlight. Returns an object with the
* following properties:
*
* @private
* @return {null} - Void result.
*/
function execNoop() {
return null;
}
/**
* Check.
* - language (detected language)
* - relevance (int)
* - value (an HTML string with highlighting markup)
* - secondBest (object with the same structure for
* second-best heuristically detected language, may
* be absent).
*
* @private
* @param {RegExp} expression - Expression.
* @param {string} lexeme - Value.
* @return {boolean} - whether `lexeme` matches `re`.
* @param {string} value - Source to highlight.
* @param {Object?} [options={}] - Configuration.
* @param {string} [options.prefix='hljs-'] - Highlight
* prefix.
* @param {Array.<string>} [options.subset] - List of
* allowed languages.
* @return {Object} - Highlighted `value`.
*/
function test(expression, lexeme) {
var match = expression && expression.exec(lexeme);
function autoHighlight(value, options) {
var settings = options || {};
var prefix = settings.prefix || DEFAULT_PREFIX;
var subset = settings.subset || languageNames;
var length = subset.length;
var index = -1;
var result;
var secondBest;
var current;
var name;
return match && match.index == 0;
}
if (typeof value !== 'string') {
throw new Error('Expected `string` for value, got `' + value + '`');
}
/**
* Normalize a syntax result.
*
* @param {Object} result - Syntax result.
* @return {Object} - Normalized syntax result.
*/
function normalize(result) {
return {
'relevance': result.relevance || 0,
'language': result.language || null,
'value': result.value || []
};
}
secondBest = normalize({});
result = normalize({});
/**
* Compile a language.
*
* @private
* @param {Object} language - Language to compile.
*/
function compileLanguage(language) {
/**
* Get the source of an expression or string.
*
* @private
* @param {RegExp|string} re - Value.
* @return {string} - Source.
*/
function source(re) {
return (re && re.source) || re;
}
while (++index < length) {
name = subset[index];
/**
* Get the source of an expression or string.
*
* @private
* @param {RegExp|string} value - Expression.
* @param {boolean?} [global] - Whether to execute
* globally.
* @return {RegExp} - Compiled expression.
*/
function langRe(value, global) {
return new RegExp(
source(value),
'm' + (language[KEY_INSENSITIVE] ? 'i' : '') +
(global ? 'g' : '')
);
if (!getLanguage(name)) {
continue;
}
/**
* Compile a mode.
*
* @private
* @param {Object} mode - Language mode to compile.
* @param {Object} [parent] - Parent mode.
*/
function compileMode(mode, parent) {
var compiledKeywords = {};
var expandedContains = [];
var terminators;
current = normalize(coreHighlight(name, value, false, prefix));
/**
* Flatten a class-name.
*
* @private
* @param {string} className - Classname to flatten.
* @param {string} value - Value.
*/
function flatten(className, value) {
var pairs;
var pair;
var index;
var length;
current.language = name;
if (language[KEY_INSENSITIVE]) {
value = value.toLowerCase();
}
if (current.relevance > secondBest.relevance) {
secondBest = current;
}
pairs = value.split(C_SPACE);
length = pairs.length;
index = -1;
if (current.relevance > result.relevance) {
secondBest = result;
result = current;
}
}
while (++index < length) {
pair = pairs[index].split(C_PIPE);
if (secondBest.language) {
result.secondBest = secondBest;
}
compiledKeywords[pair[0]] = [
className,
pair[1] ? Number(pair[1]) : 1
];
}
}
return result;
}
if (mode.compiled) {
return;
}
/**
* Highlighting `value` in the language `language`.
*
* @param {string} language - Language name.
* @param {string} value - Source to highlight.
* @param {Object?} [options={}] - Configuration.
* @param {string} [options.prefix='hljs-'] - Highlight
* prefix.
* @return {Object} - Highlighted `value`.
*/
function highlight(language, value, options) {
var settings = options || {};
var prefix = settings.prefix || DEFAULT_PREFIX;
mode.compiled = true;
mode.keywords = mode.keywords || mode.beginKeywords;
if (mode.keywords) {
if (typeof mode.keywords == 'string') {
flatten('keyword', mode.keywords);
} else {
Object.keys(mode.keywords).forEach(function (className) {
flatten(className, mode.keywords[className]);
});
}
mode.keywords = compiledKeywords;
}
mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);
if (parent) {
if (mode.beginKeywords) {
mode.begin = '\\b(' +
mode.beginKeywords.split(C_SPACE).join(C_PIPE) +
')\\b';
}
if (!mode.begin) {
mode.begin = /\B|\b/;
}
mode.beginRe = langRe(mode.begin);
if (!mode.end && !mode.endsWithParent) {
mode.end = /\B|\b/;
}
if (mode.end) {
mode.endRe = langRe(mode.end);
}
mode.terminatorEnd = source(mode.end) || EMPTY;
if (mode.endsWithParent && parent.terminatorEnd) {
mode.terminatorEnd += (mode.end ? C_PIPE : EMPTY) +
parent.terminatorEnd;
}
}
if (mode.illegal) {
mode.illegalRe = langRe(mode.illegal);
}
if (mode.relevance === undefined) {
mode.relevance = 1;
}
if (!mode.contains) {
mode.contains = [];
}
mode.contains.forEach(function (c) {
if (c.variants) {
c.variants.forEach(function (v) {
expandedContains.push(inherit(c, v));
});
} else {
expandedContains.push(c == 'self' ? mode : c);
}
});
mode.contains = expandedContains;
mode.contains.forEach(function (c) {
compileMode(c, mode);
});
if (mode.starts) {
compileMode(mode.starts, parent);
}
terminators =
mode.contains.map(function (c) {
return c.beginKeywords ?
'\\.?(' + c.begin + ')\\.?' :
c.begin;
})
.concat([mode.terminatorEnd, mode.illegal])
.map(source)
.filter(Boolean);
mode.terminators = terminators.length ?
langRe(terminators.join(C_PIPE), true) :
{'exec': execNoop};
}
compileMode(language);
return normalize(coreHighlight(language, value, true, prefix));
}

@@ -303,12 +153,12 @@

function registerLanguage(name, syntax) {
var lang = languages[name] = syntax(low);
var values = lang.aliases;
var length = values && values.length;
var index = -1;
var lang = languages[name] = syntax(low);
var values = lang.aliases;
var length = values && values.length;
var index = -1;
languageNames.push(name);
languageNames.push(name);
while (++index < length) {
aliases[values[index]] = name;
}
while (++index < length) {
aliases[values[index]] = name;
}
}

@@ -321,3 +171,2 @@

*
* @private
* @param {string} name - Language name.

@@ -327,4 +176,3 @@ * @param {string} value - Source to highlight.

* illegals.
* @param {string?} [prefix] - Whether to continue
* processing with `continuation`.
* @param {string?} [prefix] - Highlight prefix.
* @param {boolean} [continuation] - Whether to continue

@@ -335,597 +183,541 @@ * processing with `continuation`.

function coreHighlight(name, value, ignore, prefix, continuation) {
var continuations = {};
var stack = [];
var modeBuffer = EMPTY;
var relevance = 0;
var language;
var top;
var current;
var currentChildren;
var offset;
var count;
var match;
var children;
var continuations = {};
var stack = [];
var modeBuffer = EMPTY;
var relevance = 0;
var language;
var top;
var current;
var currentChildren;
var offset;
var count;
var match;
var children;
if (typeof name !== 'string') {
throw new Error('Expected `string` for name, got `' + name + '`');
}
if (typeof name !== 'string') {
throw new Error('Expected `string` for name, got `' + name + '`');
}
if (typeof value !== 'string') {
throw new Error('Expected `string` for value, got `' + value + '`');
}
if (typeof value !== 'string') {
throw new Error('Expected `string` for value, got `' + value + '`');
}
language = getLanguage(name);
current = top = continuation || language;
currentChildren = children = [];
language = getLanguage(name);
current = top = continuation || language;
currentChildren = children = [];
if (!language) {
throw new Error('Expected `' + name + '` to be registered');
}
if (!language) {
throw new Error('Unknown language: `' + name + '` is not registered');
}
compileLanguage(language);
compileLanguage(language);
/**
* Exit the current context.
*
* @private
*/
function pop() {
/* istanbul ignore next - removed in hljs 9.3 */
currentChildren = stack.pop() || children;
}
try {
offset = top.terminators.lastIndex = 0;
match = top.terminators.exec(value);
/**
* Check a sub-mode.
*
* @private
* @param {string} lexeme - Value.
* @param {Object} mode - Sub-mode.
* @return {boolean} - Whether the lexeme matches.
*/
function subMode(lexeme, mode) {
var values = mode.contains;
var length = values.length;
var index = -1;
while (match) {
count = processLexeme(
value.substr(offset, match.index - offset),
match[0]
);
while (++index < length) {
if (test(values[index].beginRe, lexeme)) {
return values[index];
}
}
offset = top.terminators.lastIndex = match.index + count;
match = top.terminators.exec(value);
}
/**
* Check if `lexeme` ends `mode`.
*
* @private
* @param {Object} mode - Sub-mode.
* @param {string} lexeme - Value.
* @return {boolean} - Whether `lexeme` ends `mode`.
*/
function endOfMode(mode, lexeme) {
if (test(mode.endRe, lexeme)) {
while (mode.endsParent && mode.parent) {
mode = mode.parent;
}
return mode;
}
if (mode.endsWithParent) {
return endOfMode(mode.parent, lexeme);
}
processLexeme(value.substr(offset));
current = top;
while (current.parent) {
if (current.className) {
pop();
}
current = current.parent;
}
/**
* Check if `lexeme` is illegal according to `mode`.
*
* @private
* @param {string} lexeme - Value.
* @param {Object} mode - Sub-mode.
* @return {boolean} - Whether `lexeme` is illegal
* according to `mode`.
*/
function isIllegal(lexeme, mode) {
return !ignore && test(mode.illegalRe, lexeme);
return {
relevance: relevance,
value: currentChildren,
language: name,
top: top
};
} catch (err) {
/* istanbul ignore if - Catch-all */
if (err.message.indexOf('Illegal') === -1) {
throw err;
}
/**
* Check if the first word in `keywords` is a keyword.
*
* @private
* @param {Object} mode - Sub-mode.
* @param {Array.<string>} keywords - Words.
* @return {boolean} - Whether the first word in
* `keywords` is a keyword.
*/
function keywordMatch(mode, keywords) {
var keyword = keywords[0];
return {relevance: 0, value: addText(value, [])};
}
if (language[KEY_INSENSITIVE]) {
keyword = keyword.toLowerCase();
}
/* Process a lexeme. Returns next position. */
function processLexeme(buffer, lexeme) {
var newMode;
var endMode;
var origin;
return mode.keywords.hasOwnProperty(keyword) &&
mode.keywords[keyword];
}
modeBuffer += buffer;
/**
* Build a span.
*
* @private
* @param {string} name - Class-name.
* @param {string} contents - Value inside the span.
* @param {boolean?} [noPrefix] - Don’t prefix class.
* @return {HASTNode} - HAST Element node.
*/
function build(name, contents, noPrefix) {
return {
'type': T_ELEMENT,
'tagName': T_SPAN,
'properties': {
'className': [(noPrefix ? EMPTY : prefix) + name]
},
'children': contents
};
}
if (lexeme === undefined) {
addSiblings(processBuffer(), currentChildren);
/**
* Build a text.
*
* @private
* @param {string} value - Content.
* @return {HASTNode} - HAST Text node.
*/
function buildText(value) {
return {
'type': T_TEXT,
'value': value
};
return 0;
}
/**
* Add a text.
*
* @private
* @param {string} value - Content.
* @param {Array.<Node>} [nodes] - Nodes to add to,
* defaults to `currentChildren`.
*/
function addText(value, nodes) {
var tail;
newMode = subMode(lexeme, top);
if (value) {
tail = nodes[nodes.length - 1];
if (newMode) {
addSiblings(processBuffer(), currentChildren);
if (tail && tail.type === T_TEXT) {
tail.value += value;
} else {
nodes.push(buildText(value));
}
}
startNewMode(newMode, lexeme);
return nodes;
return newMode.returnBegin ? 0 : lexeme.length;
}
/**
* Add a text.
*
* @private
* @param {Array.<Node>} siblings - Nodes to add.
* @param {Array.<Node>} [nodes] - Nodes to add to.
*/
function addSiblings(siblings, nodes) {
var length = siblings.length;
var index = -1;
var sibling;
endMode = endOfMode(top, lexeme);
while (++index < length) {
sibling = siblings[index];
if (endMode) {
origin = top;
if (sibling.type === T_TEXT) {
addText(sibling.value, nodes);
} else {
nodes.push(sibling);
}
}
}
if (!(origin.returnEnd || origin.excludeEnd)) {
modeBuffer += lexeme;
}
/**
* Process keywords.
*
* @private
* @return {Array.<Node>} - Nodes.
*/
function processKeywords() {
var nodes = [];
var lastIndex;
var keyword;
var node;
var submatch;
addSiblings(processBuffer(), currentChildren);
if (!top.keywords) {
return addText(modeBuffer, nodes);
/* Close open modes. */
do {
if (top.className) {
pop();
}
lastIndex = 0;
relevance += top.relevance;
top = top.parent;
} while (top !== endMode.parent);
top.lexemesRe.lastIndex = 0;
if (origin.excludeEnd) {
addText(lexeme, currentChildren);
}
keyword = top.lexemesRe.exec(modeBuffer);
modeBuffer = EMPTY;
while (keyword) {
addText(modeBuffer.substr(
lastIndex, keyword.index - lastIndex
), nodes);
if (endMode.starts) {
startNewMode(endMode.starts, EMPTY);
}
submatch = keywordMatch(top, keyword);
return origin.returnEnd ? 0 : lexeme.length;
}
if (submatch) {
relevance += submatch[1];
if (isIllegal(lexeme, top)) {
throw new Error(
'Illegal lexeme "' + lexeme + '" for mode "' +
(top.className || '<unnamed>') + '"'
);
}
node = build(submatch[0], []);
/* Parser should not reach this point as all
* types of lexemes should be caught earlier,
* but if it does due to some bug make sure it
* advances at least one character forward to
* prevent infinite looping. */
modeBuffer += lexeme;
nodes.push(node);
return lexeme.length || /* istanbul ignore next */ 1;
}
addText(keyword[0], node.children);
} else {
addText(keyword[0], nodes);
}
/* Start a new mode with a `lexeme` to process. */
function startNewMode(mode, lexeme) {
var node;
lastIndex = top.lexemesRe.lastIndex;
keyword = top.lexemesRe.exec(modeBuffer);
}
if (mode.className) {
node = build(mode.className, []);
}
addText(modeBuffer.substr(lastIndex), nodes);
if (mode.returnBegin) {
modeBuffer = EMPTY;
} else if (mode.excludeBegin) {
addText(lexeme, currentChildren);
return nodes;
modeBuffer = EMPTY;
} else {
modeBuffer = lexeme;
}
/**
* Process a sublanguage.
*
* @private
* @return {Array.<Node>} - Nodes.
*/
function processSubLanguage() {
var explicit = typeof top.subLanguage == 'string';
var subvalue;
/* Enter a new mode. */
if (node) {
currentChildren.push(node);
stack.push(currentChildren);
currentChildren = node.children;
}
/* istanbul ignore if - support non-loaded sublanguages */
if (explicit && !languages[top.subLanguage]) {
return addText(modeBuffer, []);
}
top = Object.create(mode, {parent: {value: top}});
}
if (explicit) {
subvalue = coreHighlight(
top.subLanguage,
modeBuffer,
true,
prefix,
continuations[top.subLanguage]
);
} else {
subvalue = autoHighlight(modeBuffer, {
'subset': top.subLanguage.length ?
top.subLanguage : undefined,
'prefix': prefix
});
}
/* Process the buffer. */
function processBuffer() {
var result = top.subLanguage === undefined ? processKeywords() : processSubLanguage();
modeBuffer = EMPTY;
return result;
}
/*
* Counting embedded language score towards the
* host language may be disabled with zeroing the
* containing mode relevance. Usecase in point is
* Markdown that allows XML everywhere and makes
* every XML snippet to have a much larger Markdown
* score.
*/
/* Process a sublanguage (returns a list of nodes). */
function processSubLanguage() {
var explicit = typeof top.subLanguage === 'string';
var subvalue;
if (top.relevance > 0) {
relevance += subvalue.relevance;
}
/* istanbul ignore if - support non-loaded sublanguages */
if (explicit && !languages[top.subLanguage]) {
return addText(modeBuffer, []);
}
if (explicit) {
continuations[top.subLanguage] = subvalue.top;
}
if (explicit) {
subvalue = coreHighlight(
top.subLanguage,
modeBuffer,
true,
prefix,
continuations[top.subLanguage]
);
} else {
subvalue = autoHighlight(modeBuffer, {
subset: top.subLanguage.length ? top.subLanguage : undefined,
prefix: prefix
});
}
return [build(subvalue.language, subvalue.value, true)];
/* Counting embedded language score towards the
* host language may be disabled with zeroing the
* containing mode relevance. Usecase in point is
* Markdown that allows XML everywhere and makes
* every XML snippet to have a much larger Markdown
* score. */
if (top.relevance > 0) {
relevance += subvalue.relevance;
}
/**
* Process the buffer.
*
* @private
* @return {string} - The processed buffer.
*/
function processBuffer() {
var result = top.subLanguage !== undefined ?
processSubLanguage() :
processKeywords();
if (explicit) {
continuations[top.subLanguage] = subvalue.top;
}
modeBuffer = EMPTY;
return [build(subvalue.language, subvalue.value, true)];
}
return result;
/* Process keywords. Returns nodes. */
function processKeywords() {
var nodes = [];
var lastIndex;
var keyword;
var node;
var submatch;
if (!top.keywords) {
return addText(modeBuffer, nodes);
}
/**
* Start a new mode.
*
* @private
* @param {Object} mode - Mode to use.
* @param {string} lexeme - Lexeme to process..
*/
function startNewMode(mode, lexeme) {
var node;
lastIndex = 0;
if (mode.className) {
node = build(mode.className, []);
}
top.lexemesRe.lastIndex = 0;
if (mode.returnBegin) {
modeBuffer = EMPTY;
} else if (mode.excludeBegin) {
addText(lexeme, currentChildren);
keyword = top.lexemesRe.exec(modeBuffer);
modeBuffer = EMPTY;
} else {
modeBuffer = lexeme;
}
while (keyword) {
addText(modeBuffer.substr(lastIndex, keyword.index - lastIndex), nodes);
/*
* Enter a new mode.
*/
submatch = keywordMatch(top, keyword);
if (node) {
currentChildren.push(node);
stack.push(currentChildren);
currentChildren = node.children;
}
if (submatch) {
relevance += submatch[1];
top = Object.create(mode, {
'parent': {
'value': top
}
});
node = build(submatch[0], []);
nodes.push(node);
addText(keyword[0], node.children);
} else {
addText(keyword[0], nodes);
}
lastIndex = top.lexemesRe.lastIndex;
keyword = top.lexemesRe.exec(modeBuffer);
}
/**
* Process a lexeme.
*
* @private
* @param {string} buffer - Current buffer.
* @param {string} lexeme - Current lexeme.
* @return {number} - Next position.
*/
function processLexeme(buffer, lexeme) {
var newMode;
var endMode;
var origin;
addText(modeBuffer.substr(lastIndex), nodes);
modeBuffer += buffer;
return nodes;
}
if (lexeme === undefined) {
addSiblings(processBuffer(), currentChildren);
/* Add siblings. */
function addSiblings(siblings, nodes) {
var length = siblings.length;
var index = -1;
var sibling;
return 0;
}
while (++index < length) {
sibling = siblings[index];
newMode = subMode(lexeme, top);
if (sibling.type === T_TEXT) {
addText(sibling.value, nodes);
} else {
nodes.push(sibling);
}
}
}
if (newMode) {
addSiblings(processBuffer(), currentChildren);
/* Add a text. */
function addText(value, nodes) {
var tail;
startNewMode(newMode, lexeme);
if (value) {
tail = nodes[nodes.length - 1];
return newMode.returnBegin ? 0 : lexeme.length;
}
if (tail && tail.type === T_TEXT) {
tail.value += value;
} else {
nodes.push(buildText(value));
}
}
endMode = endOfMode(top, lexeme);
return nodes;
}
if (endMode) {
origin = top;
/* Build a text. */
function buildText(value) {
return {type: T_TEXT, value: value};
}
if (!(origin.returnEnd || origin.excludeEnd)) {
modeBuffer += lexeme;
}
/* Build a span. */
function build(name, contents, noPrefix) {
return {
type: T_ELEMENT,
tagName: T_SPAN,
properties: {
className: [(noPrefix ? EMPTY : prefix) + name]
},
children: contents
};
}
addSiblings(processBuffer(), currentChildren);
/* Check if the first word in `keywords` is a keyword. */
function keywordMatch(mode, keywords) {
var keyword = keywords[0];
/*
* Close open modes.
*/
if (language[KEY_INSENSITIVE]) {
keyword = keyword.toLowerCase();
}
do {
if (top.className) {
pop();
}
return own.call(mode.keywords, keyword) && mode.keywords[keyword];
}
relevance += top.relevance;
top = top.parent;
} while (top !== endMode.parent);
/* Check if `lexeme` is illegal according to `mode`. */
function isIllegal(lexeme, mode) {
return !ignore && test(mode.illegalRe, lexeme);
}
if (origin.excludeEnd) {
addText(lexeme, currentChildren);
}
/* Check if `lexeme` ends `mode`. */
function endOfMode(mode, lexeme) {
if (test(mode.endRe, lexeme)) {
while (mode.endsParent && mode.parent) {
mode = mode.parent;
}
return mode;
}
modeBuffer = EMPTY;
if (mode.endsWithParent) {
return endOfMode(mode.parent, lexeme);
}
}
if (endMode.starts) {
startNewMode(endMode.starts, EMPTY);
}
/* Check a sub-mode. */
function subMode(lexeme, mode) {
var values = mode.contains;
var length = values.length;
var index = -1;
return origin.returnEnd ? 0 : lexeme.length;
}
while (++index < length) {
if (test(values[index].beginRe, lexeme)) {
return values[index];
}
}
}
if (isIllegal(lexeme, top)) {
throw new Error(
'Illegal lexeme "' + lexeme + '" for mode "' +
(top.className || '<unnamed>') + '"'
);
}
/* Exit the current context. */
function pop() {
/* istanbul ignore next - removed in hljs 9.3 */
currentChildren = stack.pop() || children;
}
}
/*
* Parser should not reach this point as all
* types of lexemes should be caught earlier,
* but if it does due to some bug make sure it
* advances at least one character forward to
* prevent infinite looping.
*/
/* Compile a language. */
function compileLanguage(language) {
compileMode(language);
return;
modeBuffer += lexeme;
/* Compile a language mode, optionally with a parent. */
function compileMode(mode, parent) {
var compiledKeywords = {};
var expandedContains = [];
var terminators;
return lexeme.length || /* istanbul ignore next */ 1;
if (mode.compiled) {
return;
}
try {
offset = top.terminators.lastIndex = 0;
match = top.terminators.exec(value);
mode.compiled = true;
while (match) {
count = processLexeme(
value.substr(offset, match.index - offset),
match[0]
);
mode.keywords = mode.keywords || mode.beginKeywords;
offset = top.terminators.lastIndex = match.index + count;
match = top.terminators.exec(value);
}
if (mode.keywords) {
if (typeof mode.keywords === 'string') {
flatten('keyword', mode.keywords);
} else {
Object.keys(mode.keywords).forEach(function (className) {
flatten(className, mode.keywords[className]);
});
}
processLexeme(value.substr(offset));
current = top;
mode.keywords = compiledKeywords;
}
while (current.parent) {
if (current.className) {
pop();
}
mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);
current = current.parent;
}
if (parent) {
if (mode.beginKeywords) {
mode.begin = '\\b(' + mode.beginKeywords.split(C_SPACE).join(C_PIPE) + ')\\b';
}
return {
'relevance': relevance,
'value': currentChildren,
'language': name,
'top': top
};
} catch (e) {
/* istanbul ignore else - Catch-all */
if (e.message.indexOf('Illegal') !== -1) {
return {
'relevance': 0,
'value': addText(value, [])
};
} else {
throw e;
}
}
}
if (!mode.begin) {
mode.begin = /\B|\b/;
}
/**
* Highlighting with language detection. Accepts a string
* with the code to highlight. Returns an object with the
* following properties:
*
* - language (detected language)
* - relevance (int)
* - value (an HTML string with highlighting markup)
* - secondBest (object with the same structure for
* second-best heuristically detected language, may
* be absent).
*
* @param {string} value - Source to highlight.
* @param {Object?} [options={}] - Configuration.
* @param {string} [options.prefix='hljs-'] - Highlight
* prefix.
* @param {Array.<string>} [options.subset] - List of
* allowed languages.
* @return {Object} - Highlighted `value`.
*/
function autoHighlight(value, options) {
var settings = options || {};
var prefix = settings.prefix || DEFAULT_PREFIX;
var subset = settings.subset || languageNames;
var result;
var secondBest;
var index;
var length;
var current;
var name;
mode.beginRe = langRe(mode.begin);
length = subset.length;
index = -1;
if (!mode.end && !mode.endsWithParent) {
mode.end = /\B|\b/;
}
if (typeof value !== 'string') {
throw new Error('Expected `string` for value, got `' + value + '`');
if (mode.end) {
mode.endRe = langRe(mode.end);
}
mode.terminatorEnd = source(mode.end) || EMPTY;
if (mode.endsWithParent && parent.terminatorEnd) {
mode.terminatorEnd += (mode.end ? C_PIPE : EMPTY) + parent.terminatorEnd;
}
}
secondBest = normalize({});
result = normalize({});
if (mode.illegal) {
mode.illegalRe = langRe(mode.illegal);
}
while (++index < length) {
name = subset[index];
if (mode.relevance === undefined) {
mode.relevance = 1;
}
if (!getLanguage(name)) {
continue;
}
if (!mode.contains) {
mode.contains = [];
}
current = normalize(coreHighlight(name, value, false, prefix));
mode.contains.forEach(function (c) {
if (c.variants) {
c.variants.forEach(function (v) {
expandedContains.push(inherit(c, v));
});
} else {
expandedContains.push(c === 'self' ? mode : c);
}
});
current.language = name;
mode.contains = expandedContains;
if (current.relevance > secondBest.relevance) {
secondBest = current;
}
mode.contains.forEach(function (c) {
compileMode(c, mode);
});
if (current.relevance > result.relevance) {
secondBest = result;
result = current;
}
if (mode.starts) {
compileMode(mode.starts, parent);
}
if (secondBest.language) {
result.secondBest = secondBest;
}
terminators =
mode.contains.map(function (c) {
return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin;
})
.concat([mode.terminatorEnd, mode.illegal])
.map(source)
.filter(Boolean);
return result;
}
mode.terminators = terminators.length ?
langRe(terminators.join(C_PIPE), true) :
{exec: execNoop};
/**
* Highlighting `value` in the language `language`.
*
* @private
* @param {string} language - Language name.
* @param {string} value - Source to highlight.
* @param {Object?} [options={}] - Configuration.
* @param {string} [options.prefix='hljs-'] - Highlight
* prefix.
* @return {Object} - Highlighted `value`.
*/
function highlight(language, value, options) {
var settings = options || {};
var prefix = settings.prefix || DEFAULT_PREFIX;
return;
return normalize(coreHighlight(language, value, true, prefix));
}
/* Flatten a classname. */
function flatten(className, value) {
var pairs;
var pair;
var index;
var length;
/*
* The lowlight interface, which has to be compatible
* with highlight.js, as this object is passed to
* highlight.js syntaxes.
*/
if (language[KEY_INSENSITIVE]) {
value = value.toLowerCase();
}
/** High constructor. */
function High() {}
pairs = value.split(C_SPACE);
length = pairs.length;
index = -1;
High.prototype = high;
while (++index < length) {
pair = pairs[index].split(C_PIPE);
low = new High(); // Ha!
compiledKeywords[pair[0]] = [
className,
pair[1] ? Number(pair[1]) : 1
];
}
}
}
low.highlight = highlight;
low.highlightAuto = autoHighlight;
low.registerLanguage = registerLanguage;
low.getLanguage = getLanguage;
/* Create a regex for `value`. */
function langRe(value, global) {
return new RegExp(
source(value),
'm' + (language[KEY_INSENSITIVE] ? 'i' : '') +
(global ? 'g' : '')
);
}
/*
* Expose.
*/
/* Get the source of an expression or string. */
function source(re) {
return (re && re.source) || re;
}
}
module.exports = low;
/* Normalize a syntax result. */
function normalize(result) {
return {
relevance: result.relevance || 0,
language: result.language || null,
value: result.value || []
};
}
/* Check if `expression` matches `lexeme`. */
function test(expression, lexeme) {
var match = expression && expression.exec(lexeme);
return match && match.index === 0;
}
/* No-op exec. */
function execNoop() {
return null;
}
/* Get a language by `name`. */
function getLanguage(name) {
name = name.toLowerCase();
return languages[name] || languages[aliases[name]];
}
{
"name": "lowlight",
"version": "1.2.0",
"version": "1.3.0",
"description": "Virtual syntax highlighting for virtual DOMs and non-HTML things",

@@ -19,6 +19,3 @@ "license": "MIT",

],
"repository": {
"type": "git",
"url": "https://github.com/wooorm/lowlight.git"
},
"repository": "https://github.com/wooorm/lowlight",
"bugs": "https://github.com/wooorm/lowlight/issues",

@@ -31,3 +28,3 @@ "author": "Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)",

"dependencies": {
"highlight.js": "~9.4.0"
"highlight.js": "~9.6.0"
},

@@ -37,16 +34,10 @@ "devDependencies": {

"chalk": "^1.1.1",
"eslint": "^2.0.0",
"esmangle": "^1.0.0",
"hast": "0.0.2",
"istanbul": "^0.4.0",
"jscs": "^3.0.0",
"jscs-jsdoc": "^2.0.0",
"remark": "^4.0.0",
"remark-comment-config": "^3.0.0",
"remark-github": "^4.0.1",
"remark-lint": "^3.0.0",
"remark-usage": "^3.0.0",
"remark-validate-links": "^3.0.0",
"rehype": "2.0.0",
"nyc": "^8.1.0",
"remark-cli": "^2.0.0",
"remark-preset-wooorm": "^1.0.0",
"tape": "^4.0.0",
"unist-util-visit": "^1.0.0"
"unist-util-visit": "^1.0.0",
"xo": "^0.16.0"
},

@@ -59,9 +50,27 @@ "scripts": {

"build": "npm run build-registry && npm run build-md && npm run build-bundle && npm run build-mangle",
"lint-api": "eslint .",
"lint-style": "jscs --reporter inline .",
"lint": "npm run lint-api && npm run lint-style",
"lint": "xo",
"test-api": "node test/index.js",
"test-coverage": "istanbul cover test/index.js",
"test-coverage": "nyc --reporter lcov tape test/index.js",
"test": "npm run build && npm run lint && npm run test-coverage"
},
"nyc": {
"check-coverage": true,
"lines": 100,
"functions": 100,
"branches": 100
},
"xo": {
"space": true,
"rules": {
"max-lines": "off",
"max-params": "off"
},
"ignores": [
"lowlight.js"
]
},
"remarkConfig": {
"output": true,
"presets": "wooorm"
}
}

@@ -8,7 +8,19 @@ # lowlight [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov]

Lowlight is built to work with all syntaxes supported by [highlight.js][],
that’s [155 languages][names] (and all 73 themes).
that’s [166 languages][names] (and all 73 themes).
## Table of Contents
* [Installation](#installation)
* [Usage](#usage)
* [API](#api)
* [low.highlight(language, value\[, options\])](#lowhighlightlanguage-value-options)
* [low.highlightAuto(value\[, options\])](#lowhighlightautovalue-options)
* [low.registerLanguage(name, syntax)](#lowregisterlanguagename-syntax)
* [Browser](#browser)
* [Projects](#projects)
* [License](#license)
## Installation
[npm][npm-install]:
[npm][]:

@@ -19,56 +31,39 @@ ```bash

**lowlight** is also available for [duo][duo-install], and as an AMD,
CommonJS, and globals module, [uncompressed and compressed][releases].
Read more about [usage in the browser][browser].
[Usage in the browser »][browser]
## Usage
Dependencies:
Highlight:
```javascript
var hast = require('hast');
var low = require('lowlight');
var ast = low.highlight('js', '"use strict";').value;
```
Compile:
Yields:
```javascript
var ast = low.highlight('js', '"use strict";').value;
var html = hast.stringify({'type': 'root', 'children': ast});
```js
[ { type: 'element',
tagName: 'span',
properties: { className: [ 'hljs-meta' ] },
children: [ { type: 'text', value: '"use strict"' } ] },
{ type: 'text', value: ';' } ]
```
Yields:
Or, stringified with [rehype][]:
```json
[
{
"type": "element",
"tagName": "span",
"properties": {
"className": [
"hljs-meta"
]
},
"children": [
{
"type": "text",
"value": "\"use strict\""
}
]
},
{
"type": "text",
"value": ";"
}
]
```js
var rehype = require('rehype');
var html = rehype().stringify({type: 'root', children: ast}));
```
Or, stringified with [hast][]:
Yields:
```html
<span class="hljs-meta">&quot;use strict&quot;</span>;
<span class="hljs-meta">"use strict"</span>;
```
> **Tip**: Use [`hast-to-hyperscript`][to-hyperscript] to transform
> to other virtual DOMs, or DIY.
## API

@@ -80,14 +75,12 @@

**Parameters**
##### Parameters
* `name` (`string`) — See list of [names and aliases][names];
* `value` (`string`) — Source to highlight;
* `options` (`Object?`, optional):
* `prefix` (`string?`, default: `'hljs-'`) — Class prefix.
* `prefix` (`string?`, default: `'hljs-'`)
— Class prefix.
###### Returns
**Returns**: `Object`:
`Object`:

@@ -97,5 +90,3 @@ * `relevance` (`number`)

the given language;
* `language` (`string`) — The given `language`;
* `value` ([`Array.<Node>`][hast-node]) — [Hast nodes][hast-node]

@@ -108,11 +99,8 @@ representing the highlighted given code.

**Parameters**
###### Parameters
* `value` (`string`) — Source to highlight;
* `options` (`Object?`, optional):
* `prefix` (`string?`, default: `'hljs-'`)
— Class prefix;
* `subset` (`Array.<string>?`, optional, defaults to

@@ -122,13 +110,12 @@ all registered languages.)

**Returns**: `Object`:
###### Returns
`Object`:
* `relevance` (`number`)
— Integer representing how sure **low** is the given code
is in the detected language;
* `language` (`string`) — The given `language`;
* `value` ([`Array.<Node>`][hast-node]) — [Hast nodes][hast-node]
representing the highlighted given code.
* `secondBest` (`Object?`)

@@ -141,15 +128,14 @@ — Object with the same structure as the top returned object, but

Register a syntax. Useful in the browser or with custom grammars.
Register a syntax. Useful in the browser or with custom grammars.
**Parameters**
###### Parameters
* `name` (`string`) — Name of language;
* `syntax` (`Function`) — Syntax highlighter, see
[`highlight.js`s docs][syntax] for more information.
## Lowlight in the browser
## Browser
I do not suggest using the pre-built files or requiring `lowlight` in
the browser as that would include a 530kb (170kb with GZIP) file.
the browser as that would include a 530kb (170kb GZipped) file.

@@ -169,5 +155,18 @@ Instead, require `lowlight/lib/core`, and include only the used

...When using browserify, minifying, and GZIP that results in just
17kb of code (7kb with GZIP).
...When using browserify, minifying this results in just 17kb of code
(7kb with GZip).
## Projects
* [`emphasize`](https://github.com/wooorm/emphasize)
— Syntax highlighting in ANSI, for the terminal;
* [`react-lowlight`](https://github.com/rexxars/react-lowlight)
— Syntax highlighter for [React][];
* [`react-syntax-highlighter`](https://github.com/conorhastings/react-syntax-highlighter)
— [React][] component for syntax highlighting.
* [`rehype-highlight`](https://github.com/wooorm/rehype-highlight)
— Syntax highlighting in [**rehype**](https://github.com/wooorm/rehype);
* [`remark-highlight.js`](https://github.com/ben-eb/remark-highlight.js)
— Syntax highlighting in [**remark**](https://github.com/wooorm/remark);
## License

@@ -187,8 +186,4 @@

[npm-install]: https://docs.npmjs.com/cli/install
[npm]: https://docs.npmjs.com/cli/install
[duo-install]: http://duojs.org/#getting-started
[releases]: https://github.com/wooorm/lowlight/releases
[license]: LICENSE

@@ -198,3 +193,3 @@

[hast]: https://github.com/wooorm/hast
[rehype]: https://github.com/wooorm/rehype

@@ -213,2 +208,4 @@ [hast-node]: https://github.com/wooorm/hast#nodes

[browser]: #lowlight-in-the-browser
[to-hyperscript]: https://github.com/wooorm/hast-to-hyperscript
[browser]: #browser
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc