diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 58858535..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index af3da470..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/README.md b/README.md index 5ea4cd27..9ebdfbf1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # debug -[![Build Status](https://travis-ci.org/debug-js/debug.svg?branch=master)](https://travis-ci.org/debug-js/debug) [![Coverage Status](https://coveralls.io/repos/github/debug-js/debug/badge.svg?branch=master)](https://coveralls.io/github/debug-js/debug?branch=master) [![Slack](https://visionmedia-community-slackin.now.sh/badge.svg)](https://visionmedia-community-slackin.now.sh/) [![OpenCollective](https://opencollective.com/debug/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/debug/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/debug/sponsors/badge.svg)](#sponsors) @@ -241,6 +241,9 @@ setInterval(function(){ }, 1200); ``` +In Chromium-based web browsers (e.g. Brave, Chrome, and Electron), the JavaScript console will—by default—only show messages logged by `debug` if the "Verbose" log level is _enabled_. + + ## Output streams diff --git a/package.json b/package.json index cb7efa8e..60dfcf57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "debug", - "version": "4.3.3", + "version": "4.4.0", "repository": { "type": "git", "url": "git://github.com/debug-js/debug.git" @@ -16,7 +16,7 @@ "LICENSE", "README.md" ], - "author": "Josh Junon ", + "author": "Josh Junon (https://github.com/qix-)", "contributors": [ "TJ Holowaychuk ", "Nathan Rajlich (http://n8.io)", @@ -26,12 +26,12 @@ "scripts": { "lint": "xo", "test": "npm run test:node && npm run test:browser && npm run lint", - "test:node": "istanbul cover _mocha -- test.js", + "test:node": "istanbul cover _mocha -- test.js test.node.js", "test:browser": "karma start --single-run", "test:coverage": "cat ./coverage/lcov.info | coveralls" }, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "devDependencies": { "brfs": "^2.0.1", @@ -44,6 +44,7 @@ "karma-mocha": "^1.3.0", "mocha": "^5.2.0", "mocha-lcov-reporter": "^1.2.0", + "sinon": "^14.0.0", "xo": "^0.23.0" }, "peerDependenciesMeta": { @@ -55,5 +56,10 @@ "browser": "./src/browser.js", "engines": { "node": ">=6.0" + }, + "xo": { + "rules": { + "import/extensions": "off" + } } } diff --git a/src/browser.js b/src/browser.js index cd0fc35d..df8e179e 100644 --- a/src/browser.js +++ b/src/browser.js @@ -125,14 +125,17 @@ function useColors() { return false; } + let m; + // Is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + // eslint-disable-next-line no-return-assign return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // Is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // Is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) || // Double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } diff --git a/src/common.js b/src/common.js index 6d571d28..528c7ecf 100644 --- a/src/common.js +++ b/src/common.js @@ -166,24 +166,62 @@ function setup(env) { createDebug.names = []; createDebug.skips = []; - let i; - const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - const len = split.length; - - for (i = 0; i < len; i++) { - if (!split[i]) { - // ignore empty strings - continue; + const split = (typeof namespaces === 'string' ? namespaces : '') + .trim() + .replace(' ', ',') + .split(',') + .filter(Boolean); + + for (const ns of split) { + if (ns[0] === '-') { + createDebug.skips.push(ns.slice(1)); + } else { + createDebug.names.push(ns); } + } + } - namespaces = split[i].replace(/\*/g, '.*?'); - - if (namespaces[0] === '-') { - createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + /** + * Checks if the given string matches a namespace template, honoring + * asterisks as wildcards. + * + * @param {String} search + * @param {String} template + * @return {Boolean} + */ + function matchesTemplate(search, template) { + let searchIndex = 0; + let templateIndex = 0; + let starIndex = -1; + let matchIndex = 0; + + while (searchIndex < search.length) { + if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) { + // Match character or proceed with wildcard + if (template[templateIndex] === '*') { + starIndex = templateIndex; + matchIndex = searchIndex; + templateIndex++; // Skip the '*' + } else { + searchIndex++; + templateIndex++; + } + } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition + // Backtrack to the last '*' and try to match more characters + templateIndex = starIndex + 1; + matchIndex++; + searchIndex = matchIndex; } else { - createDebug.names.push(new RegExp('^' + namespaces + '$')); + return false; // No match } } + + // Handle trailing '*' in template + while (templateIndex < template.length && template[templateIndex] === '*') { + templateIndex++; + } + + return templateIndex === template.length; } /** @@ -194,8 +232,8 @@ function setup(env) { */ function disable() { const namespaces = [ - ...createDebug.names.map(toNamespace), - ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ...createDebug.names, + ...createDebug.skips.map(namespace => '-' + namespace) ].join(','); createDebug.enable(''); return namespaces; @@ -209,21 +247,14 @@ function setup(env) { * @api public */ function enabled(name) { - if (name[name.length - 1] === '*') { - return true; - } - - let i; - let len; - - for (i = 0, len = createDebug.skips.length; i < len; i++) { - if (createDebug.skips[i].test(name)) { + for (const skip of createDebug.skips) { + if (matchesTemplate(name, skip)) { return false; } } - for (i = 0, len = createDebug.names.length; i < len; i++) { - if (createDebug.names[i].test(name)) { + for (const ns of createDebug.names) { + if (matchesTemplate(name, ns)) { return true; } } @@ -231,19 +262,6 @@ function setup(env) { return false; } - /** - * Convert regexp to namespace - * - * @param {RegExp} regxep - * @return {String} namespace - * @api private - */ - function toNamespace(regexp) { - return regexp.toString() - .substring(2, regexp.toString().length - 2) - .replace(/\.\*\?$/, '*'); - } - /** * Coerce `val`. * diff --git a/src/node.js b/src/node.js index 79bc085c..715560a4 100644 --- a/src/node.js +++ b/src/node.js @@ -187,11 +187,11 @@ function getDate() { } /** - * Invokes `util.format()` with the specified arguments and writes to stderr. + * Invokes `util.formatWithOptions()` with the specified arguments and writes to stderr. */ function log(...args) { - return process.stderr.write(util.format(...args) + '\n'); + return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n'); } /** diff --git a/test.node.js b/test.node.js new file mode 100644 index 00000000..4cc3c051 --- /dev/null +++ b/test.node.js @@ -0,0 +1,40 @@ +/* eslint-env mocha */ + +const assert = require('assert'); +const util = require('util'); +const sinon = require('sinon'); +const debug = require('./src/node'); + +const formatWithOptionsSpy = sinon.spy(util, 'formatWithOptions'); +beforeEach(() => { + formatWithOptionsSpy.resetHistory(); +}); + +describe('debug node', () => { + describe('formatting options', () => { + it('calls util.formatWithOptions', () => { + debug.enable('*'); + const stdErrWriteStub = sinon.stub(process.stderr, 'write'); + const log = debug('formatting options'); + log('hello world'); + assert(util.formatWithOptions.callCount === 1); + stdErrWriteStub.restore(); + }); + + it('calls util.formatWithOptions with inspectOpts', () => { + debug.enable('*'); + const options = { + hideDate: true, + colors: true, + depth: 10, + showHidden: true + }; + Object.assign(debug.inspectOpts, options); + const stdErrWriteStub = sinon.stub(process.stderr, 'write'); + const log = debug('format with inspectOpts'); + log('hello world2'); + assert.deepStrictEqual(util.formatWithOptions.getCall(0).args[0], options); + stdErrWriteStub.restore(); + }); + }); +});