diff --git a/demo/logger/index.ts b/demo/logger/index.ts index daf260362..62ea538d0 100644 --- a/demo/logger/index.ts +++ b/demo/logger/index.ts @@ -1,7 +1,32 @@ import {createLogger} from '@vatr/logger'; -const log = createLogger('loggerScope', 'info'); -const error = createLogger('loggerScope', 'error', true); +const logger = createLogger('logger/demo', 'green'); -log('Hello ;)'); -error('Err: Hello ;) - Forced to log'); +console.debug('--- logger.logProperty ---'); +logger.logProperty('name', 'ali'); +logger.logProperty('options', {a: 1, b: 2}); + +console.debug('--- logger.logMethod ---'); +logger.logMethod('myMethod'); + +console.debug('--- logger.logMethodArgs ---'); +logger.logMethodArgs('myMethod', {a: 1, b: 2}); + +console.debug('--- logger.logMethodFull ---'); +logger.logMethodFull('add', {a: 1, b: 2}, 3); + +console.debug('--- logger.incident ---'); +logger.incident('myMethod', 'abort_signal', 'Aborted signal received', {url: '/test.json'}); + +console.debug('--- logger.accident ---'); +logger.accident('myMethod', 'file_not_found', 'Url requested return 404 not found', {url: '/test.json'}); + +console.debug('--- logger.logOther ---'); +logger.logOther('foo:', 'bar', {a: 1}); + +console.debug('--- logger.error ---'); +try { + throw new Error('my_error_message'); +} catch (err) { + logger.error('myMethod', 'error_code', (err as Error).stack || err, {a: 1, b: 2}); +} diff --git a/package.json b/package.json index e34111686..7af313f59 100644 --- a/package.json +++ b/package.json @@ -31,15 +31,15 @@ "publish": "lerna publish from-package" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.12.1", - "@typescript-eslint/parser": "^5.12.1", + "@typescript-eslint/eslint-plugin": "^5.14.0", + "@typescript-eslint/parser": "^5.14.0", "@web/dev-server": "^0.1.30", - "eslint": "^8.9.0", + "eslint": "^8.10.0", "eslint-config-google": "^0.14.0", "eslint-plugin-wc": "^1.3.2", "lerna": "^4.0.0", "npm-run-all": "^4.1.5", "ts-lit-plugin": "^1.2.1", - "typescript": "^4.5.5" + "typescript": "^4.6.2" } } diff --git a/package/fetch/src/fetch.ts b/package/fetch/src/fetch.ts index ba87673eb..30d58d470 100644 --- a/package/fetch/src/fetch.ts +++ b/package/fetch/src/fetch.ts @@ -1,7 +1,6 @@ import {createLogger, vatrRegisteredList} from '@vatr/logger'; -const log = createLogger('vatr/fetch'); -// const error = createLogger('vatr/fetch', 'error', true); +const logger = createLogger('vatr/fetch'); vatrRegisteredList.push({ name: '@vatr/fetch', @@ -34,9 +33,10 @@ export interface FetchOptions extends RequestInit * @example const response = await fetch(url, {jsonResponse: false}); */ export function fetch(url: string, options?: FetchOptions): Promise { - log('fetch', url, options); + logger.logMethodArgs('fetch', {url, options}); if (!navigator.onLine) { + logger.accident('fetch', 'abort_signal', 'abort signal received', {url}); throw new Error('fetch_offline'); } @@ -60,8 +60,10 @@ export function fetch(url: string, options?: FetchOptions): Promise { if (options.bodyObject != null) { options.body = JSON.stringify(options.bodyObject); - options.headers ??= {}; - options.headers['Content-Type'] = 'application/json'; + options.headers = { + ...options.headers, + 'Content-Type': 'application/json', + }; } // @TODO: AbortController polyfill @@ -74,11 +76,11 @@ export function fetch(url: string, options?: FetchOptions): Promise { }); } abortController.signal.addEventListener('abort', () => { - log('fetch: aborted %s', abortController.signal.reason); + logger.incident('fetch', 'abort_signal', 'abort signal received', {url, reason: abortController.signal.reason}); }); options.signal = abortController.signal; - const timeoutId = setTimeout(() => abortController.abort(), options.timeout); + const timeoutId = setTimeout(() => abortController.abort('fetch_timeout'), options.timeout); // @TODO: browser fetch polyfill const response = window.fetch(url, options); @@ -96,6 +98,7 @@ export function getData( queryParameters?: Record, options?: FetchOptions, ): Promise { + logger.logMethodArgs('getData', {url, queryParameters, options}); return fetch(url, { queryParameters, ...options, @@ -112,6 +115,7 @@ export async function getJson, options?: FetchOptions, ): Promise { + logger.logMethodArgs('getJson', {url, queryParameters, options}); const response = await getData(url, queryParameters, options); if (!response.ok) { @@ -131,6 +135,7 @@ export function postData( body: Record, options?: FetchOptions, ): Promise { + logger.logMethodArgs('postData', {url, body, options}); return fetch(url, { method: 'POST', bodyObject: body, diff --git a/package/i18n/src/core.ts b/package/i18n/src/core.ts index 74b541801..f65625e7b 100644 --- a/package/i18n/src/core.ts +++ b/package/i18n/src/core.ts @@ -3,8 +3,7 @@ import {addSignalListener, requestSignal, setSignalProvider, waitForSignal} from import {getJson} from '@vatr/fetch'; import type {I18nOptions, L10Resource} from './type'; -export const log = createLogger('vatr/i18n'); -export const error = createLogger('vatr/i18n', 'error', true); +export const logger = createLogger('vatr/i18n'); vatrRegisteredList.push({ name: '@vatr/i18n', @@ -21,16 +20,19 @@ const loadingStr = '…'; let l10nResource: L10Resource; addSignalListener('l10n-resource-change', (resource) => { + logger.logMethodArgs('l10nResourceChanged', {resource}); l10nResource = resource; }); addSignalListener('local-change', (local) => { + logger.logMethodArgs('localChanged', {local}); if (configuration.autoFetchResources) requestSignal('l10n-resource-change', local); document.documentElement.setAttribute('lang', local.code); document.documentElement.setAttribute('dir', local.direction); }); setSignalProvider('l10n-resource-change', async (local): Promise => { + logger.logMethodArgs('l10nResourceProvider', {local}); const current = await waitForSignal('local-change', true); if (current.code !== local.code) { return await getJson(`${configuration.resourcePath}/${local.code}.json`); @@ -43,10 +45,12 @@ setSignalProvider('l10n-resource-change', async (local): Promise): void { + logger.logMethodArgs('initialI18n', {options}); for (const key in options) { if (Object.prototype.hasOwnProperty.call(options, key)) { - configuration[key] = options[key]; + // WTF, mastmalize type. + (configuration[key as keyof I18nOptions] as unknown) = options[key as keyof I18nOptions] as unknown; } } @@ -29,7 +30,7 @@ export function initialI18n(options?: I18nOptions): void { * return null if the key is null or undefined (for optional input). * * @example - * localize('Hello_World'); // Hello world! + * localize('hello_world'); // Hello world! */ export function localize(key?: null): null; /** @@ -42,7 +43,7 @@ export function localize(key?: null): null; * return null if the key is null or undefined (for optional input). * * @example - * localize('Hello_World'); // Hello world! + * localize('hello_world'); // Hello world! */ export function localize(key: string): string; /** @@ -55,13 +56,11 @@ export function localize(key: string): string; * return null if the key is null or undefined (for optional input). * * @example - * localize('Hello_World'); // Hello world! + * localize('hello_world'); // Hello world! */ export function localize(key?: string | null): string | null; export function localize(key?: string | null): string | null { if (key == null) return null; - key = key.trim(); - if (key === '') return ''; return _localize(key); } diff --git a/package/logger/README.md b/package/logger/README.md index 42aed9342..aa5c654db 100644 --- a/package/logger/README.md +++ b/package/logger/README.md @@ -4,9 +4,39 @@ Fancy colorful console debugger with custom scope written in tiny TypeScript, ES ## Example usage -```js +```ts import { createLogger } from 'https://esm.run/@vatr/logger'; -const log = createLogger('my-scope', 'debug', true); -log('foo'); +const logger = createLogger('demo'); + +function sayHello (name: string) { + logger.logMethodArgs('sayHello', {name}); +} ``` + +### Debug Mode + +Many of the methods in the logger are no-ops when the debug mode is off. +Please remember to **reload** the window after changing the debug mode. + +- Debugging all scopes + + ```ts + window.localStorage?.setItem('VATR_LOG', '*'); + ``` + +- Debugging specific scope + + ```ts + window.localStorage?.setItem('VATR_LOG', 'scope_name'); + ``` + +- Debugging some scopes with pattern + + ```ts + window.localStorage?.setItem('VATR_LOG', '*vatr*'); + ``` + +### API + +@TODO: update me from [type.ts](./src/type.ts) diff --git a/package/logger/src/logger.ts b/package/logger/src/logger.ts index 15a966509..49f2c3bc6 100644 --- a/package/logger/src/logger.ts +++ b/package/logger/src/logger.ts @@ -1,7 +1,20 @@ -export * from './meta'; -export type LoggerFunction = (message: string, ...restParam: Array) => void; -export type LogLevels = 'debug' | 'error' | 'info' | 'log' | 'trace' | 'warn'; +import type {Logger} from './type'; +/** + * Define `window.Vatr.registeredList` + */ +export const vatrRegisteredList = window.Vatr?.registeredList || []; +window.Vatr ??= {}; +window.Vatr.registeredList = vatrRegisteredList; + +vatrRegisteredList.push({ + name: '@vatr/logger', + version: '{{VATR_VERSION}}', // TODO: replace with real version at release time. +}); + +/** + * Color list storage for logger. + */ let colorIndex = 0; const colorList = [ '#f05561', @@ -31,48 +44,131 @@ const getNextColor = (): string => { }; const debugString = window.localStorage?.getItem('VATR_LOG')?.trim(); +const getDebugState = (scope: string, force: boolean ): boolean => { + if ( + debugString == null || + debugString == '' + ) { + return false; + } + + if ( + force || + debugString === scope || + ( + debugString.indexOf('*') === 0 && // starts with `*` for example: `*vatr*` + scope.indexOf(debugString.replaceAll('*', '')) !== -1 + ) || + ( + debugString.indexOf('*') === debugString.length - 1 && // ends with `*` for example: `vatr/*` + scope.indexOf(debugString.replaceAll('*', '')) === 0 + ) + ) { + return true; + } + + // else + return false; +}; + +export const style = { + scope: 'color: {{color}};', + reset: 'color: inherit;', +}; /** * Create a logger function for fancy console debug with custom scope. * - * @property {boolean} force - if set to true logger will work even if its not in debug mode. * @example - * const log = createLogger('my scope', 'log', true); - * log('my log message :)'); + * const logger = createLogger('demo'); + * function sayHello (name: string) { + * logger.logMethodArgs('sayHello', {name}); + * } */ -export function createLogger( +export const createLogger = ( scope: string, - level: LogLevels = 'debug', - force?: boolean, -): LoggerFunction { - const color = getNextColor(); - let debug = force === true; - - if (debugString != null && !debug) { - if (debugString === scope) { - debug = true; - } else if ( - debugString.indexOf('*') === 0 && - scope.indexOf(debugString.replaceAll('*', '')) !== -1 - ) { - debug = true; - } else if ( - debugString.indexOf('*') === debugString.length - 1 && - scope.indexOf(debugString.replaceAll('*', '')) === 0 - ) { - debug = true; - } + color: string = getNextColor(), + force = false, +): Logger => { + scope = scope.trim(); + + const debug = getDebugState(scope, force); + + const first = scope.charAt(0); + if (first !== '[' && first !== '{' && first !== '(' && first !== '<') { + scope = '[' + scope + ']'; } - return (message: string, ...restParam: Array): void => { - if (!debug) return; - // first args must be separated as keyPattern for fix issue of `this._log('a=%s', a)` - console[level]( - `%c%s%c ${message}`, - `color: ${color}; font-size: 1.2em;`, + // eslint-disable-next-line @typescript-eslint/no-empty-function + const empty = (): void => {}; + + // else if debug is true for this scope + return { + color, + scope, + + logProperty: debug ? console.debug.bind( + console, + '%c%s%c.%s = %o;', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ) : empty, + + logMethod: debug ? console.debug.bind( + console, + '%c%s%c.%s();', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ) : empty, + + logMethodArgs: debug ? console.debug.bind( + console, + '%c%s%c.%s(%o);', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ) : empty, + + logMethodFull: debug ? console.debug.bind( + console, + '%c%s%c.%s(%o); // %o', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ) : empty, + + + incident: debug ? console.trace.bind( + console, + '%c%s%c.%s() => Incident: "%s" (%s)!', + style.scope.replace('{{color}}', color), scope, - 'color: inherit;font-size: 1em', - ...restParam, - ); + style.reset, + ) : empty, + + accident: console.warn.bind( + console, + '%c%s%c.%s => Accident: "%s" (%s)!', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ), + + error: console.error.bind( + console, + '%c%s%c.%s "%s" =>', + style.scope.replace('{{color}}', color), + scope, + style.reset, + ), + + logOther: debug ? console.debug.bind( + console, + '%c%s', + style.scope.replace('{{color}}', color), + scope, + ) : empty, }; -} +}; diff --git a/package/logger/src/meta.ts b/package/logger/src/meta.ts deleted file mode 100644 index 8d7312185..000000000 --- a/package/logger/src/meta.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare global { - interface Window { - Vatr?: { - registeredList?: Array<{ - name: string, - version: string, - }>; - } - } -} - -export const vatrRegisteredList = window.Vatr?.registeredList || []; -window.Vatr ??= {}; -window.Vatr.registeredList = vatrRegisteredList; - -vatrRegisteredList.push({ - name: '@vatr/logger', - version: '{{VATR_VERSION}}', // TODO: replace with real version at release time. -}); diff --git a/package/logger/src/type.ts b/package/logger/src/type.ts new file mode 100644 index 000000000..3aeff880e --- /dev/null +++ b/package/logger/src/type.ts @@ -0,0 +1,126 @@ +declare global { + interface Window { + Vatr?: { + registeredList?: Array<{ + name: string, + version: string, + }>; + } + } + + /** + * @TODO: Make an issue to TS, WTF is this way! any better solution for more args in bind?! + */ + interface CallableFunction { + bind + (this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, arg4: A4, ...args: A) + => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, arg4: A4): (...args: A) => R; + } +} + +export interface Logger { + readonly color: string; + + readonly scope: string; + + /** + * `console.debug` property change. + * + * Example: + * + * ```ts + * logger.logProperty('name', 'ali'); + * ``` + */ + logProperty(property: string, value: unknown): void; + + /** + * `console.debug` function or method calls. + * + * Example: + * + * ```ts + * function myMethod () { + * logger.logMethod('myMethod'); + * } + * ``` + */ + logMethod(method: string): void; + + /** + * `console.debug` function or method calls with arguments. + * + * Example: + * + * ```ts + * function myMethod (a: number, b: number) { + * logger.logMethodArgs('myMethod', {a, b}); + * } + * ``` + */ + logMethodArgs(method: string, args: Record | string | number | boolean): void; + + /** + * `console.debug` function or method calls with arguments. + * + * Example: + * + * ```ts + * function add (a: number, b: number): number { + * const result = a + b; + * logger.logMethodFull('add', {a, b}, result); + * return result; + * } + * ``` + */ + logMethodFull(method: string, args: Record | string | number | boolean, result: unknown): void; + + /** + * `console.trace` an event or expected accident. (not warn or error) + * + * Example: + * + * ```ts + * logger.incident('fetch', 'abort_signal', 'aborted signal received', {url: '/test.json'}); + * ``` + */ + incident(method: string, code: string, desc: string, ...args: unknown[]): void; + + /** + * `console.warn` an unexpected accident or error that you handled. + * + * Example: + * + * ```ts + * logger.accident('fetch', 'file_not_found', 'url requested return 404 not found', {url: '/test.json'}); + * ``` + */ + accident(method: string, code: string, desc: string, ...args: unknown[]): void; + + /** + * `console.error` an unexpected error. + * + * Example: + * + * ```ts + * try { + * ... + * } + * catch (err) { + * logger.error('myMethod', 'error_code', (err as Error).stack || err, {a: 1, b: 2}); + * } + * ``` + */ + error(method: string, code: string, errorStack: string | unknown, ...args: unknown[]): void; + + /** + * Simple `console.debug` with styled scope. + * + * Example: + * + * ```ts + * logger.logOther('foo:', 'bar', {a: 1}); + * ``` + */ + logOther(...args: unknown[]): void; +} diff --git a/package/router/src/core.ts b/package/router/src/core.ts index 81a8513a6..6a1a7a2da 100644 --- a/package/router/src/core.ts +++ b/package/router/src/core.ts @@ -1,8 +1,7 @@ import {createLogger, vatrRegisteredList} from '@vatr/logger'; -import type {RequestRouteParam, Route} from './type'; +import type {ParamList, RequestRouteParam, Route} from './type'; -export const log = createLogger('vatr/router'); -// export const error = createLogger('vatr/router', 'error', true); +export const logger = createLogger('vatr/router'); vatrRegisteredList.push({ name: '@vatr/router', @@ -13,7 +12,8 @@ vatrRegisteredList.push({ * Handle requests of 'router-change' signal. */ export function routeSignalProvider(requestParam: RequestRouteParam): Route { - log('routeSignalProvider: %o', requestParam); + logger.logMethodArgs('routeSignalProvider', {requestParam}); + updateBrowserHistory(requestParam); return makeRouteObject(requestParam); } @@ -22,7 +22,8 @@ export function routeSignalProvider(requestParam: RequestRouteParam): Route { * Update browser history state (history.pushState or history.replaceState). */ export function updateBrowserHistory(options: RequestRouteParam): void { - log('_updateBrowserHistory(%o)', options); + logger.logMethodArgs('updateBrowserHistory', {options}); + if (options.pushState === false) return; // default is true then undefined means true. options.search ??= ''; @@ -44,7 +45,8 @@ export function updateBrowserHistory(options: RequestRouteParam): void { * Make Route from RequestRouteParam. */ export function makeRouteObject(requestParam: RequestRouteParam): Route { - log('makeRouteObject: %o', requestParam); + logger.logMethodArgs('makeRouteObject', {requestParam}); + requestParam.search ??= ''; requestParam.hash ??= ''; @@ -62,6 +64,8 @@ export function makeRouteObject(requestParam: RequestRouteParam): Route { }; } +// --- Utils --- + /** * decodeURIComponent without throwing error. */ @@ -77,7 +81,7 @@ export function _decodeURIComponent(val: string): string { * Make query string from {key:val} object */ export function joinParameterList( - parameterList: Record | null | undefined, + parameterList: ParamList | null | undefined, ): string { if (parameterList == null) return ''; const list: Array = []; @@ -94,15 +98,15 @@ export function joinParameterList( */ export function splitParameterString( parameterString: string | null | undefined, -): Record { - const parameterList = {}; +): ParamList { + const parameterList: ParamList = {}; if (!parameterString) return parameterList; parameterString .split('&') .forEach((parameter) => { const parameterArray = parameter.split('='); - parameterList[parameterArray[0]] = parameterArray[1] != null ? parseValue(parameterArray[1]) : null; + parameterList[parameterArray[0]] = parameterArray[1] != null ? parseValue(parameterArray[1]) : ''; }) ; diff --git a/package/router/src/router.ts b/package/router/src/router.ts index 48e459c47..e8df9a0e2 100644 --- a/package/router/src/router.ts +++ b/package/router/src/router.ts @@ -1,5 +1,5 @@ import {hasSignalDispatchedBefore, requestSignal, setSignalProvider} from '@vatr/signal'; -import {joinParameterList, log, routeSignalProvider} from './core'; +import {joinParameterList, logger, routeSignalProvider} from './core'; import {clickTrigger} from './trigger-click'; import {popstateTrigger} from './trigger-popstate'; import type {InitOptions, Route} from './type'; @@ -8,7 +8,8 @@ import type {InitOptions, Route} from './type'; * Initial and config the Router. */ export function initialRouter(options?: InitOptions): void { - log('initialRouter: %o', options); + logger.logMethodArgs('initialRouter', {options}); + clickTrigger.enable = options?.clickTrigger ?? true; popstateTrigger.enable = options?.popstateTrigger ?? true; @@ -27,6 +28,8 @@ export function initialRouter(options?: InitOptions): void { * @example */ export function makeUrl(route: Partial): string { + logger.logMethodArgs('makeUrl', {route}); + let href = ''; if (route.sectionList != null) { diff --git a/package/router/src/trigger-click.ts b/package/router/src/trigger-click.ts index 291a09982..7b1ea4c94 100644 --- a/package/router/src/trigger-click.ts +++ b/package/router/src/trigger-click.ts @@ -1,4 +1,5 @@ import {requestSignal} from '@vatr/signal'; +import {logger} from './core'; let _enabled = false; @@ -79,6 +80,8 @@ export const clickTrigger = { }, set enable(enable: boolean) { + logger.logProperty('clickTrigger.enable', enable); + if (enable && !_enabled) { window.document.addEventListener('click', clickTrigger._clickHandler); } @@ -87,6 +90,7 @@ export const clickTrigger = { } _enabled = enable; }, + get enable(): boolean { return _enabled; }, diff --git a/package/router/src/trigger-popstate.ts b/package/router/src/trigger-popstate.ts index f34bdfea8..076f132e9 100644 --- a/package/router/src/trigger-popstate.ts +++ b/package/router/src/trigger-popstate.ts @@ -1,4 +1,5 @@ import {requestSignal} from '@vatr/signal'; +import {logger} from './core'; let _enabled = false; @@ -19,6 +20,8 @@ export const popstateTrigger = { }, set enable(enable: boolean) { + logger.logProperty('popstateTrigger.enable', enable); + if (enable && !_enabled) { window.addEventListener('popstate', popstateTrigger._popstateHandler); } @@ -27,6 +30,7 @@ export const popstateTrigger = { } _enabled = enable; }, + get enable(): boolean { return _enabled; }, diff --git a/package/router/src/type.ts b/package/router/src/type.ts index 369aae767..b343cc34c 100644 --- a/package/router/src/type.ts +++ b/package/router/src/type.ts @@ -8,12 +8,14 @@ declare global { } } +export type ParamList = Record; + // @TODO: description export interface Route { // href: https://example.com/product/100/book?cart=1&color=white#description sectionList: Array; // [product, 100, book] - queryParamList: Record; // {cart: 1, color: 'white'} + queryParamList: ParamList; // {cart: 1, color: 'white'} hash: string; // '#header' } diff --git a/package/signal/src/core.ts b/package/signal/src/core.ts index e7680d682..1724aa16b 100644 --- a/package/signal/src/core.ts +++ b/package/signal/src/core.ts @@ -1,8 +1,7 @@ import {createLogger, vatrRegisteredList} from '@vatr/logger'; import type {SignalObject, SignalStack} from './type'; -export const log = createLogger('vatr/signal'); -export const error = createLogger('vatr/signal', 'error', true); +export const logger = createLogger('vatr/signal'); vatrRegisteredList.push({ name: '@vatr/signal', @@ -34,9 +33,9 @@ export function _getSignalObject( export function _callListeners( signal: SignalObject, ): void { - log('_callListeners(%s, %o)', signal.name, signal.value); + logger.logMethodArgs('_callListeners', {signalName: signal.name, signalValue: signal.value}); if (signal.value === undefined) { - error('_callListeners(%s): signal must have a value!', signal.name, signal.value); + logger.accident('_callListeners', 'no_signal_value', 'signal must have a value', {signalName: signal.name}); return; } for (const listener of signal.listenerList) { @@ -44,10 +43,12 @@ export function _callListeners( try { const ret = listener.callback(signal.value); if (ret instanceof Promise) { - ret.catch((err) => error('_callListeners(%s): listener.callback error! %o', signal.name, err)); + ret.catch((err) => + logger.error('_callListeners', 'call_listener_failed', (err as Error).stack || err, + {signalName: signal.name})); } } catch (err) { - error('_callListeners(%s): listener.callback error! %o', signal.name, err); + logger.error('_callListeners', 'call_listener_failed', (err as Error).stack || err, {signalName: signal.name}); } if (listener.once) _removeSignalListener(signal, listener.id); } diff --git a/package/signal/src/signal.ts b/package/signal/src/signal.ts index 0e7ca81c8..0d2561349 100644 --- a/package/signal/src/signal.ts +++ b/package/signal/src/signal.ts @@ -1,4 +1,5 @@ -import {log, +import { + logger, _getSignalObject, _callListeners, _removeSignalListener, @@ -24,7 +25,7 @@ export function addSignalListener( signalCallback: ListenerCallback, options?: ListenerOptions, ): symbol { - log('addSignalListener(%s, %o)', signalName, options); + logger.logMethodArgs('addSignalListener', {signalName, options}); const signal = _getSignalObject(signalName); const listener: ListenerObject = { @@ -39,17 +40,19 @@ export function addSignalListener( // Run callback for old dispatch signal if (signal.value !== undefined) { if (options?.receivePrevious === 'Immediate') { - log('addSignalListener(%s): run callback(immediately)', signalName); + logger.incident('addSignalListener', 'call_signal_callback', 'run callback with previous signal value!', + {signalName, mode: 'Immediate'}); try { signalCallback(signal.value); } catch (err) { - console.error('addSignalListener(%s): signalCallback error! %o', signalName, err); + logger.error('addSignalListener', 'call_signal_callback_failed', (err as Error).stack || err, {signalName}); } callbackCalled = true; } else if (options?.receivePrevious === true) { requestAnimationFrame(() => { if (signal.value !== undefined) { - log('addSignalListener(%s): run callback(delay)', signalName); + logger.incident('addSignalListener', 'call_signal_callback', 'run callback with previous signal value!', + {signalName, mode: 'Delay'}); signalCallback(signal.value); } }); @@ -80,7 +83,8 @@ export function removeSignalListener( signalName: SignalName, listenerId: symbol, ): void { - log('removeSignalListener(%s)', signalName); + logger.logMethodArgs('removeSignalListener', signalName); + const signal = _getSignalObject(signalName); _removeSignalListener(signal, listenerId); } @@ -96,7 +100,7 @@ export function dispatchSignal( value: VatrSignals[SignalName], options?: DispatchOptions, ): void { - log('dispatchSignal(%s, %o, %o)', signalName, value, options); + logger.logMethodArgs('dispatchSignal', {signalName, value, options}); const signal = _getSignalObject(signalName); // set value before check signal.debounced for act like throttle (call listeners with last dispatch value). @@ -130,7 +134,8 @@ export function requestSignal( signalName: SignalName, requestParam: VatrRequestSignals[SignalName], ): Promise { - log('requestSignal: %s', signalName); + logger.logMethodArgs('requestSignal', {signalName, requestParam}); + dispatchSignal( `request-${signalName}` as unknown as SignalName, requestParam as unknown as VatrSignals[SignalName], // mastmalize to avoid type error @@ -157,12 +162,13 @@ export function setSignalProvider( signalProvider: SignalProvider, options?: SignalProviderOptions, ): symbol { - log('setSignalProvider(%s)', signalName); + logger.logMethodArgs('setSignalProvider', {signalName, options}); + // @TODO: refactor with removeSignalProvider const signal = _getSignalObject(`request-${signalName}` as unknown as SignalName); if (signal.listenerList.length > 0) { - log('setSignalProvider(%s): WARNING! another provider defined and will removed!', - signalName, signal.listenerList.length); + logger.accident('setSignalProvider', 'signal_provider_already_set', 'another provider defined and will removed' + , {signalName}); signal.listenerList = []; } @@ -198,7 +204,7 @@ export async function waitForSignal( signalName: SignalName, receivePrevious?: boolean, ): Promise { - log('waitForSignal(%s)', signalName); + logger.logMethodArgs('waitForSignal', {signalName, receivePrevious}); return new Promise((resolve) => { addSignalListener(signalName, resolve, { @@ -217,7 +223,7 @@ export async function waitForSignal( */ export function hasSignalDispatchedBefore(signalName: SignalName): boolean { const dispatched = 'value' in _getSignalObject(signalName); - log('hasSignalDispatchedBefore(%s) => %s', signalName, dispatched); + logger.logMethodFull('hasSignalDispatchedBefore', signalName, dispatched); return dispatched; } @@ -231,7 +237,7 @@ export function hasSignalDispatchedBefore( * hasSignalDispatchedBefore('content-change'); // false */ export function expireSignal(signalName: SignalName): void { - log('expireSignal(%s)', signalName); + logger.logMethodArgs('expireSignal', signalName); delete _getSignalObject(signalName).value; } diff --git a/tsconfig.json b/tsconfig.json index 455cb4308..4edc5bafd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -72,6 +72,7 @@ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ + "useDefineForClassFields": false, /* Must be disabled for lit, https://lit.dev/docs/components/properties/#avoiding-issues-with-class-fields */ "plugins": [ { diff --git a/yarn.lock b/yarn.lock index 6c8b378c1..0ee6a3f01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,10 +30,10 @@ dependencies: regenerator-runtime "^0.13.4" -"@eslint/eslintrc@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.1.0.tgz#583d12dbec5d4f22f333f9669f7d0b7c7815b4d3" - integrity sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg== +"@eslint/eslintrc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" + integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1155,14 +1155,14 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" - integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== +"@typescript-eslint/eslint-plugin@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.14.0.tgz#5119b67152356231a0e24b998035288a9cd21335" + integrity sha512-ir0wYI4FfFUDfLcuwKzIH7sMVA+db7WYen47iRSaCGl+HMAZI9fpBwfDo45ZALD3A45ZGyHWDNLhbg8tZrMX4w== dependencies: - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/type-utils" "5.12.1" - "@typescript-eslint/utils" "5.12.1" + "@typescript-eslint/scope-manager" "5.14.0" + "@typescript-eslint/type-utils" "5.14.0" + "@typescript-eslint/utils" "5.14.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -1170,69 +1170,69 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" - integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== +"@typescript-eslint/parser@^5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.14.0.tgz#7c79f898aa3cff0ceee6f1d34eeed0f034fb9ef3" + integrity sha512-aHJN8/FuIy1Zvqk4U/gcO/fxeMKyoSv/rS46UXMXOJKVsLQ+iYPuXNbpbH7cBLcpSbmyyFbwrniLx5+kutu1pw== dependencies: - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/typescript-estree" "5.12.1" + "@typescript-eslint/scope-manager" "5.14.0" + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/typescript-estree" "5.14.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" - integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== +"@typescript-eslint/scope-manager@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.14.0.tgz#ea518962b42db8ed0a55152ea959c218cb53ca7b" + integrity sha512-LazdcMlGnv+xUc5R4qIlqH0OWARyl2kaP8pVCS39qSL3Pd1F7mI10DbdXeARcE62sVQE4fHNvEqMWsypWO+yEw== dependencies: - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/visitor-keys" "5.12.1" + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/visitor-keys" "5.14.0" -"@typescript-eslint/type-utils@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" - integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== +"@typescript-eslint/type-utils@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.14.0.tgz#711f08105860b12988454e91df433567205a8f0b" + integrity sha512-d4PTJxsqaUpv8iERTDSQBKUCV7Q5yyXjqXUl3XF7Sd9ogNLuKLkxz82qxokqQ4jXdTPZudWpmNtr/JjbbvUixw== dependencies: - "@typescript-eslint/utils" "5.12.1" + "@typescript-eslint/utils" "5.14.0" debug "^4.3.2" tsutils "^3.21.0" -"@typescript-eslint/types@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" - integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== +"@typescript-eslint/types@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.14.0.tgz#96317cf116cea4befabc0defef371a1013f8ab11" + integrity sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw== -"@typescript-eslint/typescript-estree@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" - integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== +"@typescript-eslint/typescript-estree@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.14.0.tgz#78b7f7385d5b6f2748aacea5c9b7f6ae62058314" + integrity sha512-QGnxvROrCVtLQ1724GLTHBTR0lZVu13izOp9njRvMkCBgWX26PKvmMP8k82nmXBRD3DQcFFq2oj3cKDwr0FaUA== dependencies: - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/visitor-keys" "5.12.1" + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/visitor-keys" "5.14.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" - integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== +"@typescript-eslint/utils@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.14.0.tgz#6c8bc4f384298cbbb32b3629ba7415f9f80dc8c4" + integrity sha512-EHwlII5mvUA0UsKYnVzySb/5EE/t03duUTweVy8Zqt3UQXBrpEVY144OTceFKaOe4xQXZJrkptCf7PjEBeGK4w== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.12.1" - "@typescript-eslint/types" "5.12.1" - "@typescript-eslint/typescript-estree" "5.12.1" + "@typescript-eslint/scope-manager" "5.14.0" + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/typescript-estree" "5.14.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.12.1": - version "5.12.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" - integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== +"@typescript-eslint/visitor-keys@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.14.0.tgz#1927005b3434ccd0d3ae1b2ecf60e65943c36986" + integrity sha512-yL0XxfzR94UEkjBqyymMLgCBdojzEuy/eim7N9/RIcTNxpJudAcqsU8eRyfzBbcEzGoPWfdM3AGak3cN08WOIw== dependencies: - "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/types" "5.14.0" eslint-visitor-keys "^3.0.0" "@web/config-loader@^0.1.3": @@ -2274,9 +2274,9 @@ deprecation@^2.0.0, deprecation@^2.3.1: integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== destroy@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.1.0.tgz#b77ae22e472d85437141319d32ae40b344dff38a" - integrity sha512-R5QZrOXxSs0JDUIU/VANvRJlQVMts9C0L76HToQdPdlftfZCE7W6dyH0G4GZ5UW9fRqUOhAoCE2aGekuu+3HjQ== + version "1.1.1" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.1.1.tgz#38a65ed2f2615ad12bf59c6b5e885512c0cf13dd" + integrity sha512-jxwFW+yrVOLdwqIWvowFOM8UPdhZnvOF6mhXQQLXMxBDLtv2JVJlVJPEwkDv9prqscEtGtmnxuuI6pQKStK1vA== detect-indent@^5.0.0: version "5.0.0" @@ -2496,12 +2496,12 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.9.0: - version "8.9.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.9.0.tgz#a2a8227a99599adc4342fd9b854cb8d8d6412fdb" - integrity sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q== +eslint@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" + integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== dependencies: - "@eslint/eslintrc" "^1.1.0" + "@eslint/eslintrc" "^1.2.0" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -3088,9 +3088,9 @@ has-flag@^4.0.0: integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-tostringtag@^1.0.0: version "1.0.0" @@ -5161,9 +5161,9 @@ read-package-json@^3.0.0: npm-normalize-package-bin "^1.0.0" read-package-json@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.1.tgz#153be72fce801578c1c86b8ef2b21188df1b9eea" - integrity sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw== + version "4.1.2" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.2.tgz#b444d047de7c75d4a160cb056d00c0693c1df703" + integrity sha512-Dqer4pqzamDE2O4M55xp1qZMuLPqi4ldk2ya648FOMHRjwMzFhuxVrG04wd0c38IsvkVdr3vgHI6z+QTPdAjrQ== dependencies: glob "^7.1.1" json-parse-even-better-errors "^2.3.0" @@ -5415,9 +5415,9 @@ rimraf@^3.0.2: glob "^7.1.3" rollup@^2.66.1: - version "2.68.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.68.0.tgz#6ccabfd649447f8f21d62bf41662e5caece3bd66" - integrity sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA== + version "2.70.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.0.tgz#17a92e5938e92a251b962352e904c9f558230ec7" + integrity sha512-iEzYw+syFxQ0X9RefVwhr8BA2TNJsTaX8L8dhyeyMECDbmiba+8UQzcu+xZdji0+JQ+s7kouQnw+9Oz5M19XKA== optionalDependencies: fsevents "~2.3.2" @@ -6148,10 +6148,10 @@ typescript@^3.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== -typescript@^4.5.5: - version "4.5.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" - integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== +typescript@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" + integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== typical@^4.0.0: version "4.0.0" @@ -6164,9 +6164,9 @@ typical@^5.2.0: integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== uglify-js@^3.1.4: - version "3.15.1" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.1.tgz#9403dc6fa5695a6172a91bc983ea39f0f7c9086d" - integrity sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ== + version "3.15.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" + integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== uid-number@0.0.6: version "0.0.6"