bmocha
Version:
Alternative implementation of mocha
302 lines (257 loc) • 4.8 kB
JavaScript
/*!
* highlight.js - highlighter for bmocha
* Copyright (c) 2018-2019, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bmocha
*/
;
/*
* Helpers
*/
const rx = (pattern, flags = '') => {
const str = pattern.replace(/#.*$/gm, '')
.replace(/\s/g, '');
return new RegExp(str, flags);
};
const escape = (str) => {
str = String(str);
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/"/g, '"');
str = str.replace(/'/g, ''');
return str;
};
/*
* Constants
*/
const types = {
string: 0,
comment: 1,
regex: 2,
reserved: 3,
number: 4,
text: 5
};
const style = [
'color:#d14',
'color:#998',
'color:#009926',
'color:#000;font-weight:bold',
'color:#099',
'color:#000'
];
const rules = [
// String
/^(?:"(?:\\"|\\\\|[^"])*"|'(?:\\'|\\\\|[^'])*'|`(?:\\`|\\\\|[^`])*`)/,
// Comment
/^(?:\/\/[^\n]*|\/\*[\s\S]*?\*\/)/,
// Regex
/^\/(?:\\\/|\\\\|[^\/\n])+\/\w*/,
// Reserved/Special
rx(`^
[^\\w]
(?:
# Conditional
if
| else
| switch
# Repeat
| while
| for
| do
| in
| of
# Branch
| break
| continue
# Operator
| new
| delete
| instanceof
| typeof
| yield
| await
# Type
| Array
| ArrayBuffer
| AsyncFunction
| Atomics
| BigInt
| BigInt64Array
| BigUint64Array
| Boolean
| Buffer
| DataView
| Date
| Error
| EvalError
| Float32Array
| Float64Array
| Function
| Generator
| GeneratorFunction
| Infinity
| Int16Array
| Int32Array
| Int8Array
| InternalError
| Intl
| JSON
| Map
| Math
| NaN
| Number
| Object
| Promise
| Proxy
| RangeError
| ReferenceError
| Reflect
| RegExp
| SIMD
| Set
| SharedArrayBuffer
| String
| Symbol
| SyntaxError
| TypeError
| TypedArray
| URIError
| Uint16Array
| Uint32Array
| Uint8Array
| Uint8ClampedArray
| WeakMap
| WeakSet
| WebAssembly
| decodeURI
| decodeURIComponent
| encodeURI
| encodeURIComponent
| eval
| isFinite
| isNaN
| parseFloat
| parseInt
| clearImmediate
| clearInterval
| clearTimeout
| setImmediate
| setInterval
| setTimeout
# Statement
| return
| with
| class
| extends
| static
# Boolean
| true
| false
# Null
| null
| undefined
| void
# Identifier
| arguments
| this
| var
| let
| const
| async
| super
| constructor
# Label
| case
| default
# Exception
| try
| catch
| finally
| throw
| debugger
# Global
| global
# Member
| console
| process
| module
| exports
| require
| __dirname
| __filename
# Reserved
| enum
| implements
| interface
| package
| private
| protected
| public
)
(?=[^\\w])
`),
// Number
rx(`^
[^\\w]
-?
(?:
# Floating Point
\\d*\\.\\d+ (?:[eE][+\\-]?\\d+)?
# Binary, Octal, Hex
| 0[bBoOxX][0-9a-fA-F]+ (?:[eE][+\\-]?\\d+|n)?
# Integer
| \\d+ (?:[eE][+\\-]?\\d+|n)?
)
`)
];
rules.push((() => {
const sources = [];
for (const rule of rules) {
const src = rule.source.substring(1);
sources.push(src);
}
const all = sources.join('|');
return rx(`^[\\s\\S]+?(?=${all}|$)`);
})());
/*
* Highlight
*/
function highlight(text) {
text = String(text);
text = ' ' + text;
text = text.replace(/\r\n/g, '\n');
text = text.replace(/\r/g, '\n');
text = text.replace(/\t/g, ' ');
let out = '';
while (text.length > 0) {
outer:
for (let type = 0; type < rules.length; type++) {
const rule = rules[type];
const match = rule.exec(text);
if (!match)
continue;
let [str] = match;
text = text.substring(str.length);
switch (type) {
case types.text:
out += escape(str);
break outer;
case types.number:
case types.reserved:
out += escape(str[0]);
str = str.substring(1);
break;
}
out += `<span style="${style[type]}">`
+ escape(str)
+ '</span>';
break;
}
}
return out.substring(1);
}
/*
* Expose
*/
module.exports = highlight;