diff --git a/packages/logger/.npmignore b/packages/logger/.npmignore
index 02153da..42fe038 100644
--- a/packages/logger/.npmignore
+++ b/packages/logger/.npmignore
@@ -1,8 +1,8 @@
-dist/*.d.ts.map
node_modules
src
+test
+.babelrc
+.eslintrc.js
.gitignore
webpack.config.js
-tsconfig.json
-.babelrc
-.eslintrc.js
\ No newline at end of file
+tsconfig.*
\ No newline at end of file
diff --git a/packages/logger/README.md b/packages/logger/README.md
new file mode 100644
index 0000000..22309a1
--- /dev/null
+++ b/packages/logger/README.md
@@ -0,0 +1,41 @@
+# @dzeio/logger
+
+A Better logger for your test
+
+## Install
+
+For the browser via `unpkg` use it from Unpkg or download the file locally
+
+```html
+
+
+```
+
+Via Yarn/NPM
+
+```bash
+yarn add @dzeio/logger
+# or
+npm i @dzeio/logger
+```
+
+## Usage
+
+As the Logger Implements the `console` the usage don't vary on their function BUT you have more control
+
+ex:
+
+```js
+import Logger from '@dzeio/logger' // Import the class
+const logger = new Logger('prefix') // initialize it
+// or
+import { logger } from '@dzeio/logger' // Import already initialized one
+
+// You can block Logging for some time
+Logger.isBlocked(true) // false to unblock
+```
diff --git a/packages/logger/package.json b/packages/logger/package.json
index 6fc842e..c1ac423 100644
--- a/packages/logger/package.json
+++ b/packages/logger/package.json
@@ -13,7 +13,7 @@
"browser": "./dist/browser.js",
"types": "./dist/Logger.d.ts",
"dependencies": {
- "chalk": "^4.1.0"
+ "ansi-colors": "^4.1.1"
},
"devDependencies": {
"@babel/core": "^7.10.3",
@@ -29,6 +29,7 @@
},
"scripts": {
"prepublishOnly": "yarn build",
- "build": "webpack --mode=\"production\" && tsc"
+ "build": "webpack --mode=\"production\" && tsc",
+ "test": "ts-node test"
}
}
diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts
index 1b686c7..fa4d616 100644
--- a/packages/logger/src/Logger.ts
+++ b/packages/logger/src/Logger.ts
@@ -1,54 +1,372 @@
-import { white, blue, yellow, green } from 'chalk'
+import colors, { black, white, blue, yellow, green } from 'ansi-colors'
+import { theme, logType, ObjectArray } from './types'
-/**
- * Logger Class
- */
-export default class Logger {
+export default class Logger implements Console {
/**
- * If it is set to true all message won't be shown until it is set to false
+ * The maximun prefix length
*/
- public static isBlocked = false
- private static queue: Array> = []
private static prefixLen = 0
/**
- * Log a message into the console
- * @param prefix the prefix used
- * @param message the message to log
+ * Current theme in use
+ *
+ * - undefined = detect theme
+ * - light = theme for light background
+ * - dark = theme for dark background
*/
- public static log(prefix: string, ...message: Array) {
- this.queue.push(this.formatMessage(prefix, ...message))
- while (this.queue.length > 0 && !this.isBlocked) {
- const item = this.queue.shift()
- if (!item) {
- continue
- }
- console.log(...item)
+ private static theme: theme = undefined
+
+ /**
+ * List of loggers currently in use
+ */
+ private static loggers: Array = []
+
+ /**
+ * Console memory
+ * (IDK what it is)
+ */
+ public memory = console.memory
+
+ // NodeJS console (will be undefined on )
+ /**
+ * NODEJS ONLY
+ * It will be undefined in Browser context
+ */
+ // @ts-ignore
+ public Console = console.Console
+ /**
+ * The messages queue
+ */
+ private queue: Array<{type: logType, msg: Array}> = []
+
+ /**
+ * If true message won't be shown to console
+ * (`urgent` message will still show)
+ */
+ private blocked = false
+
+ /**
+ * `count` function object value
+ */
+ private countCount: ObjectArray = {}
+
+ /**
+ * `time` function object value
+ */
+ private timeCount: ObjectArray = {}
+
+ /**
+ * Construct a new Logger
+ * @param prefix the prefix shown
+ */
+ public constructor(
+ public prefix: string = 'Logger'
+ ) {
+ Logger.loggers.push(this)
+
+ // If Firefox disable colors
+ // @ts-ignore
+ if (typeof InstallTrigger !== 'undefined') {
+ colors.enabled = false
}
}
/**
- * Log a message into the console (passthrough the `Logger.isBlocked` boolean)
- * @param prefix The prefix used
- * @param message the message to log
+ * STATIC FUNCTIONS
*/
- public static urgent(prefix: string, ...message: Array) {
- console.log(...this.formatMessage(prefix, ...message))
+
+ /**
+ * Choose if every loggers should be blocked or not
+ * @param value
+ */
+ public static isBlocked(value: boolean) {
+ for (const lgr of this.loggers) {
+ lgr.blocked = value
+ if (!value) {
+ lgr.processQueue()
+ }
+ }
}
- private static formatMessage(prefix: string, ...message: Array): Array {
- if (this.prefixLen < prefix.length) {
- this.prefixLen = prefix.length
+ /**
+ * Force a specific theme to be used
+ *
+ * (if undefined it will try to detect it)
+ *
+ * @param themeChosen The theme chosen to be overriden
+ */
+ public static forceTheme(themeChosen: theme) {
+ this.theme = themeChosen
+ }
+
+ /**
+ * INSTANCE FUNCTIONS
+ */
+
+ /**
+ * return nothing if `condition` is `true`, log `data` if it is not
+ * @param condition The value tested for being truthy
+ * @param data The message to pass if `condition` is false
+ */
+ public assert(condition?: boolean | undefined, ...data: Array): void {
+ if (!condition) {
+ return this.error('Assertion failed:', ...data)
}
- const els: Array = ['', '']
- if (this.prefixLen > prefix.length) {
- const diff = this.prefixLen - prefix.length
- els[0] = this.buildSpace(diff / 2 - (diff % 2 !== 0 ? 1 : 0))
- els[1] = this.buildSpace(diff / 2)
+ }
+
+ /**
+ * Clear the console/terminal
+ */
+ public clear(): void {
+ console.clear()
+ }
+
+ /**
+ * log the number of times `count` has been called
+ * @param label Display label, default to `default`
+ */
+ public count(label: string = 'default'): void {
+ if (!Object.prototype.hasOwnProperty.call(this.countCount, label)) {
+ this.countCount[label] = 0
+ }
+ this.log(`${label}:`, ++this.countCount[label])
+ }
+
+ /**
+ * Reset the count started with `count` function
+ * @param label Display label, default to `default`
+ */
+ public countReset(label: string = 'default'): void {
+ delete this.countCount[label]
+ }
+
+ /**
+ * log as debug the `data`
+ * (On browser like Chrome in the devtool you have to enable it beforehand)
+ * @param data the data to log
+ */
+ public debug(...data: Array): void {
+ this.process('debug', data)
+ }
+
+ /**
+ * NOTE: Method not fully implemented
+ *
+ * print a full object to the logger
+ * @param item Object to log
+ * @param options (NodeJS only) option for the display
+ */
+ public dir(item?: any, options?: {showHidden?: boolean, depth?: number, colors?: boolean}): void {
+ if (typeof item !== 'object') {
+ return this.log(item)
+ }
+ this.log('Method not fully implemented')
+ if (typeof window !== 'undefined') {
+ console.dir(item)
+ return
+ }
+ console.dir(item, options)
+ }
+
+ /**
+ * Alias for `log` function
+ * @param data data to log
+ */
+ public dirxml(...data: Array): void {
+ this.process('dirxml', data)
+ }
+
+ /**
+ * print to stderr on NodeJS, print with red coloring on browsers
+ * @param data data to log
+ */
+ public error(...data: Array): void {
+ this.process('error', data)
+ }
+
+ /**
+ * Alias to `error` function
+ * @param data data to log
+ */
+ public exception(...data: Array): void { // NOT STANDARD / FIREFOX ONLY
+ this.error(...data)
+ }
+
+ /**
+ * NodeJS -> Increase the indentation of future logs with `label` as header
+ *
+ * Browser -> Group futures logs
+ * @param label labels to use as header
+ */
+ public group(...label: Array): void {
+ console.group(...label)
+ }
+
+ /**
+ * Alias of `group` function
+ * @param label label to use as header
+ */
+ public groupCollapsed(...label: Array): void {
+ this.group(...label)
+ }
+
+ /**
+ * End the current group started with the `group` function
+ */
+ public groupEnd(): void {
+ console.groupEnd()
+ }
+
+ /**
+ * Log to console as Info
+ * (Only Chrome else it is an alias of `log`)
+ * @param data data to log
+ */
+ public info(...data: Array): void {
+ this.process('info', data)
+ }
+
+ /**
+ * Log to console
+ * @param data data to log
+ */
+ public log(...data: Array) {
+ this.process('log', data)
+ }
+
+ /**
+ * make a new profile in browsers or in NodeJS with `--inspect` flag
+ * @param name Profile name
+ */
+ public profile(name?: string) {
+ // @ts-ignore
+ if (console.profile) {
+ // @ts-ignore
+ console.profile(name)
+ } else {
+ throw new Error('profile don\'t exist in the current contexte')
+ }
+ }
+
+ /**
+ * end the current running profile
+ * @param name Profile name
+ */
+ public profileEnd(name?: string) {
+ // @ts-ignore
+ console.profileEnd(name)
+ }
+
+ /**
+ * Print a Table to the console
+ * @param tabularData Table data
+ * @param properties Table properties
+ */
+ public table(tabularData?: any, properties?: Array | undefined): void {
+ console.table(tabularData, properties)
+ }
+
+ /**
+ * Start a timer
+ * @param label Timer label
+ */
+ public time(label: string = 'default'): void {
+ if (!Object.prototype.hasOwnProperty.call(this.timeCount, label)) {
+ this.timeCount[label] = new Date()
+ return
+ }
+ this.warn(`Timer '${label}' already exists.`)
+ }
+
+ /**
+ * End a timer
+ * @param label Timer label
+ */
+ public timeEnd(label: string = 'default'): void {
+ const diff = (new Date()).getTime() - this.timeCount[label].getTime()
+ this.log(`${label}: ${diff}ms - Timer ended`)
+ delete this.timeCount[label]
+ }
+
+ /**
+ * Log to the console with timer before it
+ * @param label Timer label
+ * @param data data to log next to the timer
+ */
+ public timeLog(label: string = 'default', ...data: Array): void {
+ if (!this.timeCount[label]) {
+ this.warn(`Timer '${label}' does not exist`)
+ return
+ }
+ const diff = (new Date()).getTime() - this.timeCount[label].getTime()
+ this.log(`${label}: ${diff}ms`, ...data)
+ }
+
+ /**
+ * Browsers only, Add maker in the browser's Performance or Waterfall tool
+ * @param label Label to use
+ */
+ public timeStamp(label?: string): void {
+ console.timeStamp(label)
+ }
+
+ /**
+ * Print a stack trace to console
+ * @param data data to trace
+ */
+ public trace(...data: Array): void {
+ this.process('trace', data)
+ }
+
+ /**
+ * Warn in the console
+ * (in NodeJS context it is an alias to the `error` function)
+ * @param data data to log
+ */
+ public warn(...data: Array): void {
+ this.process('warn', data)
+ }
+
+ /**
+ * Log to the console but skiping `isBlocked` check
+ * @param data data to log
+ */
+ public urgent(...data: Array) {
+ console.log(...this.formatMessage(data))
+ }
+
+ /**
+ * Precoess a message sent by one of the public functions
+ * @param type logType
+ * @param message message to log
+ */
+ private process(type: logType, message: Array) {
+ this.queue.push({type, msg: this.formatMessage(message)})
+ this.processQueue()
+ }
+
+ /**
+ * Format a message for the console
+ * @param message message to format
+ */
+ private formatMessage(message: Array): Array {
+ const prefix = this.prefix
+ const prefixLen = prefix.length
+
+ if (Logger.prefixLen < prefixLen) {
+ Logger.prefixLen = prefixLen
+ }
+
+ const spacers: Array = ['', '']
+ if (Logger.prefixLen > prefixLen) {
+ const diff = Logger.prefixLen - prefixLen
+ const diff2 = diff /2
+ spacers[0] = this.buildSpace(diff2 - (diff % 2 !== 0 ? 1 : 0))
+ spacers[1] = this.buildSpace(diff2)
}
const res: Array = [
- `${white('[ ')}${els[0]}${blue(prefix)}${els[1]}${white(' ]')}:` // prefix
+ `${this.blackOrWhite('[ ')}${spacers[0]}${blue(prefix)}${spacers[1]}${this.blackOrWhite(' ]')}:`
].concat(
message.map((el) => {
if (typeof el === 'object') {
@@ -60,11 +378,48 @@ export default class Logger {
return res
}
- private static buildSpace(count: number): string {
+ /**
+ * Process Waiting queue
+ */
+ private processQueue() {
+ while (this.queue.length > 0 && !this.blocked) {
+ const item = this.queue.shift()
+ if (!item) {
+ continue
+ }
+ if (item.type === 'trace') {
+ console.log(item.msg.shift())
+ }
+ console[item.type](...item.msg)
+ }
+ }
+
+ /**
+ * Build a new string of `count` spaces
+ * @param count number of spaces to add
+ */
+ private buildSpace(count: number): string {
let str = ''
for(let i = 0; i < count; i++) {
str += ' '
}
return str
}
+
+ /**
+ * Color the text in black or white depending on `theme` variable or detection
+ * @param text the text to color
+ */
+ private blackOrWhite(text: string): string {
+ if ((!Logger.theme && typeof window !== 'undefined') || Logger.theme === 'light') {
+ return black(text)
+ }
+ return white(text)
+ }
+
}
+
+/**
+ * Export a default Logger
+ */
+export const logger = new Logger()
diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts
index 74b903b..0fab1a4 100644
--- a/packages/logger/src/index.ts
+++ b/packages/logger/src/index.ts
@@ -2,5 +2,13 @@ import Logger from './Logger'
// Browser Import
+/**
+ * Init Logger in global context and add function to replace default console
+ */
+
// @ts-ignore
window.Logger = Logger
+// @ts-ignore
+window.initConsole = function() {
+ window.console = new Logger('Console')
+}
diff --git a/packages/logger/src/types.ts b/packages/logger/src/types.ts
new file mode 100644
index 0000000..c17879f
--- /dev/null
+++ b/packages/logger/src/types.ts
@@ -0,0 +1,17 @@
+/**
+ * Object Array
+ */
+export interface ObjectArray {
+ [key: string]: T
+}
+
+/**
+ * used Internally,
+ * the different types of logs
+ */
+export type logType = 'debug' | 'dir' | 'dirxml' | 'error' | 'info' | 'log' | 'trace' | 'warn'
+
+/**
+ * The possible themes
+ */
+export type theme = undefined | 'light' | 'dark'
diff --git a/packages/logger/test/index.ts b/packages/logger/test/index.ts
new file mode 100644
index 0000000..d8f6d65
--- /dev/null
+++ b/packages/logger/test/index.ts
@@ -0,0 +1,54 @@
+import { logger as console } from '../src/Logger'
+
+/**
+ * This test file is simple :D
+ */
+
+// Should remove the precedent line
+console.clear()
+
+// Start a timer
+console.time()
+console.timeLog(undefined, 'Started Timer')
+
+// Test assert
+console.log('Assert')
+console.assert(true, 'i am true') // should print nothing
+console.assert(false, 'i am false') // Should print 'i am false'
+
+// all the different logs
+console.debug('debug')
+console.dir('dir')
+console.dirxml('dirxml')
+console.error('error')
+console.info('info')
+console.log('log')
+console.trace('trace')
+console.warn('warn')
+
+// Timelog
+console.timeLog(undefined, 'timeLog')
+
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.group('New group')
+console.log('Log in a group')
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+console.groupEnd()
+
+console.table([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], ['a'])
+
+// TimeEnd
+console.timeEnd()
diff --git a/packages/logger/tsconfig.test.json b/packages/logger/tsconfig.test.json
new file mode 100644
index 0000000..43d7ac9
--- /dev/null
+++ b/packages/logger/tsconfig.test.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "files": [
+ "test/index.ts"
+ ]
+}