Skip to content

Commit

Permalink
Align with WHATWG
Browse files Browse the repository at this point in the history
  • Loading branch information
kasperisager committed Nov 23, 2024
1 parent a19ac22 commit 8c5a79f
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 86 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bare-console

Simple debugging console for JavaScript.
WHATWG debugging console for JavaScript.

```
npm i bare-console
Expand All @@ -11,7 +11,7 @@ npm i bare-console
```js
const Console = require('bare-console')

const console = new Console({ stdout: process.stdout, stderr: process.stderr })
const console = new Console({ stdout, stderr })

console.log('Hello')
console.error(new Error('Something happened'))
Expand Down
128 changes: 90 additions & 38 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,93 @@
const { formatWithOptions } = require('bare-format')
const hrtime = require('bare-hrtime')

module.exports = class Console {
module.exports = exports = class Console {
constructor(opts = {}) {
this._stdout = adaptStream(opts.stdout)
this._stderr = adaptStream(opts.stderr)
const { stdout, stderr = stdout, colors = stdout.isTTY === true } = opts

this._colors = opts.colors === true
this._stdout = stdout
this._stderr = stderr
this._colors = colors
this._timers = new Map()

if (opts.bind) {
this.log = this.log.bind(this)
this.warn = this.warn.bind(this)
this.error = this.error.bind(this)
this.time = this.time.bind(this)
this.timeEnd = this.timeEnd.bind(this)
this.trace = this.trace.bind(this)
}
this._counters = new Map()
}

log(...args) {
// https://console.spec.whatwg.org/#log
log = (...data) => {
this._stdout.write(
formatWithOptions({ colors: this._colors }, ...args) + '\n'
formatWithOptions({ colors: this._colors }, ...data) + '\n'
)
}

warn(...args) {
this._stderr.write(
formatWithOptions({ colors: this._colors }, ...args) + '\n'
)
}
// https://console.spec.whatwg.org/#debug
debug = this.log

// https://console.spec.whatwg.org/#info
info = this.log

error(...args) {
// https://console.spec.whatwg.org/#error
error = (...data) => {
this._stderr.write(
formatWithOptions({ colors: this._colors }, ...args) + '\n'
formatWithOptions({ colors: this._colors }, ...data) + '\n'
)
}

time(label = 'default') {
// https://console.spec.whatwg.org/#warn
warn = this.error

// https://console.spec.whatwg.org/#time
time = (label = 'default') => {
if (this._timers.has(label)) {
this.error(
"Warning: Label '" + label + "' already exists for console.time()"
)
this.warn(`Warning: Label '${label}' already exists for console.time()`)
return
}

this._timers.set(label, hrtime())
}

timeEnd(label = 'default') {
// https://console.spec.whatwg.org/#timelog
timeLog = (label = 'default', ...data) => {
const started = this._timers.get(label)

if (!started) {
this.error("Warning: No such label '" + label + "' for console.timeEnd()")
if (started === undefined) {
this.warn(`Warning: No such label '${label}' for console.timeEnd()`)
return
}

const d = hrtime(started)
const ms = d[0] * 1e3 + d[1] / 1e6
const elapsed = hrtime(started)
const ms = elapsed[0] * 1e3 + elapsed[1] / 1e6

if (ms > 1000) this.log(`${label}: ${(ms / 1000).toFixed(3)}s`, ...data)
else this.log(`${label}: ${ms.toFixed(3)}ms`, ...data)
}

// https://console.spec.whatwg.org/#timeend
timeEnd = (label = 'default') => {
this.timeLog(label)

this._timers.delete(label)
}

if (ms > 1000) this.log(label + ': ' + (ms / 1000).toFixed(3) + 's')
else this.log(label + ': ' + ms.toFixed(3) + 'ms')
// https://console.spec.whatwg.org/#count
count = (label = 'default') => {
const count = this._counters.get(label) || 1

this.log(`${label}: ${count}`)

this._counters.set(label, count + 1)
}

// https://console.spec.whatwg.org/#countreset
countReset = (label = 'default') => {
this._counters.delete(label)
}

trace(...args) {
// https://console.spec.whatwg.org/#trace
trace = (...data) => {
const err = {
name: 'Trace',
message: formatWithOptions({ colors: this._colors }, ...args)
message: formatWithOptions({ colors: this._colors }, ...data),
stack: null
}

if (Error.captureStackTrace) {
Expand All @@ -76,8 +96,40 @@ module.exports = class Console {

this.error(err.stack)
}
}

function adaptStream(stream) {
return typeof stream === 'function' ? { write: stream } : stream
// https://console.spec.whatwg.org/#assert
assert = (condition, ...data) => {
if (condition) return

if (data.length === 0) data.push('Assertion failed')
else if (typeof data[0] !== 'string') data.unshift('Assertion failed')
else data[0] = `Assertion failed: ${data[0]}`

this.error(...data)
}

// https://console.spec.whatwg.org/#clear
clear = () => {};

[Symbol.for('bare.inspect')]() {
return {
__proto__: { constructor: Console },

assert: this.assert,
clear: this.clear,
count: this.count,
countReset: this.countReset,
debug: this.debug,
error: this.error,
info: this.info,
log: this.log,
time: this.time,
timeEnd: this.timeEnd,
timeLog: this.timeLog,
trace: this.trace,
warn: this.warn
}
}
}

exports.Console = exports // For Node.js compatibility
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"name": "bare-console",
"version": "5.1.1",
"description": "Simple debugging console for JavaScript",
"main": "index.js",
"description": "WHATWG debugging console for JavaScript",
"exports": {
".": "./index.js",
"./package": "./package.json"
},
"files": [
"index.js"
],
"scripts": {
"test": "standard && bare test.js"
"test": "prettier . --check && bare test.js"
},
"repository": {
"type": "git",
Expand All @@ -20,12 +23,10 @@
},
"homepage": "https://github.com/holepunchto/bare-console#readme",
"dependencies": {
"bare-events": "^2.2.0",
"bare-format": "^1.0.0",
"bare-hrtime": "^2.0.0"
},
"devDependencies": {
"bare-stream": "^2.0.0",
"brittle": "^3.1.1",
"prettier": "^3.3.3",
"prettier-config-standard": "^7.0.0"
Expand Down
96 changes: 55 additions & 41 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
const test = require('brittle')
const { Writable } = require('bare-stream')
const Console = require('.')

test('log', (t) => {
t.plan(1)

const stdout = new Writable({
write(data, encoding, cb) {
t.alike(data, Buffer.from('hello\n'))
cb(null)
const stdout = {
write(data) {
t.alike(data, 'hello\n')
}
})
}

const stderr = new Writable({
const stderr = {
write() {
t.fail()
}
})
}

const console = new Console({ stdout, stderr })

Expand All @@ -26,18 +24,17 @@ test('log', (t) => {
test('log with format', (t) => {
t.plan(1)

const stdout = new Writable({
write(data, encoding, cb) {
t.alike(data, Buffer.from('hello world\n'))
cb(null)
const stdout = {
write(data) {
t.alike(data, 'hello world\n')
}
})
}

const stderr = new Writable({
const stderr = {
write() {
t.fail()
}
})
}

const console = new Console({ stdout, stderr })

Expand All @@ -47,18 +44,17 @@ test('log with format', (t) => {
test('warn', (t) => {
t.plan(1)

const stdout = new Writable({
const stdout = {
write() {
t.fail()
}
})
}

const stderr = new Writable({
write(data, encoding, cb) {
t.alike(data, Buffer.from('hello\n'))
cb(null)
const stderr = {
write(data) {
t.alike(data, 'hello\n')
}
})
}

const console = new Console({ stdout, stderr })

Expand All @@ -68,43 +64,61 @@ test('warn', (t) => {
test('error', (t) => {
t.plan(1)

const stdout = new Writable({
const stdout = {
write() {
t.fail()
}
})
}

const stderr = new Writable({
write(data, encoding, cb) {
t.alike(data, Buffer.from('hello\n'))
cb(null)
const stderr = {
write(data) {
t.alike(data, 'hello\n')
}
})
}

const console = new Console({ stdout, stderr })

console.error('hello')
})

test('console is bound to its context', (t) => {
test('assert', (t) => {
t.plan(1)

const stdout = {
write() {
t.fail()
}
}

const stderr = {
write(data) {
t.alike(data, 'Assertion failed: falsy\n')
}
}

const console = new Console({ stdout, stderr })

console.assert(1, 'truthy')
console.assert(0, 'falsy')
})

test('bound console methods', (t) => {
t.plan(2)

const stdout = new Writable({
write(data, encoding, cb) {
const stdout = {
write() {
t.pass()
cb(null)
}
})
}

const stderr = new Writable({
write(data, encoding, cb) {
const stderr = {
write() {
t.pass()
cb(null)
}
})
}

const console = new Console({ stdout, stderr, bind: true })
const { log, error } = new Console({ stdout, stderr })

queueMicrotask(console.log, 42)
queueMicrotask(console.error, new Error('hello'))
log('hello')
error('world')
})

0 comments on commit 8c5a79f

Please sign in to comment.