From b52293fc1cf3578371f8e9201881b7017f10ef78 Mon Sep 17 00:00:00 2001 From: Marais Rossouw Date: Mon, 20 May 2024 10:22:23 +1000 Subject: [PATCH] chore: start the process to get it onto jsr --- src/generic.ts | 24 ++++ src/global.d.ts | 2 - src/index.test.ts | 234 +++++++++++++++++----------------- src/index.ts | 88 ------------- src/index.types.ts | 43 ------- src/json.d.ts | 3 - src/json.test.ts | 67 +++++----- src/json.ts | 4 +- src/levels.ts | 6 + src/{index.d.ts => logger.ts} | 70 ++++++---- src/node.ts | 38 ++++++ src/utils.d.ts | 18 --- src/utils.test.ts | 126 +++++++++--------- src/utils.ts | 15 ++- test/helpers/index.ts | 12 -- test/helpers/setup.js | 4 - 16 files changed, 343 insertions(+), 411 deletions(-) create mode 100644 src/generic.ts delete mode 100644 src/global.d.ts delete mode 100644 src/index.ts delete mode 100644 src/index.types.ts delete mode 100644 src/json.d.ts create mode 100644 src/levels.ts rename src/{index.d.ts => logger.ts} (62%) create mode 100644 src/node.ts delete mode 100644 src/utils.d.ts delete mode 100644 test/helpers/index.ts delete mode 100644 test/helpers/setup.js diff --git a/src/generic.ts b/src/generic.ts new file mode 100644 index 0000000..cc01646 --- /dev/null +++ b/src/generic.ts @@ -0,0 +1,24 @@ +/// + +import { diary as _diary, type LogEvent, type Reporter, type Diary } from './logger'; + +function reporter(event: LogEvent) { + let label = ''; + const fn = console[event.level === 'fatal' ? 'error' : event.level]; + + if (event.name) label += `[${event.name}] `; + + if (typeof event.messages[0] === 'object') { + return void fn(label, ...event.messages); + } else { + const message = event.messages.shift(); + return void fn(label + message, ...event.messages); + } +} + +export const diary = (name: string, onEmit: Reporter = reporter): Diary => _diary(name, onEmit); + +const { fatal, error, warn, debug, info, log } = diary('', reporter); +export { fatal, error, warn, debug, info, log }; +export type { Diary, LogEvent, LogLevels, Reporter } from './logger'; +export { enable } from './logger'; \ No newline at end of file diff --git a/src/global.d.ts b/src/global.d.ts deleted file mode 100644 index 1c56e4a..0000000 --- a/src/global.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const __TARGET__: 'browser' | 'worker' | 'node' | 'neutral'; -declare const _FORMAT: typeof import('util').format; \ No newline at end of file diff --git a/src/index.test.ts b/src/index.test.ts index 0bd8556..df400aa 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,163 +1,161 @@ +import {suite, test} from 'uvu'; import * as assert from 'uvu/assert'; -import * as diary from '.'; -import { enable } from '.'; -import { describe } from '../test/helpers'; import { restoreAll, spy, spyOn } from 'nanospy'; -import type { Reporter } from 'diary'; + +import * as diary from './logger' +import type {Reporter} from './logger' + +import * as GENERIC from './generic'; +import * as NODE from './node'; const levels = ['fatal', 'error', 'warn', 'debug', 'info', 'log'] as const; -describe('api', (it) => { - it.after.each(() => { - restoreAll(); - }); +function before() { + diary.enable('*'); + restoreAll(); +} + +test.before.each(before); - it('exports', () => { +Object.entries({ generic: GENERIC, node: NODE }).forEach(([name, mod]) => { + const s = suite(`mod :: ${name}`); + s.before.each(before); + + s('exports', () => { [...levels, 'diary'].forEach((verb) => { assert.type( // @ts-ignore - diary[verb], + mod[verb], 'function', `Expected diary to have #${verb} function`, ); }); }); - it('default diary should not be named', () => { - const log_output = spyOn(console, 'info', () => {}); + s.run(); +}); - diary.info('info'); - assert.equal(log_output.calls[0].join(''), 'ℹ info info'); - diary.diary('named').info('info'); - assert.equal(log_output.calls[1].join(''), 'ℹ info [named] info'); - }); +test('should allow object logging', () => { + const reporter = spy(); + const scope = diary.diary('error', reporter); - it('#error persist', () => { - const reporter = spy(); - const scope = diary.diary('error', reporter); + scope.info('info'); + assert.equal(reporter.callCount, 1); + assert.equal(reporter.calls[0][0], 'ℹ info info'); + scope.info({ foo: 'bar' }); - scope.error(new Error('some error')); + assert.equal(reporter.calls[1][0], "ℹ info { foo: 'bar' }"); +}); - assert.equal(reporter.callCount, 1); - assert.equal(reporter.calls[0][0].messages[0].message, 'some error'); - assert.instance(reporter.calls[0][0].messages[0], Error); - }); +const allows = suite('allows'); +allows.before.each(before); - it('should allow object logging', () => { - const log_output = spyOn(console, 'info', () => {}); +allows('should only allow some scopes', () => { + const reporter = spy(); + const scopeA = diary.diary('scope:a', reporter); + const scopeB = diary.diary('scope:b', reporter); - diary.info('info'); - assert.equal(log_output.callCount, 1); - assert.equal(log_output.calls[0][0], 'ℹ info info'); - diary.info({ foo: 'bar' }); + diary.enable('scope:a'); - assert.equal(log_output.calls[1][0], "ℹ info { foo: 'bar' }"); - }); + scopeA.info('info a'); + scopeB.info('info b'); + scopeB.info('info b'); + scopeA.info('info a'); + + assert.equal( + reporter.calls.flatMap((i) => i[0].messages), + ['info a', 'info a'], + ); }); -describe('allows', (it) => { - it('should only allow some scopes', () => { - const reporter = spy(); - const scopeA = diary.diary('scope:a', reporter); - const scopeB = diary.diary('scope:b', reporter); +allows('should allow nested scopes', () => { + const reporter = spy(); + const scopeA = diary.diary('scope:a', reporter); + const scopeB = diary.diary('scope:b', reporter); - enable('scope:a'); + diary.enable('scope:*'); - scopeA.info('info a'); - scopeB.info('info b'); - scopeB.info('info b'); - scopeA.info('info a'); + scopeA.info('info a'); + scopeB.info('info b'); - assert.equal( - reporter.calls.flatMap((i) => i[0].messages), - ['info a', 'info a'], - ); - }); + assert.equal( + reporter.calls.flatMap((i) => i[0].messages), + ['info a', 'info b'], + ); +}); - it('should allow nested scopes', () => { - const reporter = spy(); - const scopeA = diary.diary('scope:a', reporter); - const scopeB = diary.diary('scope:b', reporter); +allows('should allow multiple allows per enable', () => { + const reporter = spy(); - enable('scope:*'); + const scopeA = diary.diary('scope:a', reporter); + const scopeB = diary.diary('scope:b', reporter); - scopeA.info('info a'); - scopeB.info('info b'); + diary.enable('scope:a,blah'); - assert.equal( - reporter.calls.flatMap((i) => i[0].messages), - ['info a', 'info b'], - ); - }); + scopeA.info('info a'); + scopeB.info('info b'); - it('should allow multiple allows per enable', () => { - const reporter = spy(); + diary.enable('blah,scope:a'); + + scopeA.info('info a'); + scopeB.info('info b'); + scopeB.info('info b'); + scopeA.info('info a'); + + diary.enable('foo,bar:*,scope:,scope:*'); - const scopeA = diary.diary('scope:a', reporter); - const scopeB = diary.diary('scope:b', reporter); + scopeA.info('info a'); + scopeB.info('info b'); - enable('scope:a,blah'); + assert.equal( + reporter.calls.flatMap((i) => i[0].messages), + ['info a', 'info a', 'info a', 'info a', 'info b'], + ); +}); - scopeA.info('info a'); - scopeB.info('info b'); +allows.run(); - enable('blah,scope:a'); +levels.forEach((level) => { + const l = suite(`level :: ${level}`); + l.before.each(before); - scopeA.info('info a'); - scopeB.info('info b'); - scopeB.info('info b'); - scopeA.info('info a'); + l('should log something', () => { + const reporter = spy(); + const scope = diary.diary(level, reporter); - enable('foo,bar:*,scope:,scope:*'); + scope[level]('something'); + scope[level]('something else'); + scope[level]('object else', { foo: 'bar' }); + scope[level]({ foo: 'bar' }); - scopeA.info('info a'); - scopeB.info('info b'); + assert.equal(reporter.callCount, 4); assert.equal( - reporter.calls.flatMap((i) => i[0].messages), - ['info a', 'info a', 'info a', 'info a', 'info b'], + reporter.calls.map((i) => i[0]), + [ + { + name: level, + level: level, + messages: ['something'], + }, + { + name: level, + level: level, + messages: ['something else'], + }, + { + name: level, + level: level, + messages: ['object else', { foo: 'bar' }], + }, + { + name: level, + level: level, + messages: [{ foo: 'bar' }], + }, + ], ); }); -}); -levels.forEach((level) => { - describe(`level :: ${level}`, (it) => { - it('should log something', () => { - const reporter = spy(); - const scope = diary.diary(level, reporter); - - scope[level]('something'); - scope[level]('something else'); - scope[level]('object else', { foo: 'bar' }); - scope[level]({ foo: 'bar' }); - - assert.equal(reporter.callCount, 4); - - assert.equal( - reporter.calls.map((i) => i[0]), - [ - { - name: level, - level: level, - messages: ['something'], - }, - { - name: level, - level: level, - messages: ['something else'], - }, - { - name: level, - level: level, - messages: ['object else', { foo: 'bar' }], - }, - { - name: level, - level: level, - messages: [{ foo: 'bar' }], - }, - ], - ); - }); - }); + l.run(); }); diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index c76f7c7..0000000 --- a/src/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { Diary, LogLevels, Reporter } from 'diary'; - -let allows: RegExp[] = []; - -const to_reg_exp = (x: string) => new RegExp(x.replace(/\*/g, '.*') + '$'); - -export const enable = (allows_query: string) => { - allows = allows_query.split(/[\s,]+/).map(to_reg_exp); -}; - -if (__TARGET__ === 'node') enable(process.env.DEBUG || 'a^'); - -// ~ Logger - -const logger = ( - name: string, - reporter: Reporter, - level: LogLevels, - ...messages: unknown[] -): void => { - for (let len = allows.length; len--;) - if (allows[len].test(name)) return reporter({ name, level, messages }); -}; - -// ~ Reporter - -const loglevel_strings: Record = /*#__PURE__*/ { - fatal: '✗ fatal', - error: '✗ error', - warn: '‼ warn ', - debug: '● debug', - info: 'ℹ info ', - log: '◆ log ', -} as const; - -export const default_reporter: Reporter = (event) => { - let label = ''; - const fn = console[event.level === 'fatal' ? 'error' : event.level]; - - if (__TARGET__ === 'node') label = `${loglevel_strings[event.level]} `; - if (event.name) label += `[${event.name}] `; - - if (__TARGET__ === 'node') { - let message: string; - const maybe_error = event.messages[0]; - - if (maybe_error instanceof Error && typeof maybe_error.stack !== 'undefined') { - const m = maybe_error.stack.split('\n'); - m.shift(); - message = `${maybe_error.message}\n${m.join('\n')}`; - } else { - message = _FORMAT(...event.messages); - } - - return void fn(label + message); - } - - if (typeof event.messages[0] === 'object') { - return void fn(label, ...event.messages); - } else { - const message = event.messages.shift(); - return void fn(label + message, ...event.messages); - } -}; - -// ~ Public api - -export const diary = (name: string, onEmit?: Reporter): Diary => { - onEmit = onEmit || default_reporter; - - return { - fatal: logger.bind(0, name, onEmit, 'fatal'), - error: logger.bind(0, name, onEmit, 'error'), - warn: logger.bind(0, name, onEmit, 'warn'), - debug: logger.bind(0, name, onEmit, 'debug'), - info: logger.bind(0, name, onEmit, 'info'), - log: logger.bind(0, name, onEmit, 'log'), - }; -}; - -const default_diary = diary(''); - -export const fatal = default_diary.fatal; -export const error = default_diary.error; -export const warn = default_diary.warn; -export const debug = default_diary.debug; -export const info = default_diary.info; -export const log = default_diary.log; diff --git a/src/index.types.ts b/src/index.types.ts deleted file mode 100644 index e332add..0000000 --- a/src/index.types.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - type Diary, - type Reporter, - type LogLevels, - type LogEvent, - diary, - enable, -} from 'diary'; - -declare function assert(thing: T): void; - -let scope = diary('name'); -enable('*'); - -assert(scope); -assert(enable); - -scope.info('string'); -scope.info(1); -scope.info([]); -scope.info({}); -scope.info('string', {}); - -scope.info(new Error()); -scope.fatal(new Error()); -scope.warn(new Error()); - -diary('name'); - -// @ts-expect-error -diary({}); - -const reporter: Reporter = (event) => { - assert(event); - - assert(event.name); - assert(event.messages); - assert(event.level); - - assert(event.blah); // allows other things -}; - -diary('name', reporter); diff --git a/src/json.d.ts b/src/json.d.ts deleted file mode 100644 index e3ec731..0000000 --- a/src/json.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { Reporter } from 'diary'; - -export const reporter: Reporter; \ No newline at end of file diff --git a/src/json.test.ts b/src/json.test.ts index 5ca5985..d71503d 100644 --- a/src/json.test.ts +++ b/src/json.test.ts @@ -1,47 +1,48 @@ +import {test, suite} from 'uvu'; import * as assert from 'uvu/assert'; -import * as diary from '.'; +import * as diary from './logger'; import * as json from './json'; -import { describe } from '../test/helpers'; import { restoreAll, spyOn } from 'nanospy'; -describe('api', (it) => { - it('should export', () => { - assert.type(json.reporter, 'function'); - }); +test('api', () => { + assert.type(json.reporter, 'function'); }); -describe('output', (it) => { - it.after.each(() => { - restoreAll(); - }); - - it('simple', () => { - const log_output = spyOn(console, 'log', () => {}); +const output = suite('output'); - const scope = diary.diary('json', json.reporter); - scope.info('foo %s', 'bar'); +output.before.each(() => { + diary.enable('*'); + restoreAll(); +}); - assert.equal(log_output.callCount, 1); - assert.equal( - log_output.calls[0][0], - '{"name":"json","level":"info","message":"foo bar"}', - ); - }); +output('simple', () => { + const log_output = spyOn(console, 'log', () => {}); - it('with rest', () => { - const log_output = spyOn(console, 'log', () => {}); + const scope = diary.diary('json', json.reporter); + scope.info('foo %s', 'bar'); - const scope = diary.diary('json', (event) => { - event.context = { sequence: 0 }; - json.reporter(event); - }); + assert.equal(log_output.callCount, 1); + assert.equal( + log_output.calls[0][0], + '{"name":"json","level":"info","message":"foo bar"}', + ); +}); - scope.info('foo %s', 'bar'); +output('with rest', () => { + const log_output = spyOn(console, 'log', () => {}); - assert.equal(log_output.callCount, 1); - assert.equal( - log_output.calls[0][0], - '{"name":"json","level":"info","message":"foo bar","context":{"sequence":0}}', - ); + const scope = diary.diary('json', (event) => { + event.context = { sequence: 0 }; + json.reporter(event); }); + + scope.info('foo %s', 'bar'); + + assert.equal(log_output.callCount, 1); + assert.equal( + log_output.calls[0][0], + '{"name":"json","level":"info","message":"foo bar","context":{"sequence":0}}', + ); }); + +output.run(); diff --git a/src/json.ts b/src/json.ts index 0524af5..f45c248 100644 --- a/src/json.ts +++ b/src/json.ts @@ -1,5 +1,5 @@ -import type { Reporter } from 'diary'; -import { sprintf } from 'diary/utils'; +import type { Reporter } from './logger'; +import { sprintf } from './utils'; export const reporter: Reporter = ({ name, level, messages, ...rest }) => { if (typeof messages[0] === 'object') { diff --git a/src/levels.ts b/src/levels.ts new file mode 100644 index 0000000..07fa6e3 --- /dev/null +++ b/src/levels.ts @@ -0,0 +1,6 @@ +export const fatal = '✗ fatal' as const; +export const error = '✗ error' as const; +export const warn = '‼ warn ' as const; +export const debug = '● debug' as const; +export const info = 'ℹ info ' as const; +export const log = '◆ log ' as const; diff --git a/src/index.d.ts b/src/logger.ts similarity index 62% rename from src/index.d.ts rename to src/logger.ts index 226c5f4..27a2fcc 100644 --- a/src/index.d.ts +++ b/src/logger.ts @@ -9,8 +9,6 @@ interface LogFn { export type LogLevels = 'fatal' | 'error' | 'warn' | 'debug' | 'info' | 'log'; -export type Diary = Record - export interface LogEvent { name: string; level: LogLevels; @@ -20,23 +18,9 @@ export interface LogEvent { [other: string]: any; } -/** - * Creates a new diary logging instance. - * - * @example - * ```ts - * import { diary } from 'diary'; - * - * const log = diary('my-fancy-app'); - * - * log.info('app has started'); - * ``` - * - * @param name A name to give this diary instance this can be unique to your application, or not. - * When logged, it'll exist after the level string, eg: `ℹ info [my-fancy-app] app has started` - * @param onEmit The reporter that handles the output of the log messages - */ -export const diary: (name: string, onEmit?: Reporter) => Diary; +let allows: RegExp[] = []; + +const to_reg_exp = (x: string) => new RegExp(x.replace(/\*/g, '.*') + '$'); /** * Configure what logs to emit. Follows the colon delimited scheme. @@ -59,13 +43,45 @@ export const diary: (name: string, onEmit?: Reporter) => Diary; * scopeB.log('foo bar'); // => 'foo bar' * ``` */ -export const enable: (allows_query: string) => void; +export const enable = (allows_query: string) => { + allows = allows_query.split(/[\s,]+/).map(to_reg_exp); +}; -export const default_reporter: Reporter; +const logger = ( + name: string, + reporter: Reporter, + level: LogLevels, + ...messages: unknown[] +): void => { + for (let len = allows.length; len--;) + if (allows[len].test(name)) return reporter({ name, level, messages }); +}; -export const fatal: LogFn; -export const error: LogFn; -export const warn: LogFn; -export const debug: LogFn; -export const info: LogFn; -export const log: LogFn; +export type Diary = Record; + +/** + * Creates a new diary logging instance. + * + * @example + * ```ts + * import { diary } from 'diary'; + * + * const log = diary('my-fancy-app'); + * + * log.info('app has started'); + * ``` + * + * @param name A name to give this diary instance this can be unique to your application, or not. + * When logged, it'll exist after the level string, eg: `ℹ info [my-fancy-app] app has started` + * @param onEmit The reporter that handles the output of the log messages + */ +export const diary = (name: string, onEmit?: Reporter): Diary => { + return { + fatal: logger.bind(0, name, onEmit, 'fatal'), + error: logger.bind(0, name, onEmit, 'error'), + warn: logger.bind(0, name, onEmit, 'warn'), + debug: logger.bind(0, name, onEmit, 'debug'), + info: logger.bind(0, name, onEmit, 'info'), + log: logger.bind(0, name, onEmit, 'log'), + }; +}; \ No newline at end of file diff --git a/src/node.ts b/src/node.ts new file mode 100644 index 0000000..0c79ada --- /dev/null +++ b/src/node.ts @@ -0,0 +1,38 @@ +/// + +import { format } from 'node:util' + +import { enable, diary as _diary, type LogEvent, type Diary, Reporter } from './logger'; +import * as LEVELS from './levels'; + +enable(process.env.DEBUG || 'a^'); + +function reporter(event: LogEvent) { + let label = `${LEVELS[event.level]} `; + const fn = console[event.level === 'fatal' ? 'error' : event.level]; + + if (event.name) label += `[${event.name}] `; + + let message: string; + const maybe_error = event.messages[0]; + + if ( + maybe_error instanceof Error && + typeof maybe_error.stack !== 'undefined' + ) { + const m = maybe_error.stack.split('\n'); + m.shift(); + message = `${maybe_error.message}\n${m.join('\n')}`; + } else { + message = format(...event.messages); + } + + return void fn(label + message); +} + +export const diary = (name: string, onEmit: Reporter = reporter): Diary => _diary(name, onEmit); + +const { fatal, error, warn, debug, info, log } = diary('', reporter); +export { fatal, error, warn, debug, info, log }; +export type { Diary, LogEvent, LogLevels, Reporter } from './logger'; +export { enable } from './logger'; diff --git a/src/utils.d.ts b/src/utils.d.ts deleted file mode 100644 index 7a76d49..0000000 --- a/src/utils.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { LogLevels } from 'diary'; - -export const sprintf = (message: string, ...extra: unknown[]) => string; - -/** - * Returns if a log level is than its comparitor. - * - * @example - * - * ```js - * compare("error", "fatal") === -1; - * // Thus error is "less-than" fatal. - * ``` - * - * @param input the level youre trying to test - * @param target the level youre wanting to compare too - */ -export const compare = (input: LogLevels, target: LogLevels) => boolean; diff --git a/src/utils.test.ts b/src/utils.test.ts index d65fe88..a99e6c9 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -1,74 +1,80 @@ +import { suite } from 'uvu'; import * as assert from 'uvu/assert'; -import { compare, sprintf } from './utils'; -import { describe } from '../test/helpers'; +import * as lib from './utils'; -describe('sprintf', (it) => { - it('should format something basic', () => { - assert.equal(sprintf('hello %s', 'world'), 'hello world'); - }); +const sprintf = suite('sprintf'); - it('should support strings', () => { - assert.equal(sprintf('foo %s', { bar: 'baz' }), 'foo [object Object]'); - assert.equal(sprintf('foo %s', ['bar']), 'foo bar'); - assert.equal(sprintf('foo %s', ['bar', 'baz']), 'foo bar,baz'); - }); +sprintf('should format something basic', () => { + assert.equal(lib.sprintf('hello %s', 'world'), 'hello world'); +}); + +sprintf('should support strings', () => { + assert.equal(lib.sprintf('foo %s', { bar: 'baz' }), 'foo [object Object]'); + assert.equal(lib.sprintf('foo %s', ['bar']), 'foo bar'); + assert.equal(lib.sprintf('foo %s', ['bar', 'baz']), 'foo bar,baz'); +}); - it('should support object notation', () => { - assert.equal(sprintf('foo %o', { bar: 'baz' }), 'foo {"bar":"baz"}'); - assert.equal(sprintf('foo %O', { bar: 'baz' }), 'foo {"bar":"baz"}'); - assert.equal(sprintf('foo %o', 'bar'), 'foo bar'); - assert.equal(sprintf('foo %o', ['bar', 'baz']), 'foo ["bar","baz"]'); - }); +sprintf('should support object notation', () => { + assert.equal(lib.sprintf('foo %o', { bar: 'baz' }), 'foo {"bar":"baz"}'); + assert.equal(lib.sprintf('foo %O', { bar: 'baz' }), 'foo {"bar":"baz"}'); + assert.equal(lib.sprintf('foo %o', 'bar'), 'foo bar'); + assert.equal(lib.sprintf('foo %o', ['bar', 'baz']), 'foo ["bar","baz"]'); +}); - it('should support integers', () => { - assert.equal(sprintf('foo %i', 1), 'foo 1'); - assert.equal(sprintf('foo %i', 1.25), 'foo 1'); - assert.equal(sprintf('foo %d', 1.25), 'foo 1'); - }); +sprintf('should support integers', () => { + assert.equal(lib.sprintf('foo %i', 1), 'foo 1'); + assert.equal(lib.sprintf('foo %i', 1.25), 'foo 1'); + assert.equal(lib.sprintf('foo %d', 1.25), 'foo 1'); +}); - it('should support floats', () => { - assert.equal(sprintf('foo %f', 1), 'foo 1'); - assert.equal(sprintf('foo %f', 1.25), 'foo 1.25'); - assert.equal(sprintf('foo %f', 1.25), 'foo 1.25'); - }); +sprintf('should support floats', () => { + assert.equal(lib.sprintf('foo %f', 1), 'foo 1'); + assert.equal(lib.sprintf('foo %f', 1.25), 'foo 1.25'); + assert.equal(lib.sprintf('foo %f', 1.25), 'foo 1.25'); +}); - it('should work when under supplied', () => { - assert.equal(sprintf('foo %s %s', 'bar'), 'foo bar undefined'); - assert.equal( - sprintf('foo %s with %o', 'bar', { bar: 'baz' }), - 'foo bar with {"bar":"baz"}', - ); - // assert.equal(sprintf('foo %s with %o', 'bar', {"bar":"baz"}, 'test'), 'foo bar with {"bar":"baz"} test'); - assert.equal(sprintf('foo %o %s', { bar: 'baz' }), 'foo {"bar":"baz"} undefined'); - }); +sprintf('should work when under supplied', () => { + assert.equal(lib.sprintf('foo %s %s', 'bar'), 'foo bar undefined'); + assert.equal( + lib.sprintf('foo %s with %o', 'bar', { bar: 'baz' }), + 'foo bar with {"bar":"baz"}', + ); + // assert.equal(lib.sprintf('foo %s with %o', 'bar', {"bar":"baz"}, 'test'), 'foo bar with {"bar":"baz"} test'); + assert.equal( + lib.sprintf('foo %o %s', { bar: 'baz' }), + 'foo {"bar":"baz"} undefined', + ); +}); - it('should work, when over supplied', () => { - assert.equal(sprintf('foo %s', 'bar', 'baz'), 'foo bar'); - }); +sprintf('should work, when over supplied', () => { + assert.equal(lib.sprintf('foo %s', 'bar', 'baz'), 'foo bar'); }); -describe('compare', (it) => { - it('should compare when equal', () => { - assert.equal(compare('log', 'log'), 0); - assert.equal(compare('error', 'error'), 0); - }); +const compare = suite('compare'); + +compare('should compare when equal', () => { + assert.equal(lib.compare('log', 'log'), 0); + assert.equal(lib.compare('error', 'error'), 0); +}); - it('should compare when less', () => { - assert.equal(compare('error', 'fatal'), -1); - assert.equal(compare('warn', 'error'), -1); - }); +compare('should compare when less', () => { + assert.equal(lib.compare('error', 'fatal'), -1); + assert.equal(lib.compare('warn', 'error'), -1); +}); - it('should compare when more', () => { - assert.equal(compare('fatal', 'error'), 1); - assert.equal(compare('info', 'log'), 1); - }); +compare('should compare when more', () => { + assert.equal(lib.compare('fatal', 'error'), 1); + assert.equal(lib.compare('info', 'log'), 1); +}); - it('show be zero when level is _real_', () => { - // @ts-ignore - assert.equal(compare('what the', 'log'), 0); - // @ts-ignore - assert.equal(compare('what the', 'heck'), 0); - // @ts-ignore - assert.equal(compare('log', 'heck'), 0); - }); +compare('show be zero when level is _real_', () => { + // @ts-ignore + assert.equal(lib.compare('what the', 'log'), 0); + // @ts-ignore + assert.equal(lib.compare('what the', 'heck'), 0); + // @ts-ignore + assert.equal(lib.compare('log', 'heck'), 0); }); + +sprintf.run(); +compare.run(); diff --git a/src/utils.ts b/src/utils.ts index c9bc9b1..92bbd22 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import type { LogLevels } from 'diary'; +import type { LogLevels } from './logger'; export const sprintf = (message: string, ...extra: unknown[]) => message.replace(/(\s+)(%[Oodifs](?=[^a-z0-9A-Z]|$))/g, (_, ws, pattern) => { @@ -12,6 +12,19 @@ export const sprintf = (message: string, ...extra: unknown[]) => const LEVELS: Record = { fatal: 60, error: 50, warn: 40, info: 30, debug: 20, log: 10 } as const; +/** + * Returns if a log level is than its comparitor. + * + * @example + * + * ```js + * compare("error", "fatal") === -1; + * // Thus error is "less-than" fatal. + * ``` + * + * @param input the level youre trying to test + * @param target the level youre wanting to compare too + */ export const compare = (log_level: LogLevels, input: LogLevels) => { if (!(input in LEVELS) || !(log_level in LEVELS)) return 0; diff --git a/test/helpers/index.ts b/test/helpers/index.ts deleted file mode 100644 index 912d751..0000000 --- a/test/helpers/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { suite } from 'uvu'; -import type { Test } from 'uvu'; -import { enable } from '../../src/index'; - -export const describe = (name: string, it: (t: Test) => void) => { - const s = suite(name); - s.before.each(() => { - enable('*'); - }); - it(s); - s.run(); -}; diff --git a/test/helpers/setup.js b/test/helpers/setup.js deleted file mode 100644 index 262320c..0000000 --- a/test/helpers/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -// @ts-nocheck - -globalThis.__TARGET__ = 'node'; -globalThis._FORMAT = require('util').format;