diff --git a/.npmignore b/.npmignore
index d398edd..e677ad7 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,4 +1,6 @@
.DS_Store
node_modules
.travis.yml
+test
+core.js
package-lock.json
diff --git a/.travis.yml b/.travis.yml
index 1e49e0e..e11171d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,9 @@ node_js:
- 0.12
- 4
- 6
+ - 10
git:
depth: 1
branches:
only:
- - master
\ No newline at end of file
+ - master
diff --git a/cjs/index.js b/cjs/index.js
new file mode 100644
index 0000000..a34ace6
--- /dev/null
+++ b/cjs/index.js
@@ -0,0 +1,334 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+/*! (c) 2013-2018 Andrea Giammarchi (ISC) */
+/**
+ * Fully inspired by the work of John Gruber
+ *
+ */
+for (var
+ isNodeJS = typeof process === 'object' && !process.browser,
+ parse = isNodeJS ?
+ // on NodeJS simply fallback to echomd
+ (function (echomd, map) {
+ function parse(value) {
+ return typeof value === 'string' ?
+ echomd(value) : value;
+ }
+ return function () {
+ return map.call(arguments, parse);
+ };
+ }(require('echomd').raw, [].map)) :
+ // on browsers implement some %cmagic%c
+ // The current algorithm is based on two passes:
+ // 1. collect all info ordered by string index
+ // 2. transform surrounding with special %c chars
+ // Info are grouped together whenever is possible
+ // since the console does not support one style per %c
+ (function () {
+ return function (txt) {
+ var
+ code = (Object.create || Object)(null),
+ multiLineCode = transform.multiLineCode.re,
+ singleLineCode = transform.singleLineCode.re,
+ storeAndHide = function ($0, $1, $2, $3) {
+ $3 = $3.replace(/%c/g, '%%c');
+ return $1 + $2 + (code[$3] = md5Base64($3)) + $2;
+ },
+ restoreHidden = function ($0, $1, $2, $3) {
+ return $1 + '%c' + getSource($3, code) + '%c';
+ },
+ out = [],
+ args, i, j, length, css, key
+ ;
+
+ // match and hide possible code (which should not be parsed)
+ match(txt, 'multiLineCode', out);
+ txt = txt.replace(multiLineCode, storeAndHide);
+ match(txt, 'singleLineCode', out);
+ txt = txt.replace(singleLineCode, storeAndHide);
+
+ // find all special cases preserving the order
+ // in which are these found
+ match(txt, 'header2', out);
+ match(txt, 'header1', out);
+ match(txt, 'blink', out);
+ match(txt, 'bold', out);
+ match(txt, 'dim', out);
+ match(txt, 'hidden', out);
+ match(txt, 'reverse', out);
+ match(txt, 'strike', out);
+ match(txt, 'underline', out);
+ match(txt, 'color', out);
+
+ // transform using all info
+
+ // - - - or ___ or * * * with or without space in between
+ txt = txt.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm, line);
+
+ // ## Header
+ txt = replace(txt, 'header2');
+
+ // # Header
+ txt = replace(txt, 'header1');
+
+ // :blink: *bold* -dim- ?hidden? !reverse! _underline_ ~strike~
+ txt = replace(txt, 'blink');
+ txt = replace(txt, 'bold');
+ txt = replace(txt, 'dim');
+ txt = replace(txt, 'hidden');
+ txt = replace(txt, 'reverse');
+ txt = replace(txt, 'strike');
+ txt = replace(txt, 'underline');
+
+ // * list bullets
+ txt = txt.replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm, '$1•$2');
+
+ // > simple quotes
+ txt = txt.replace(/^[ \t]*>([ \t]?)/gm, function ($0, $1) {
+ return Array($1.length + 1).join('▌') + $1;
+ });
+
+ // #RGBA(color) and !#RGBA(background-color)
+ txt = replace(txt, 'color');
+
+ // cleanup duplicates
+ txt = txt.replace(/(%c)+/g, '%c');
+
+ // put back code
+ txt = txt.replace(singleLineCode, restoreHidden);
+ txt = txt.replace(multiLineCode, restoreHidden);
+
+ // create list of arguments to style the console
+ args = [txt];
+ length = out.length;
+ for (i = 0; i < length; i++) {
+ css = '';
+ key = '';
+ // group styles by type (start/end)
+ for (j = i; j < length; j++) {
+ i = j; // update the i to move fast-forward
+ if (j in out) {
+ // first match or same kind of operation (start/end)
+ if (!key || (key === out[j].k)) {
+ key = out[j].k;
+ css += out[j].v;
+ } else {
+ i--; // if key changed, next loop should update
+ break;
+ }
+ }
+ }
+ if (css) args.push(css);
+ }
+ return args;
+ };
+ }())
+ ,
+ line = Array(33).join('─'),
+ // just using same name used in echomd, not actual md5
+ md5Base64 = function (txt) {
+ for (var out = [], i = 0; i < txt.length; i++) {
+ out[i] = txt.charCodeAt(i).toString(32);
+ }
+ return out.join('').slice(0, txt.length);
+ },
+ getSource = function (hash, code) {
+ for (var source in code) {
+ if (code[source] === hash) {
+ return source;
+ }
+ }
+ },
+ commonReplacer = function ($0, $1, $2, $3) {
+ return '%c' + $2 + $3 + '%c';
+ },
+ match = function (txt, what, stack) {
+ var info = transform[what], i, match;
+ while (match = info.re.exec(txt)) {
+ i = match.index;
+ stack[i] = {
+ k: 'start',
+ v: typeof info.start === 'string' ?
+ info.start : info.start(match)
+ };
+ i = i + match[0].length - 1;
+ stack[i] = {
+ k: 'end',
+ v: typeof info.end === 'string' ?
+ info.end : info.end(match)
+ };
+ }
+ },
+ replace = function (txt, what) {
+ var info = transform[what];
+ return txt.replace(info.re, info.place);
+ },
+ transform = {
+ blink: {
+ re: /(\:{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;border:1px solid darkslategray;text-shadow:0 0 2px darkslategray;',
+ end: 'padding:none;border:none;text-shadow:none;'
+ },
+ bold: {
+ re: /(\*{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'font-weight:bold;',
+ end: 'font-weight:default;'
+ },
+ color: {
+ re: /(!?)#([a-zA-Z0-9]{3,8})\((.+?)\)(?!\))/g,
+ place: function ($0, bg, rgb, txt) {
+ return '%c' + txt + '%c';
+ },
+ start: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:' +
+ (/^[a-fA-F0-9]{3,8}$/.test(match[2]) ? '#' : '') +
+ match[2] + ';';
+ },
+ end: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:initial;';
+ }
+ },
+ dim: {
+ re: /(-{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:dimgray;',
+ end: 'color:none;'
+ },
+ header1: {
+ re: /^(\#[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.6em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ header2: {
+ re: /^(\#{2,6}[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.3em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ hidden: {
+ re: /(\?{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:rgba(0,0,0,0);',
+ end: 'color:none;'
+ },
+ reverse: {
+ re: /(\!{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;background:darkslategray;color:lightgray;',
+ end: 'padding:none;background:none;color:none;'
+ },
+ multiLineCode: {
+ re: /(^|[^\\])(`{2,})([\s\S]+?)\2(?!`)/g,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ singleLineCode: {
+ re: /(^|[^\\])(`)(.+?)\2/gm,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ strike: {
+ re: /(~{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'text-decoration:line-through;',
+ end: 'text-decoration:default;'
+ },
+ underline: {
+ re: /(_{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'border-bottom:1px solid;',
+ end: 'border-bottom:default;'
+ }
+ },
+ // 'error', 'info', 'log', 'warn' are overwritten
+ // it is possible to use original method at any time
+ // simply accessing console.methodName.raw( ... ) instead
+ overwrite = function (method) {
+ var original = console[method];
+ if (original) (consolemd[method] = isNodeJS ?
+ function () {
+ return original.apply(console, parse.apply(null, arguments));
+ } :
+ function () {
+ var singleStringArg = arguments.length === 1 && typeof arguments[0] === 'string';
+ var args = singleStringArg ? parse(arguments[0]) : arguments;
+
+ // Todo: We might expose more to the reporter (e.g., returning
+ // `what` and `match` from the `parse`->`match` function) so
+ // the user could, e.g., build spans with classes rather than
+ // inline styles
+ if (_reporter) {
+ var
+ lastIndex, resultInfo,
+ msg = args[0],
+ formattingArgs = args.slice(1),
+ formatRegex = /%c(.*?)(?=%c|$)/g,
+ tmpIndex = 0;
+ _reporter.init();
+ while ((resultInfo = formatRegex.exec(msg)) !== null) {
+ var lastIndex = formatRegex.lastIndex;
+ var result = resultInfo[0];
+ if (result.length > 2) { // Ignore any empty %c's
+ var beginningResultIdx = lastIndex - result.length;
+ if (beginningResultIdx > tmpIndex) {
+ var text = msg.slice(tmpIndex, beginningResultIdx);
+ _reporter.report(text);
+ }
+ _reporter.report(result.slice(2), formattingArgs.splice(0, 1)[0]);
+ }
+ tmpIndex = lastIndex;
+ }
+ if (tmpIndex < msg.length) {
+ var text = msg.slice(tmpIndex);
+ _reporter.report(text);
+ }
+ _reporter.done(args);
+ }
+ return original.apply(console, args);
+ }).raw = function () {
+ return original.apply(console, arguments);
+ };
+ },
+ consolemd = {},
+ methods = ['error', 'info', 'log', 'warn'],
+ key,
+ i = 0; i < methods.length; i++
+) {
+ overwrite(methods[i]);
+}
+// if this is a CommonJS module
+try {
+ overwrite = function (original) {
+ return function () {
+ return original.apply(console, arguments);
+ };
+ };
+ for (key in console) {
+ if (!consolemd.hasOwnProperty(key)) {
+ consolemd[key] = overwrite(console[key]);
+ }
+ }
+} catch(e) {
+ // otherwise replace global console methods
+ for (i = 0; i < methods.length; i++) {
+ key = methods[i];
+ if (!console[key].raw) {
+ console[key] = consolemd[key];
+ }
+ }
+}
+
+var _reporter = null;
+var addReporter = function (reporter) {
+ _reporter = reporter;
+};
+
+exports.addReporter = addReporter;
+exports.default = consolemd;
+
+module.exports = exports.default;
diff --git a/core.js b/core.js
new file mode 100644
index 0000000..f96997d
--- /dev/null
+++ b/core.js
@@ -0,0 +1,328 @@
+/*! (c) 2013-2018 Andrea Giammarchi (ISC) */
+/**
+ * Fully inspired by the work of John Gruber
+ *
+ */
+for (var
+ isNodeJS = typeof process === 'object' && !process.browser,
+ parse = isNodeJS ?
+ // on NodeJS simply fallback to echomd
+ (function (echomd, map) {
+ function parse(value) {
+ return typeof value === 'string' ?
+ echomd(value) : value;
+ }
+ return function () {
+ return map.call(arguments, parse);
+ };
+ }(require('echomd').raw, [].map)) :
+ // on browsers implement some %cmagic%c
+ // The current algorithm is based on two passes:
+ // 1. collect all info ordered by string index
+ // 2. transform surrounding with special %c chars
+ // Info are grouped together whenever is possible
+ // since the console does not support one style per %c
+ (function () {
+ return function (txt) {
+ var
+ code = (Object.create || Object)(null),
+ multiLineCode = transform.multiLineCode.re,
+ singleLineCode = transform.singleLineCode.re,
+ storeAndHide = function ($0, $1, $2, $3) {
+ $3 = $3.replace(/%c/g, '%%c');
+ return $1 + $2 + (code[$3] = md5Base64($3)) + $2;
+ },
+ restoreHidden = function ($0, $1, $2, $3) {
+ return $1 + '%c' + getSource($3, code) + '%c';
+ },
+ out = [],
+ args, i, j, length, css, key
+ ;
+
+ // match and hide possible code (which should not be parsed)
+ match(txt, 'multiLineCode', out);
+ txt = txt.replace(multiLineCode, storeAndHide);
+ match(txt, 'singleLineCode', out);
+ txt = txt.replace(singleLineCode, storeAndHide);
+
+ // find all special cases preserving the order
+ // in which are these found
+ match(txt, 'header2', out);
+ match(txt, 'header1', out);
+ match(txt, 'blink', out);
+ match(txt, 'bold', out);
+ match(txt, 'dim', out);
+ match(txt, 'hidden', out);
+ match(txt, 'reverse', out);
+ match(txt, 'strike', out);
+ match(txt, 'underline', out);
+ match(txt, 'color', out);
+
+ // transform using all info
+
+ // - - - or ___ or * * * with or without space in between
+ txt = txt.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm, line);
+
+ // ## Header
+ txt = replace(txt, 'header2');
+
+ // # Header
+ txt = replace(txt, 'header1');
+
+ // :blink: *bold* -dim- ?hidden? !reverse! _underline_ ~strike~
+ txt = replace(txt, 'blink');
+ txt = replace(txt, 'bold');
+ txt = replace(txt, 'dim');
+ txt = replace(txt, 'hidden');
+ txt = replace(txt, 'reverse');
+ txt = replace(txt, 'strike');
+ txt = replace(txt, 'underline');
+
+ // * list bullets
+ txt = txt.replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm, '$1•$2');
+
+ // > simple quotes
+ txt = txt.replace(/^[ \t]*>([ \t]?)/gm, function ($0, $1) {
+ return Array($1.length + 1).join('▌') + $1;
+ });
+
+ // #RGBA(color) and !#RGBA(background-color)
+ txt = replace(txt, 'color');
+
+ // cleanup duplicates
+ txt = txt.replace(/(%c)+/g, '%c');
+
+ // put back code
+ txt = txt.replace(singleLineCode, restoreHidden);
+ txt = txt.replace(multiLineCode, restoreHidden);
+
+ // create list of arguments to style the console
+ args = [txt];
+ length = out.length;
+ for (i = 0; i < length; i++) {
+ css = '';
+ key = '';
+ // group styles by type (start/end)
+ for (j = i; j < length; j++) {
+ i = j; // update the i to move fast-forward
+ if (j in out) {
+ // first match or same kind of operation (start/end)
+ if (!key || (key === out[j].k)) {
+ key = out[j].k;
+ css += out[j].v;
+ } else {
+ i--; // if key changed, next loop should update
+ break;
+ }
+ }
+ }
+ if (css) args.push(css);
+ }
+ return args;
+ };
+ }())
+ ,
+ line = Array(33).join('─'),
+ // just using same name used in echomd, not actual md5
+ md5Base64 = function (txt) {
+ for (var out = [], i = 0; i < txt.length; i++) {
+ out[i] = txt.charCodeAt(i).toString(32);
+ }
+ return out.join('').slice(0, txt.length);
+ },
+ getSource = function (hash, code) {
+ for (var source in code) {
+ if (code[source] === hash) {
+ return source;
+ }
+ }
+ },
+ commonReplacer = function ($0, $1, $2, $3) {
+ return '%c' + $2 + $3 + '%c';
+ },
+ match = function (txt, what, stack) {
+ var info = transform[what], i, match;
+ while (match = info.re.exec(txt)) {
+ i = match.index;
+ stack[i] = {
+ k: 'start',
+ v: typeof info.start === 'string' ?
+ info.start : info.start(match)
+ };
+ i = i + match[0].length - 1;
+ stack[i] = {
+ k: 'end',
+ v: typeof info.end === 'string' ?
+ info.end : info.end(match)
+ };
+ }
+ },
+ replace = function (txt, what) {
+ var info = transform[what];
+ return txt.replace(info.re, info.place);
+ },
+ transform = {
+ blink: {
+ re: /(\:{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;border:1px solid darkslategray;text-shadow:0 0 2px darkslategray;',
+ end: 'padding:none;border:none;text-shadow:none;'
+ },
+ bold: {
+ re: /(\*{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'font-weight:bold;',
+ end: 'font-weight:default;'
+ },
+ color: {
+ re: /(!?)#([a-zA-Z0-9]{3,8})\((.+?)\)(?!\))/g,
+ place: function ($0, bg, rgb, txt) {
+ return '%c' + txt + '%c';
+ },
+ start: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:' +
+ (/^[a-fA-F0-9]{3,8}$/.test(match[2]) ? '#' : '') +
+ match[2] + ';';
+ },
+ end: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:initial;';
+ }
+ },
+ dim: {
+ re: /(-{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:dimgray;',
+ end: 'color:none;'
+ },
+ header1: {
+ re: /^(\#[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.6em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ header2: {
+ re: /^(\#{2,6}[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.3em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ hidden: {
+ re: /(\?{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:rgba(0,0,0,0);',
+ end: 'color:none;'
+ },
+ reverse: {
+ re: /(\!{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;background:darkslategray;color:lightgray;',
+ end: 'padding:none;background:none;color:none;'
+ },
+ multiLineCode: {
+ re: /(^|[^\\])(`{2,})([\s\S]+?)\2(?!`)/g,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ singleLineCode: {
+ re: /(^|[^\\])(`)(.+?)\2/gm,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ strike: {
+ re: /(~{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'text-decoration:line-through;',
+ end: 'text-decoration:default;'
+ },
+ underline: {
+ re: /(_{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'border-bottom:1px solid;',
+ end: 'border-bottom:default;'
+ }
+ },
+ // 'error', 'info', 'log', 'warn' are overwritten
+ // it is possible to use original method at any time
+ // simply accessing console.methodName.raw( ... ) instead
+ overwrite = function (method) {
+ var original = console[method];
+ if (original) (consolemd[method] = isNodeJS ?
+ function () {
+ return original.apply(console, parse.apply(null, arguments));
+ } :
+ function () {
+ var singleStringArg = arguments.length === 1 && typeof arguments[0] === 'string';
+ var args = singleStringArg ? parse(arguments[0]) : arguments;
+
+ // Todo: We might expose more to the reporter (e.g., returning
+ // `what` and `match` from the `parse`->`match` function) so
+ // the user could, e.g., build spans with classes rather than
+ // inline styles
+ if (_reporter) {
+ var
+ lastIndex, resultInfo,
+ msg = args[0],
+ formattingArgs = args.slice(1),
+ formatRegex = /%c(.*?)(?=%c|$)/g,
+ tmpIndex = 0;
+ _reporter.init();
+ while ((resultInfo = formatRegex.exec(msg)) !== null) {
+ var lastIndex = formatRegex.lastIndex;
+ var result = resultInfo[0];
+ if (result.length > 2) { // Ignore any empty %c's
+ var beginningResultIdx = lastIndex - result.length;
+ if (beginningResultIdx > tmpIndex) {
+ var text = msg.slice(tmpIndex, beginningResultIdx);
+ _reporter.report(text);
+ }
+ _reporter.report(result.slice(2), formattingArgs.splice(0, 1)[0]);
+ }
+ tmpIndex = lastIndex;
+ }
+ if (tmpIndex < msg.length) {
+ var text = msg.slice(tmpIndex);
+ _reporter.report(text);
+ }
+ _reporter.done(args);
+ }
+ return original.apply(console, args);
+ }).raw = function () {
+ return original.apply(console, arguments);
+ };
+ },
+ consolemd = {},
+ methods = ['error', 'info', 'log', 'warn'],
+ key,
+ i = 0; i < methods.length; i++
+) {
+ overwrite(methods[i]);
+}
+// if this is a CommonJS module
+try {
+ overwrite = function (original) {
+ return function () {
+ return original.apply(console, arguments);
+ };
+ };
+ for (key in console) {
+ if (!consolemd.hasOwnProperty(key)) {
+ consolemd[key] = overwrite(console[key]);
+ }
+ }
+} catch(e) {
+ // otherwise replace global console methods
+ for (i = 0; i < methods.length; i++) {
+ key = methods[i];
+ if (!console[key].raw) {
+ console[key] = consolemd[key];
+ }
+ }
+}
+
+var _reporter = null;
+var addReporter = function (reporter) {
+ _reporter = reporter;
+};
+
+export { addReporter };
+export default consolemd;
diff --git a/esm/index.js b/esm/index.js
new file mode 100644
index 0000000..38e0592
--- /dev/null
+++ b/esm/index.js
@@ -0,0 +1,328 @@
+/*! (c) 2013-2018 Andrea Giammarchi (ISC) */
+/**
+ * Fully inspired by the work of John Gruber
+ *
+ */
+for (var
+ isNodeJS = typeof process === 'object' && !process.browser,
+ parse = isNodeJS ?
+ // on NodeJS simply fallback to echomd
+ (function (echomd, map) {
+ function parse(value) {
+ return typeof value === 'string' ?
+ echomd(value) : value;
+ }
+ return function () {
+ return map.call(arguments, parse);
+ };
+ }(require('echomd').raw, [].map)) :
+ // on browsers implement some %cmagic%c
+ // The current algorithm is based on two passes:
+ // 1. collect all info ordered by string index
+ // 2. transform surrounding with special %c chars
+ // Info are grouped together whenever is possible
+ // since the console does not support one style per %c
+ (function () {
+ return function (txt) {
+ var
+ code = (Object.create || Object)(null),
+ multiLineCode = transform.multiLineCode.re,
+ singleLineCode = transform.singleLineCode.re,
+ storeAndHide = function ($0, $1, $2, $3) {
+ $3 = $3.replace(/%c/g, '%%c');
+ return $1 + $2 + (code[$3] = md5Base64($3)) + $2;
+ },
+ restoreHidden = function ($0, $1, $2, $3) {
+ return $1 + '%c' + getSource($3, code) + '%c';
+ },
+ out = [],
+ args, i, j, length, css, key
+ ;
+
+ // match and hide possible code (which should not be parsed)
+ match(txt, 'multiLineCode', out);
+ txt = txt.replace(multiLineCode, storeAndHide);
+ match(txt, 'singleLineCode', out);
+ txt = txt.replace(singleLineCode, storeAndHide);
+
+ // find all special cases preserving the order
+ // in which are these found
+ match(txt, 'header2', out);
+ match(txt, 'header1', out);
+ match(txt, 'blink', out);
+ match(txt, 'bold', out);
+ match(txt, 'dim', out);
+ match(txt, 'hidden', out);
+ match(txt, 'reverse', out);
+ match(txt, 'strike', out);
+ match(txt, 'underline', out);
+ match(txt, 'color', out);
+
+ // transform using all info
+
+ // - - - or ___ or * * * with or without space in between
+ txt = txt.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm, line);
+
+ // ## Header
+ txt = replace(txt, 'header2');
+
+ // # Header
+ txt = replace(txt, 'header1');
+
+ // :blink: *bold* -dim- ?hidden? !reverse! _underline_ ~strike~
+ txt = replace(txt, 'blink');
+ txt = replace(txt, 'bold');
+ txt = replace(txt, 'dim');
+ txt = replace(txt, 'hidden');
+ txt = replace(txt, 'reverse');
+ txt = replace(txt, 'strike');
+ txt = replace(txt, 'underline');
+
+ // * list bullets
+ txt = txt.replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm, '$1•$2');
+
+ // > simple quotes
+ txt = txt.replace(/^[ \t]*>([ \t]?)/gm, function ($0, $1) {
+ return Array($1.length + 1).join('▌') + $1;
+ });
+
+ // #RGBA(color) and !#RGBA(background-color)
+ txt = replace(txt, 'color');
+
+ // cleanup duplicates
+ txt = txt.replace(/(%c)+/g, '%c');
+
+ // put back code
+ txt = txt.replace(singleLineCode, restoreHidden);
+ txt = txt.replace(multiLineCode, restoreHidden);
+
+ // create list of arguments to style the console
+ args = [txt];
+ length = out.length;
+ for (i = 0; i < length; i++) {
+ css = '';
+ key = '';
+ // group styles by type (start/end)
+ for (j = i; j < length; j++) {
+ i = j; // update the i to move fast-forward
+ if (j in out) {
+ // first match or same kind of operation (start/end)
+ if (!key || (key === out[j].k)) {
+ key = out[j].k;
+ css += out[j].v;
+ } else {
+ i--; // if key changed, next loop should update
+ break;
+ }
+ }
+ }
+ if (css) args.push(css);
+ }
+ return args;
+ };
+ }())
+ ,
+ line = Array(33).join('─'),
+ // just using same name used in echomd, not actual md5
+ md5Base64 = function (txt) {
+ for (var out = [], i = 0; i < txt.length; i++) {
+ out[i] = txt.charCodeAt(i).toString(32);
+ }
+ return out.join('').slice(0, txt.length);
+ },
+ getSource = function (hash, code) {
+ for (var source in code) {
+ if (code[source] === hash) {
+ return source;
+ }
+ }
+ },
+ commonReplacer = function ($0, $1, $2, $3) {
+ return '%c' + $2 + $3 + '%c';
+ },
+ match = function (txt, what, stack) {
+ var info = transform[what], i, match;
+ while (match = info.re.exec(txt)) {
+ i = match.index;
+ stack[i] = {
+ k: 'start',
+ v: typeof info.start === 'string' ?
+ info.start : info.start(match)
+ };
+ i = i + match[0].length - 1;
+ stack[i] = {
+ k: 'end',
+ v: typeof info.end === 'string' ?
+ info.end : info.end(match)
+ };
+ }
+ },
+ replace = function (txt, what) {
+ var info = transform[what];
+ return txt.replace(info.re, info.place);
+ },
+ transform = {
+ blink: {
+ re: /(\:{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;border:1px solid darkslategray;text-shadow:0 0 2px darkslategray;',
+ end: 'padding:none;border:none;text-shadow:none;'
+ },
+ bold: {
+ re: /(\*{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'font-weight:bold;',
+ end: 'font-weight:default;'
+ },
+ color: {
+ re: /(!?)#([a-zA-Z0-9]{3,8})\((.+?)\)(?!\))/g,
+ place: function ($0, bg, rgb, txt) {
+ return '%c' + txt + '%c';
+ },
+ start: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:' +
+ (/^[a-fA-F0-9]{3,8}$/.test(match[2]) ? '#' : '') +
+ match[2] + ';';
+ },
+ end: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:initial;';
+ }
+ },
+ dim: {
+ re: /(-{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:dimgray;',
+ end: 'color:none;'
+ },
+ header1: {
+ re: /^(\#[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.6em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ header2: {
+ re: /^(\#{2,6}[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.3em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ hidden: {
+ re: /(\?{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:rgba(0,0,0,0);',
+ end: 'color:none;'
+ },
+ reverse: {
+ re: /(\!{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;background:darkslategray;color:lightgray;',
+ end: 'padding:none;background:none;color:none;'
+ },
+ multiLineCode: {
+ re: /(^|[^\\])(`{2,})([\s\S]+?)\2(?!`)/g,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ singleLineCode: {
+ re: /(^|[^\\])(`)(.+?)\2/gm,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ strike: {
+ re: /(~{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'text-decoration:line-through;',
+ end: 'text-decoration:default;'
+ },
+ underline: {
+ re: /(_{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'border-bottom:1px solid;',
+ end: 'border-bottom:default;'
+ }
+ },
+ // 'error', 'info', 'log', 'warn' are overwritten
+ // it is possible to use original method at any time
+ // simply accessing console.methodName.raw( ... ) instead
+ overwrite = function (method) {
+ var original = console[method];
+ if (original) (consolemd[method] = isNodeJS ?
+ function () {
+ return original.apply(console, parse.apply(null, arguments));
+ } :
+ function () {
+ var singleStringArg = arguments.length === 1 && typeof arguments[0] === 'string';
+ var args = singleStringArg ? parse(arguments[0]) : arguments;
+
+ // Todo: We might expose more to the reporter (e.g., returning
+ // `what` and `match` from the `parse`->`match` function) so
+ // the user could, e.g., build spans with classes rather than
+ // inline styles
+ if (_reporter) {
+ var
+ lastIndex, resultInfo,
+ msg = args[0],
+ formattingArgs = args.slice(1),
+ formatRegex = /%c(.*?)(?=%c|$)/g,
+ tmpIndex = 0;
+ _reporter.init();
+ while ((resultInfo = formatRegex.exec(msg)) !== null) {
+ var lastIndex = formatRegex.lastIndex;
+ var result = resultInfo[0];
+ if (result.length > 2) { // Ignore any empty %c's
+ var beginningResultIdx = lastIndex - result.length;
+ if (beginningResultIdx > tmpIndex) {
+ var text = msg.slice(tmpIndex, beginningResultIdx);
+ _reporter.report(text);
+ }
+ _reporter.report(result.slice(2), formattingArgs.splice(0, 1)[0]);
+ }
+ tmpIndex = lastIndex;
+ }
+ if (tmpIndex < msg.length) {
+ var text = msg.slice(tmpIndex);
+ _reporter.report(text);
+ }
+ _reporter.done(args);
+ }
+ return original.apply(console, args);
+ }).raw = function () {
+ return original.apply(console, arguments);
+ };
+ },
+ consolemd = {},
+ methods = ['error', 'info', 'log', 'warn'],
+ key,
+ i = 0; i < methods.length; i++
+) {
+ overwrite(methods[i]);
+}
+// if this is a CommonJS module
+try {
+ overwrite = function (original) {
+ return function () {
+ return original.apply(console, arguments);
+ };
+ };
+ for (key in console) {
+ if (!consolemd.hasOwnProperty(key)) {
+ consolemd[key] = overwrite(console[key]);
+ }
+ }
+} catch(e) {
+ // otherwise replace global console methods
+ for (i = 0; i < methods.length; i++) {
+ key = methods[i];
+ if (!console[key].raw) {
+ console[key] = consolemd[key];
+ }
+ }
+}
+
+var _reporter = null;
+var addReporter = function (reporter) {
+ _reporter = reporter;
+};
+
+export default consolemd;
+export { addReporter };
diff --git a/esm/index.min.js b/esm/index.min.js
new file mode 100644
index 0000000..f8ccec1
--- /dev/null
+++ b/esm/index.min.js
@@ -0,0 +1 @@
+for(var key,isNodeJS="object"==typeof process&&!process.browser,parse=isNodeJS?function(e,r){function o(r){return"string"==typeof r?e(r):r}return function(){return r.call(arguments,o)}}(require("echomd").raw,[].map):function(e){var r,o,t,n,a,c,l=(Object.create||Object)(null),i=transform.multiLineCode.re,d=transform.singleLineCode.re,p=function(e,r,o,t){return t=t.replace(/%c/g,"%%c"),r+o+(l[t]=md5Base64(t))+o},s=function(e,r,o,t){return r+"%c"+getSource(t,l)+"%c"},f=[];for(match(e,"multiLineCode",f),e=e.replace(i,p),match(e,"singleLineCode",f),e=e.replace(d,p),match(e,"header2",f),match(e,"header1",f),match(e,"blink",f),match(e,"bold",f),match(e,"dim",f),match(e,"hidden",f),match(e,"reverse",f),match(e,"strike",f),match(e,"underline",f),match(e,"color",f),e=e.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm,line),e=replace(e,"header2"),e=replace(e,"header1"),e=replace(e,"blink"),e=replace(e,"bold"),e=replace(e,"dim"),e=replace(e,"hidden"),e=replace(e,"reverse"),e=replace(e,"strike"),e=(e=(e=replace(e,"underline")).replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm,"$1•$2")).replace(/^[ \t]*>([ \t]?)/gm,function(e,r){return Array(r.length+1).join("▌")+r}),r=[e=(e=(e=(e=replace(e,"color")).replace(/(%c)+/g,"%c")).replace(d,s)).replace(i,s)],n=f.length,o=0;o2){var d=l-i.length;if(d>c){var p=t.slice(c,d);_reporter.report(p)}_reporter.report(i.slice(2),n.splice(0,1)[0])}c=l}if(c
- */
-(function () {'use strict';
+var consolemd = (function (exports) {
+ 'use strict';
+
+ /*! (c) 2013-2018 Andrea Giammarchi (ISC) */
+ /**
+ * Fully inspired by the work of John Gruber
+ *
+ */
for (var
isNodeJS = typeof process === 'object' && !process.browser,
parse = isNodeJS ?
@@ -37,7 +39,7 @@
return $1 + '%c' + getSource($3, code) + '%c';
},
out = [],
- args, i, j, length, css, key, re
+ args, i, j, length, css, key
;
// match and hide possible code (which should not be parsed)
@@ -252,9 +254,41 @@
return original.apply(console, parse.apply(null, arguments));
} :
function () {
- return arguments.length === 1 && typeof arguments[0] === 'string' ?
- original.apply(console, parse(arguments[0])) :
- original.apply(console, arguments);
+ var singleStringArg = arguments.length === 1 && typeof arguments[0] === 'string';
+ var args = singleStringArg ? parse(arguments[0]) : arguments;
+
+ // Todo: We might expose more to the reporter (e.g., returning
+ // `what` and `match` from the `parse`->`match` function) so
+ // the user could, e.g., build spans with classes rather than
+ // inline styles
+ if (_reporter) {
+ var
+ lastIndex, resultInfo,
+ msg = args[0],
+ formattingArgs = args.slice(1),
+ formatRegex = /%c(.*?)(?=%c|$)/g,
+ tmpIndex = 0;
+ _reporter.init();
+ while ((resultInfo = formatRegex.exec(msg)) !== null) {
+ var lastIndex = formatRegex.lastIndex;
+ var result = resultInfo[0];
+ if (result.length > 2) { // Ignore any empty %c's
+ var beginningResultIdx = lastIndex - result.length;
+ if (beginningResultIdx > tmpIndex) {
+ var text = msg.slice(tmpIndex, beginningResultIdx);
+ _reporter.report(text);
+ }
+ _reporter.report(result.slice(2), formattingArgs.splice(0, 1)[0]);
+ }
+ tmpIndex = lastIndex;
+ }
+ if (tmpIndex < msg.length) {
+ var text = msg.slice(tmpIndex);
+ _reporter.report(text);
+ }
+ _reporter.done(args);
+ }
+ return original.apply(console, args);
}).raw = function () {
return original.apply(console, arguments);
};
@@ -268,8 +302,6 @@
}
// if this is a CommonJS module
try {
- // export consolemd fake object
- module.exports = consolemd;
overwrite = function (original) {
return function () {
return original.apply(console, arguments);
@@ -289,4 +321,15 @@
}
}
}
-}());
+
+ var _reporter = null;
+ var addReporter = function (reporter) {
+ _reporter = reporter;
+ };
+
+ exports.addReporter = addReporter;
+ exports.default = consolemd;
+
+ return exports;
+
+}({}));
diff --git a/min.js b/min.js
index 1d3d214..c77a730 100644
--- a/min.js
+++ b/min.js
@@ -1,2 +1 @@
-/*! (c) 2013-2018 Andrea Giammarchi (ISC) */
-!function(){"use strict";for(var n,r="object"==typeof process&&!process.browser,t=r?function(n,e){function r(e){return"string"==typeof e?n(e):e}return function(){return e.call(arguments,r)}}(require("echomd").raw,[].map):function(e){var n,r,t,o,a,l,c=(Object.create||Object)(null),i=y.multiLineCode.re,d=y.singleLineCode.re,f=function(e,n,r,t){return t=t.replace(/%c/g,"%%c"),n+r+(c[t]=p(t))+r},u=function(e,n,r,t){return n+"%c"+h(t,c)+"%c"},s=[];for(m(e,"multiLineCode",s),e=e.replace(i,f),m(e,"singleLineCode",s),e=e.replace(d,f),m(e,"header2",s),m(e,"header1",s),m(e,"blink",s),m(e,"bold",s),m(e,"dim",s),m(e,"hidden",s),m(e,"reverse",s),m(e,"strike",s),m(e,"underline",s),m(e,"color",s),e=e.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm,g),e=b(e,"header2"),e=b(e,"header1"),e=b(e,"blink"),e=b(e,"bold"),e=b(e,"dim"),e=b(e,"hidden"),e=b(e,"reverse"),e=b(e,"strike"),e=(e=(e=b(e,"underline")).replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm,"$1•$2")).replace(/^[ \t]*>([ \t]?)/gm,function(e,n){return Array(n.length+1).join("▌")+n}),n=[e=(e=(e=(e=b(e,"color")).replace(/(%c)+/g,"%c")).replace(d,u)).replace(i,u)],o=s.length,r=0;r([ \t]?)/gm,function(e,r){return Array(r.length+1).join("▌")+r}),r=[e=(e=(e=(e=d(e,"color")).replace(/(%c)+/g,"%c")).replace(h,b)).replace(p,b)],i=y.length,n=0;n2){var f=c-d.length;if(f>i){var u=o.slice(i,f);h.report(u)}h.report(d.slice(2),a.splice(0,1)[0])}i=c}if(i
+
+
+
+ consolemd tests
+
+
+
+
+
+
diff --git a/test/test-cjs.js b/test/test-cjs.js
new file mode 100644
index 0000000..01d5fc2
--- /dev/null
+++ b/test/test-cjs.js
@@ -0,0 +1,341 @@
+'use strict';
+
+/*! (c) 2013-2018 Andrea Giammarchi (ISC) */
+/**
+ * Fully inspired by the work of John Gruber
+ *
+ */
+for (var
+ isNodeJS = typeof process === 'object' && !process.browser,
+ parse = isNodeJS ?
+ // on NodeJS simply fallback to echomd
+ (function (echomd, map) {
+ function parse(value) {
+ return typeof value === 'string' ?
+ echomd(value) : value;
+ }
+ return function () {
+ return map.call(arguments, parse);
+ };
+ }(require('echomd').raw, [].map)) :
+ // on browsers implement some %cmagic%c
+ // The current algorithm is based on two passes:
+ // 1. collect all info ordered by string index
+ // 2. transform surrounding with special %c chars
+ // Info are grouped together whenever is possible
+ // since the console does not support one style per %c
+ (function () {
+ return function (txt) {
+ var
+ code = (Object.create || Object)(null),
+ multiLineCode = transform.multiLineCode.re,
+ singleLineCode = transform.singleLineCode.re,
+ storeAndHide = function ($0, $1, $2, $3) {
+ $3 = $3.replace(/%c/g, '%%c');
+ return $1 + $2 + (code[$3] = md5Base64($3)) + $2;
+ },
+ restoreHidden = function ($0, $1, $2, $3) {
+ return $1 + '%c' + getSource($3, code) + '%c';
+ },
+ out = [],
+ args, i, j, length, css, key
+ ;
+
+ // match and hide possible code (which should not be parsed)
+ match(txt, 'multiLineCode', out);
+ txt = txt.replace(multiLineCode, storeAndHide);
+ match(txt, 'singleLineCode', out);
+ txt = txt.replace(singleLineCode, storeAndHide);
+
+ // find all special cases preserving the order
+ // in which are these found
+ match(txt, 'header2', out);
+ match(txt, 'header1', out);
+ match(txt, 'blink', out);
+ match(txt, 'bold', out);
+ match(txt, 'dim', out);
+ match(txt, 'hidden', out);
+ match(txt, 'reverse', out);
+ match(txt, 'strike', out);
+ match(txt, 'underline', out);
+ match(txt, 'color', out);
+
+ // transform using all info
+
+ // - - - or ___ or * * * with or without space in between
+ txt = txt.replace(/^[ ]{0,2}([ ]?[*_-][ ]?){3,}[ \t]*$/gm, line);
+
+ // ## Header
+ txt = replace(txt, 'header2');
+
+ // # Header
+ txt = replace(txt, 'header1');
+
+ // :blink: *bold* -dim- ?hidden? !reverse! _underline_ ~strike~
+ txt = replace(txt, 'blink');
+ txt = replace(txt, 'bold');
+ txt = replace(txt, 'dim');
+ txt = replace(txt, 'hidden');
+ txt = replace(txt, 'reverse');
+ txt = replace(txt, 'strike');
+ txt = replace(txt, 'underline');
+
+ // * list bullets
+ txt = txt.replace(/^([ \t]{1,})[*+-]([ \t]{1,})/gm, '$1•$2');
+
+ // > simple quotes
+ txt = txt.replace(/^[ \t]*>([ \t]?)/gm, function ($0, $1) {
+ return Array($1.length + 1).join('▌') + $1;
+ });
+
+ // #RGBA(color) and !#RGBA(background-color)
+ txt = replace(txt, 'color');
+
+ // cleanup duplicates
+ txt = txt.replace(/(%c)+/g, '%c');
+
+ // put back code
+ txt = txt.replace(singleLineCode, restoreHidden);
+ txt = txt.replace(multiLineCode, restoreHidden);
+
+ // create list of arguments to style the console
+ args = [txt];
+ length = out.length;
+ for (i = 0; i < length; i++) {
+ css = '';
+ key = '';
+ // group styles by type (start/end)
+ for (j = i; j < length; j++) {
+ i = j; // update the i to move fast-forward
+ if (j in out) {
+ // first match or same kind of operation (start/end)
+ if (!key || (key === out[j].k)) {
+ key = out[j].k;
+ css += out[j].v;
+ } else {
+ i--; // if key changed, next loop should update
+ break;
+ }
+ }
+ }
+ if (css) args.push(css);
+ }
+ return args;
+ };
+ }())
+ ,
+ line = Array(33).join('─'),
+ // just using same name used in echomd, not actual md5
+ md5Base64 = function (txt) {
+ for (var out = [], i = 0; i < txt.length; i++) {
+ out[i] = txt.charCodeAt(i).toString(32);
+ }
+ return out.join('').slice(0, txt.length);
+ },
+ getSource = function (hash, code) {
+ for (var source in code) {
+ if (code[source] === hash) {
+ return source;
+ }
+ }
+ },
+ commonReplacer = function ($0, $1, $2, $3) {
+ return '%c' + $2 + $3 + '%c';
+ },
+ match = function (txt, what, stack) {
+ var info = transform[what], i, match;
+ while (match = info.re.exec(txt)) {
+ i = match.index;
+ stack[i] = {
+ k: 'start',
+ v: typeof info.start === 'string' ?
+ info.start : info.start(match)
+ };
+ i = i + match[0].length - 1;
+ stack[i] = {
+ k: 'end',
+ v: typeof info.end === 'string' ?
+ info.end : info.end(match)
+ };
+ }
+ },
+ replace = function (txt, what) {
+ var info = transform[what];
+ return txt.replace(info.re, info.place);
+ },
+ transform = {
+ blink: {
+ re: /(\:{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;border:1px solid darkslategray;text-shadow:0 0 2px darkslategray;',
+ end: 'padding:none;border:none;text-shadow:none;'
+ },
+ bold: {
+ re: /(\*{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'font-weight:bold;',
+ end: 'font-weight:default;'
+ },
+ color: {
+ re: /(!?)#([a-zA-Z0-9]{3,8})\((.+?)\)(?!\))/g,
+ place: function ($0, bg, rgb, txt) {
+ return '%c' + txt + '%c';
+ },
+ start: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:' +
+ (/^[a-fA-F0-9]{3,8}$/.test(match[2]) ? '#' : '') +
+ match[2] + ';';
+ },
+ end: function (match) {
+ return (match[1] ? 'background-' : '') + 'color:initial;';
+ }
+ },
+ dim: {
+ re: /(-{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:dimgray;',
+ end: 'color:none;'
+ },
+ header1: {
+ re: /^(\#[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.6em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ header2: {
+ re: /^(\#{2,6}[ \t]+)(.+?)[ \t]*\#*([\r\n]+|$)/gm,
+ place: commonReplacer,
+ start: 'font-weight:bold;font-size:1.3em;',
+ end: 'font-weight:default;font-size:default;'
+ },
+ hidden: {
+ re: /(\?{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'color:rgba(0,0,0,0);',
+ end: 'color:none;'
+ },
+ reverse: {
+ re: /(\!{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'padding:0 2px;background:darkslategray;color:lightgray;',
+ end: 'padding:none;background:none;color:none;'
+ },
+ multiLineCode: {
+ re: /(^|[^\\])(`{2,})([\s\S]+?)\2(?!`)/g,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ singleLineCode: {
+ re: /(^|[^\\])(`)(.+?)\2/gm,
+ start: 'font-family:monospace;',
+ end: 'font-family:default;'
+ },
+ strike: {
+ re: /(~{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'text-decoration:line-through;',
+ end: 'text-decoration:default;'
+ },
+ underline: {
+ re: /(_{1,2})(?=\S)(.*?)(\S)\1/g,
+ place: commonReplacer,
+ start: 'border-bottom:1px solid;',
+ end: 'border-bottom:default;'
+ }
+ },
+ // 'error', 'info', 'log', 'warn' are overwritten
+ // it is possible to use original method at any time
+ // simply accessing console.methodName.raw( ... ) instead
+ overwrite = function (method) {
+ var original = console[method];
+ if (original) (consolemd[method] = isNodeJS ?
+ function () {
+ return original.apply(console, parse.apply(null, arguments));
+ } :
+ function () {
+ var singleStringArg = arguments.length === 1 && typeof arguments[0] === 'string';
+ var args = singleStringArg ? parse(arguments[0]) : arguments;
+
+ // Todo: We might expose more to the reporter (e.g., returning
+ // `what` and `match` from the `parse`->`match` function) so
+ // the user could, e.g., build spans with classes rather than
+ // inline styles
+ if (_reporter) {
+ var
+ lastIndex, resultInfo,
+ msg = args[0],
+ formattingArgs = args.slice(1),
+ formatRegex = /%c(.*?)(?=%c|$)/g,
+ tmpIndex = 0;
+ _reporter.init();
+ while ((resultInfo = formatRegex.exec(msg)) !== null) {
+ var lastIndex = formatRegex.lastIndex;
+ var result = resultInfo[0];
+ if (result.length > 2) { // Ignore any empty %c's
+ var beginningResultIdx = lastIndex - result.length;
+ if (beginningResultIdx > tmpIndex) {
+ var text = msg.slice(tmpIndex, beginningResultIdx);
+ _reporter.report(text);
+ }
+ _reporter.report(result.slice(2), formattingArgs.splice(0, 1)[0]);
+ }
+ tmpIndex = lastIndex;
+ }
+ if (tmpIndex < msg.length) {
+ var text = msg.slice(tmpIndex);
+ _reporter.report(text);
+ }
+ _reporter.done(args);
+ }
+ return original.apply(console, args);
+ }).raw = function () {
+ return original.apply(console, arguments);
+ };
+ },
+ consolemd = {},
+ methods = ['error', 'info', 'log', 'warn'],
+ key,
+ i = 0; i < methods.length; i++
+) {
+ overwrite(methods[i]);
+}
+// if this is a CommonJS module
+try {
+ overwrite = function (original) {
+ return function () {
+ return original.apply(console, arguments);
+ };
+ };
+ for (key in console) {
+ if (!consolemd.hasOwnProperty(key)) {
+ consolemd[key] = overwrite(console[key]);
+ }
+ }
+} catch(e) {
+ // otherwise replace global console methods
+ for (i = 0; i < methods.length; i++) {
+ key = methods[i];
+ if (!console[key].raw) {
+ console[key] = consolemd[key];
+ }
+ }
+}
+
+var _reporter = null;
+var addReporter = function (reporter) {
+ _reporter = reporter;
+};
+
+function test (reporter) {
+ if (reporter) {
+ addReporter(reporter);
+ }
+ consolemd.log(':#green(*✓*): *OK*');
+ consolemd.log(':#red(*x*): *FAIL*');
+ consolemd.log('no formatting front only#yellow(*✓*)');
+ consolemd.log('no formatting front#yellow(*✓*)no formatting back');
+ consolemd.log('#yellow(*✓*)no formatting back only');
+ consolemd.log('no formatting at all');
+}
+
+module.exports = test;
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..a833d7b
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,13 @@
+import {default as consolemd, addReporter} from '../esm/index.js';
+
+export default function (reporter) {
+ if (reporter) {
+ addReporter(reporter);
+ }
+ consolemd.log(':#green(*✓*): *OK*');
+ consolemd.log(':#red(*x*): *FAIL*');
+ consolemd.log('no formatting front only#yellow(*✓*)');
+ consolemd.log('no formatting front#yellow(*✓*)no formatting back');
+ consolemd.log('#yellow(*✓*)no formatting back only');
+ consolemd.log('no formatting at all');
+}