Comparing version 1.1.0 to 1.2.0
@@ -27,7 +27,6 @@ # Contributing to Signale | ||
- [`enhancement` issues](https://github.com/klauscfhq/signale/labels/enhancement) are features we are open to including | ||
- [`feature request` issues](https://github.com/klauscfhq/signale/labels/feature%20request) are features we are open to including | ||
- [`bug` issues](https://github.com/klauscfhq/signale/labels/bug) are known bugs we would like to fix | ||
- [`needs testing` issues](https://github.com/klauscfhq/signale/labels/needs%20testing) are features that we are still working on improving | ||
- [`future` issues](https://github.com/klauscfhq/signale/labels/future) are those that we'd like to get to, but not anytime soon. Please check before working on these since we may not yet want to take on the burden of supporting those features | ||
- on the [`help wanted`](https://github.com/klauscfhq/signale/labels/future) label you can always find something exciting going on | ||
- on the [`help wanted`](https://github.com/klauscfhq/signale/labels/help%20wanted) label you can always find something exciting going on | ||
@@ -34,0 +33,0 @@ You may find an issue is assigned, or has the [`assigned` label](https://github.com/klauscfhq/signale/labels/assigned). Please double-check before starting on this issue because somebody else is likely already working on it |
MIT License | ||
Copyright (c) 2018 Klaus Sinani | ||
Copyright (c) Klaus Sinani <klauscfhq@protonmail.com> | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "signale", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "👋 Hackable console logger", | ||
@@ -38,2 +38,3 @@ "license": "MIT", | ||
"default": { | ||
"coloredInterpolation": false, | ||
"displayScope": true, | ||
@@ -46,3 +47,6 @@ "displayBadge": true, | ||
"underlineLabel": true, | ||
"underlineMessage": false | ||
"underlineMessage": false, | ||
"underlinePrefix": false, | ||
"underlineSuffix": false, | ||
"uppercaseLabel": false | ||
} | ||
@@ -49,0 +53,0 @@ }, |
160
readme.md
@@ -32,5 +32,7 @@ <h1 align="center"> | ||
- Custom pluggable loggers | ||
- Interactive and regular modes | ||
- Filename, date and timestamp support | ||
- Scoped loggers and timers | ||
- Configurable writable streams | ||
- String interpolation support | ||
- Multiple configurable writable streams | ||
- Simple and minimal syntax | ||
@@ -49,2 +51,4 @@ - Globally configurable through `package.json` | ||
- [Development](#development) | ||
- [Related](#related) | ||
- [Team](#team) | ||
- [License](#license) | ||
@@ -95,3 +99,3 @@ | ||
signale.debug('Hello', 'from', 'L59'); | ||
signale.pending('Write release notes for 1.2.0'); | ||
signale.pending('Write release notes for %s', '1.2.0'); | ||
signale.fatal(new Error('Unable to acquire lock')); | ||
@@ -114,2 +118,4 @@ signale.watch('Recursively watching build directory...'); | ||
const options = { | ||
disabled: false, | ||
interactive: false, | ||
stream: process.stdout, | ||
@@ -140,4 +146,2 @@ scope: 'custom', | ||
Additionally, all default loggers can be overridden to your own preference. | ||
Here is an example where we override the default `error` and `success` loggers. | ||
@@ -152,3 +156,2 @@ | ||
badge: '!!', | ||
color: 'red', | ||
label: 'fatal error' | ||
@@ -158,3 +161,2 @@ }, | ||
badge: '++', | ||
color: 'green', | ||
label: 'huge success' | ||
@@ -178,16 +180,30 @@ } | ||
The `options` object can hold the `stream`, `scope` and `types` attributes, where the first yields the destination to which the logged data is written, the second corresponds to the name of the scope the logger is reporting from and the third is where the objects named after the custom loggers reside. | ||
The `options` object can hold any of the following attributes: `disabled`, `interactive`, `stream`, `scope` and `types`. | ||
##### `disabled` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Disables the logging functionality of all loggers belonging to the created instance. | ||
##### `interactive` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Switches all loggers belonging to the created instance into the interactive mode. | ||
##### `stream` | ||
- Type: `Writable stream` | ||
- Type: `Writable stream` or `Array of Writable streams` | ||
- Default: `process.stdout` | ||
Destination to which the data is written, can be any valid [Writable stream](https://nodejs.org/api/stream.html#stream_writable_streams). | ||
Destination to which the data is written, can be a single valid [Writable stream](https://nodejs.org/api/stream.html#stream_writable_streams) or an array holding multiple valid Writable streams. | ||
##### `scope` | ||
- Type: `String` | ||
- Type: `String` or `Array of Strings` | ||
Name of the scope. | ||
Name of the scope the logger is reporting from. | ||
@@ -237,3 +253,3 @@ ##### `types` | ||
To create a scoped logger based on an already existing one, use the `scope()` function, which will return a new signale instance, inheriting all custom loggers, timers, stream and configuration from the initial one. | ||
To create a scoped logger based on an already existing one, use the `scope()` function, which will return a new signale instance, inheriting all custom loggers, timers, streams, configuration, interactive mode & disabled statuses from the initial one. | ||
@@ -263,2 +279,47 @@ ```js | ||
### Interactive Loggers | ||
To initialize an interactive logger, create a new signale instance with the [`interactive`](#interactive) attribute set to `true`. While into the interactive mode, previously logged messages originating from an interactive logger, will be overridden only by new ones originating from the same or a different interactive logger. Note that regular messages originating from regular loggers are not overridden by the interactive ones. | ||
```js | ||
const {Signale} = require('signale'); | ||
const interactive = new Signale({interactive: true, scope: 'interactive'}); | ||
interactive.await('[%d/4] - Process A', 1); | ||
setTimeout(() => { | ||
interactive.success('[%d/4] - Process A', 2); | ||
setTimeout(() => { | ||
interactive.await('[%d/4] - Process B', 3); | ||
setTimeout(() => { | ||
interactive.error('[%d/4] - Process B', 4); | ||
setTimeout(() => {}, 1000); | ||
}, 1000); | ||
}, 1000); | ||
}, 1000); | ||
``` | ||
### Writable Streams | ||
By default, all signale instances log their messages to the `process.stdout` stream. This can be modified, to match your own preference, through the [`stream`](#stream) property, where you can define a single or multiple valid Writable streams, which will be used by all logger types to log your data. Additionally, it is possible to define one or more Writable streams exclusively for a specific logger type, thus write data independently from the rest logger types. | ||
```js | ||
const {Signale} = require('signale'); | ||
const options = { | ||
stream: process.stderr, // All loggers will now write to `process.stderr` | ||
types: { | ||
error: { | ||
// Only `error` will write to both `process.stdout` & `process.stderr` | ||
stream: [process.stdout, process.stderr] | ||
} | ||
} | ||
}; | ||
const signale = new Signale(options); | ||
signale.success('Message will appear on `process.stderr`'); | ||
signale.error('Message will appear on both `process.stdout` & `process.stderr`'); | ||
``` | ||
### Timers | ||
@@ -297,2 +358,3 @@ | ||
"signale": { | ||
"coloredInterpolation": false, | ||
"displayScope": true, | ||
@@ -305,3 +367,6 @@ "displayBadge": true, | ||
"underlineLabel": true, | ||
"underlineMessage": false | ||
"underlineMessage": false, | ||
"underlinePrefix": false, | ||
"underlineSuffix": false, | ||
"uppercaseLabel": false | ||
} | ||
@@ -314,2 +379,9 @@ } | ||
##### `coloredInterpolation` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Display the arguments, which replace the placeholder tokens on string interpolation, colored. | ||
##### `displayScope` | ||
@@ -371,2 +443,23 @@ | ||
##### `underlinePrefix` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Underline the logger prefix. | ||
##### `underlineSuffix` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Underline the logger suffix. | ||
##### `uppercaseLabel` | ||
- Type: `Boolean` | ||
- Default: `false` | ||
Display the label of the logger in uppercase. | ||
</details> | ||
@@ -484,3 +577,3 @@ | ||
signale.complete({prefix: '[task]', message: 'Fix issue #59', suffix: '(@klauscfhq)'}); | ||
signale.complete({prefix: '[task]', message: ['Fix issue #%d', 59], suffix: '(@klauscfhq)'}); | ||
//=> [task] ☒ complete Fix issue #59 (@klauscfhq) | ||
@@ -617,2 +710,36 @@ ``` | ||
#### signale.`disable()` | ||
Disables the logging functionality of all loggers belonging to a specific instance. | ||
```js | ||
const signale = require('signale'); | ||
signale.success('foo'); | ||
//=> ✔ success foo | ||
signale.disable(); | ||
signale.success('foo'); | ||
//=> | ||
``` | ||
#### signale.`enable()` | ||
Enables the logging functionality of all loggers belonging to a specific instance. | ||
```js | ||
const signale = require('signale'); | ||
signale.disable(); | ||
signale.success('foo'); | ||
//=> | ||
signale.enable(); | ||
signale.success('foo'); | ||
//=> ✔ success foo | ||
``` | ||
## Development | ||
@@ -627,2 +754,7 @@ | ||
## Related | ||
- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right | ||
- [figures](https://github.com/sindresorhus/figures) - Unicode symbols | ||
## Team | ||
@@ -629,0 +761,0 @@ |
111
signale.js
'use strict'; | ||
const util = require('util'); | ||
const path = require('path'); | ||
@@ -6,8 +7,12 @@ const chalk = require('chalk'); | ||
const pkgConf = require('pkg-conf'); | ||
const types = require('./types'); | ||
const pkg = require('./package.json'); | ||
const defaultTypes = require('./types'); | ||
let isPreviousLogInteractive = false; | ||
const defaults = pkg.options.default; | ||
const namespace = pkg.name; | ||
const arrayify = x => { | ||
return Array.isArray(x) ? x : [x]; | ||
}; | ||
const now = () => Date.now(); | ||
@@ -20,9 +25,11 @@ const timeSpan = then => { | ||
constructor(options = {}) { | ||
this._interactive = options.interactive || false; | ||
this._config = Object.assign(this.packageConfiguration, options.config); | ||
this._customTypes = Object.assign({}, options.types); | ||
this._disabled = options.disabled || false; | ||
this._scopeName = options.scope || ''; | ||
this._timers = options.timers || new Map(); | ||
this._types = Object.assign({}, types, this._customTypes); | ||
this._types = this._mergeTypes(defaultTypes, this._customTypes); | ||
this._stream = options.stream || process.stdout; | ||
this._longestLabel = types.start.label.length; | ||
this._longestLabel = defaultTypes.start.label.length; | ||
@@ -47,3 +54,5 @@ Object.keys(this._types).forEach(type => { | ||
config: this._config, | ||
disabled: this._disabled, | ||
types: this._customTypes, | ||
interactive: this._interactive, | ||
timers: this._timers, | ||
@@ -54,2 +63,6 @@ stream: this._stream | ||
get isEnabled() { | ||
return !this._disabled; | ||
} | ||
get date() { | ||
@@ -69,7 +82,9 @@ return new Date().toLocaleDateString(); | ||
const callers = stack.map(x => path.basename(x.getFileName())); | ||
const callers = stack.map(x => x.getFileName()); | ||
return callers.find(x => { | ||
const firstExternalFilePath = callers.find(x => { | ||
return x !== callers[0]; | ||
}); | ||
return firstExternalFilePath ? path.basename(firstExternalFilePath) : 'anonymous'; | ||
} | ||
@@ -85,8 +100,11 @@ | ||
_logger(type, ...messageObj) { | ||
this._log(this._buildSignale(this._types[type], ...messageObj)); | ||
_mergeTypes(standard, custom) { | ||
Object.keys(custom).forEach(type => { | ||
standard[type] = Object.assign({}, standard[type], custom[type]); | ||
}); | ||
return standard; | ||
} | ||
_log(message) { | ||
this._stream.write(message + '\n'); | ||
_formatStream(stream) { | ||
return arrayify(stream); | ||
} | ||
@@ -114,2 +132,20 @@ | ||
_formatMessage(str, type) { | ||
str = arrayify(str); | ||
if (this._config.coloredInterpolation) { | ||
const _ = Object.assign({}, util.inspect.styles); | ||
Object.keys(util.inspect.styles).forEach(x => { | ||
util.inspect.styles[x] = type.color || _[x]; | ||
}); | ||
str = util.formatWithOptions({colors: true}, ...str); | ||
util.inspect.styles = Object.assign({}, _); | ||
return str; | ||
} | ||
return util.format(...str); | ||
} | ||
_meta() { | ||
@@ -136,2 +172,6 @@ const meta = []; | ||
_hasAdditional({suffix, prefix}, args, type) { | ||
return (suffix || prefix) ? '' : this._formatMessage(args, type); | ||
} | ||
_buildSignale(type, ...args) { | ||
@@ -145,7 +185,7 @@ let [msg, additional] = [{}, {}]; | ||
const [{prefix, message, suffix}] = args; | ||
msg = message; | ||
additional = Object.assign({}, {suffix, prefix}); | ||
msg = message ? this._formatMessage(message, type) : this._hasAdditional(additional, args, type); | ||
} | ||
} else { | ||
msg = args.join(' '); | ||
msg = this._formatMessage(args, type); | ||
} | ||
@@ -156,3 +196,7 @@ | ||
if (additional.prefix) { | ||
signale.push(additional.prefix); | ||
if (this._config.underlinePrefix) { | ||
signale.push(chalk.underline(additional.prefix)); | ||
} else { | ||
signale.push(additional.prefix); | ||
} | ||
} | ||
@@ -165,10 +209,11 @@ | ||
if (this._config.displayLabel && type.label) { | ||
const label = this._config.uppercaseLabel ? type.label.toUpperCase() : type.label; | ||
if (this._config.underlineLabel) { | ||
signale.push(chalk[type.color].underline(type.label).padEnd(this._longestLabel + 20)); | ||
signale.push(chalk[type.color].underline(label).padEnd(this._longestLabel + 20)); | ||
} else { | ||
signale.push(chalk[type.color](type.label.padEnd(this._longestLabel + 1))); | ||
signale.push(chalk[type.color](label.padEnd(this._longestLabel + 1))); | ||
} | ||
} | ||
if (msg instanceof Error) { | ||
if (msg instanceof Error && msg.stack) { | ||
const [name, ...rest] = msg.stack.split('\n'); | ||
@@ -191,3 +236,7 @@ if (this._config.underlineMessage) { | ||
if (additional.suffix) { | ||
signale.push(additional.suffix); | ||
if (this._config.underlineSuffix) { | ||
signale.push(chalk.underline(additional.suffix)); | ||
} else { | ||
signale.push(additional.suffix); | ||
} | ||
} | ||
@@ -198,2 +247,24 @@ | ||
_write(stream, message) { | ||
if (this._interactive && isPreviousLogInteractive) { | ||
stream.moveCursor(0, -1); | ||
stream.clearLine(); | ||
stream.cursorTo(0); | ||
} | ||
stream.write(message + '\n'); | ||
isPreviousLogInteractive = this._interactive; | ||
} | ||
_log(message, streams = this._stream) { | ||
if (this.isEnabled) { | ||
this._formatStream(streams).forEach(stream => { | ||
this._write(stream, message); | ||
}); | ||
} | ||
} | ||
_logger(type, ...messageObj) { | ||
this._log(this._buildSignale(this._types[type], ...messageObj), this._types[type].stream); | ||
} | ||
config(configObj) { | ||
@@ -203,2 +274,10 @@ this.configuration = configObj; | ||
disable() { | ||
this._disabled = true; | ||
} | ||
enable() { | ||
this._disabled = false; | ||
} | ||
scope(...name) { | ||
@@ -205,0 +284,0 @@ if (name.length === 0) { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
793505
357
750