diff --git a/.codecov.yml b/.codecov.yml index 3b26ad1..e8e41a8 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,28 +1,69 @@ # codecov: # notify: # require_ci_to_pass: yes - coverage: status: project: - default: - target: 90% - color: + utilities: target: auto threshold: 7% base: auto if_ci_failed: success flags: - color + - config + - log + - watch + common: + target: 40% + threshold: 10% + if_ci_failed: error + flags: + - common precision: 2 round: down range: '70...100' - +# flag_management: +# # this section will govern all default rules of Flags +# default_rules: +# carryforward: true +# ignore: +# - "**/*_test.ts" +# - "**/*_test.tsx" +# paths: +# - "src/**" +# statuses: +# - name_prefix: default_project +# type: project +# target: auto +# threshold: 1% +# - name_prefix: default_patch +# type: patch +# target: percent +# threshold: 80% +ignore: + - "**/*_test.ts" + - "**/*_test.tsx" flags: color: paths: - - color/src/** - - '!color/src/**_test.ts' + - src/color/ + common: + paths: + - src/common/ + config: + paths: + - src/config/ + log: + paths: + - src/log/ + watch: + paths: + - src/watch/ + # test: + # paths: + # - test/ + parsers: gcov: branch_detection: diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 0000000..cb26741 --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,17 @@ +FROM alpine:3.13.2 AS organizer + +# Installation files +WORKDIR /out/usr/src/install +COPY src src +COPY test test +COPY mod.ts . +COPY import_map.json . +COPY trailmix.config.ts . +COPY trilom.config.ts . + +FROM hayd/alpine-deno:1.8.1 AS runner +COPY --from=organizer /out / + +# Install +WORKDIR /usr/src/install +ENV PATH "/root/.deno/bin:$PATH" diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 757a727..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - extends: ['alloy', 'alloy/react', 'alloy/typescript'], - env: { - node: true, - }, - globals: { - Deno: false, - }, - rules: { - '@typescript-eslint/consistent-type-imports': 'error', - }, -}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ae800e..634ae46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,15 +25,16 @@ jobs: - name: Run tests (ubuntu) if: matrix.os == 'ubuntu-latest' - run: yarn test-coverage + run: deno test --unstable --allow-write --allow-read --allow-env --import-map=import_map.json --coverage=./coverage/output - name: Run tests (win/mac) if: matrix.os != 'ubuntu-latest' - run: deno test --unstable --allow-net --import-map=import_map.json + run: deno test --unstable --allow-write --allow-read --allow-env --import-map=import_map.json + - name: Generate codecov report if: matrix.os == 'ubuntu-latest' - run: yarn coverage + run: deno coverage --unstable ./coverage --lcov > ./coverage/lcov.info - name: Push codecov report if: matrix.os == 'ubuntu-latest' - run: bash <(curl -s https://codecov.io/bash) + run: bash <(curl -s https://codecov.io/bash) -F color,common,config -c diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 313853f..0000000 --- a/.prettierignore +++ /dev/null @@ -1,16 +0,0 @@ -*.svg -*.png -*.ico -*.sh -*.pxd - -.github/ISSUE_TEMPLATE -.dockerignore -.DS_Store -.eslintignore -.gitattributes -.gitignore -.prettierignore -Dockerfile -LICENSE - diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 0f0c897..0000000 --- a/.prettierrc.js +++ /dev/null @@ -1,38 +0,0 @@ -// .prettierrc.js -module.exports = { - // max 120 characters per line - printWidth: 120, - // use 2 spaces for indentation - tabWidth: 2, - // use spaces instead of indentations - useTabs: false, - // semicolon at the end of the line - semi: true, - // use single quotes - singleQuote: true, - // object's key is quoted only when necessary - quoteProps: 'as-needed', - // use double quotes instead of single quotes in jsx - jsxSingleQuote: false, - // no comma at the end - trailingComma: 'all', - // spaces are required at the beginning and end of the braces - bracketSpacing: true, - // end tag of jsx need to wrap - jsxBracketSameLine: false, - // brackets are required for arrow function parameter, even when there is only one parameter - arrowParens: 'always', - // format the entire contents of the file - rangeStart: 0, - rangeEnd: Infinity, - // no need to write the beginning @prettier of the file - requirePragma: false, - // No need to automatically insert @prettier at the beginning of the file - insertPragma: false, - // use default break criteria - proseWrap: 'preserve', - // decide whether to break the html according to the display style - htmlWhitespaceSensitivity: 'css', - // lf for newline - endOfLine: 'lf', -}; diff --git a/.vscode/launch.json b/.vscode/launch.json index 0660fb9..46bacaf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,12 +5,21 @@ "version": "0.2.0", "configurations": [ { - "name": "test: test", + "name": "Launch", + "type": "node", "request": "launch", - "runtimeExecutable": "yarn", - "runtimeArgs": ["test-inspect"], - "attachSimplePort": 9229, - "type": "pwa-node", + "cwd": "${workspaceFolder}", + "runtimeExecutable": "deno", + "runtimeArgs": [ + "test", + "--inspect=127.0.0.1:9229", + "--unstable", + "--allow-read", + "--allow-write", + "--allow-env", + "--import-map=import_map.json" + ], + "port": 9229, "outputCapture": "std" } ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 2c523f5..d510da5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { "files.eol": "\n", + // deno "deno.enable": true, + "deno.lint": true, "deno.codeLens.implementations": true, "deno.codeLens.references": true, "deno.codeLens.referencesAllFunctions": true, @@ -9,16 +11,15 @@ "deno.suggest.completeFunctionCalls": true, "deno.suggest.paths": true, "deno.importMap": "./import_map.json", + // coverage "coverage-gutters.lcovname": "./coverage/lcov.info", "coverage-gutters.showGutterCoverage": true, + // ui "editor.snippetSuggestions": "inline", "typescript.suggest.completeJSDocs": true, + // formatter "editor.tabSize": 2, "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.organizeImports.eslint": true - }, - "typescript.tsdk": "node_modules/typescript/lib" + "editor.defaultFormatter": "denoland.vscode-deno", + "debug.javascript.unmapMissingSources": true } diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 84d26ef..bba9727 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -1,11 +1,9 @@ # Contribute + ```bash -# ensure you have extensions installed +# docker should be installed +docker build -t trailmix -f .docker/Dockerfile . -# setup env -yarn -# test all projects -yarn test -# test one project -yarn test-one color/*_test.ts -``` \ No newline at end of file +# now run tests +docker run trailmix deno test --unstable --allow-write --allow-read --allow-env --import-map=import_map.json +``` diff --git a/README.md b/README.md index 8818673..8bf5680 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,118 @@ -# utilities +

trailmix/utilities

-Repository of utilities for deno written in typescript for trailmix🌤🦕🍣😼 -[![art djkittyplayz][art]](http://djkittyplayz.art/) -[![codecov][codecov]](https://app.codecov.io/gh/trailmix/utilities) -[![downloads][downloads]](https://deno.land/x/trailmix) -[![goofus_colors goofus colors trailmix deno typescript][goofus]](https://deno.land/x/trailmix) - -[![svg][svg]](https://app.codecov.io/gh/trailmix/utilities) +

Repository of utilities for deno written in typescript for trailmix🌤🦕🍣😼

+

+ + deno + + + trailmix utilities + + + art djkittyplayz + + + downloads + +

+

+ + ci + + + codecov master + + + codecov next + + + ci + +

+

+ + codecov master + + + codecov next + +

## Usage -### Simple +### Colors + + goofus_colors goofus colors trailmix deno typescript + + +**Simple** ```typescript // import fns and style helpers import { + messageByFn, messageByFnSpread, messageByString, messageByStringSpread, - messageByFn, + random, randomOpts, randomStyleFn, randomStyleString, - random, styles as s, -} from 'https://deno.land/x/trailmix@1.0.3/mod.ts'; +} from "https://deno.land/x/trailmix@1.0.4/mod.ts"; // random StyleFn Message Functions -console.log(messageByFn('hello', [s.cyan, s.bgRed])); // cyan text, red BG -console.log(messageByFnSpread('test', s.yellow, s.bgRed)); // yellow text, red BG +console.log(messageByFn("hello", [s.cyan, s.bgRed])); // cyan text, red BG +console.log(messageByFnSpread("test", s.yellow, s.bgRed)); // yellow text, red BG // random Style Functions -console.log(randomStyleFn('emphasis')); // get a random emphasis typeof StyleFn {(str:string) => string} -console.log(randomStyleString('color')); // get a random color string typeof Style +console.log(randomStyleFn("emphasis")); // get a random emphasis typeof StyleFn {(str:string) => string} +console.log(randomStyleString("color")); // get a random color string typeof Style // random StyleString Message Functions -console.log(messageByString('hello', [randomStyleString('color')])); // random text color -console.log(messageByStringSpread('hello', randomStyleString('bgColor'))); // random background color -console.log(messageByFnSpread('hello', s[randomStyleString('emphasis')])); // call style list with random style fn -console.log(random('hello')); // get random style on this string (50% chance of color/bg/emphasis) -console.log(random('hello', { color: true })); // get random color on this string -console.log(random('hello', randomOpts({ color: true }))); // get random color 100%, (50% chance for others) +console.log(messageByString("hello", [randomStyleString("color")])); // random text color +console.log(messageByStringSpread("hello", randomStyleString("bgColor"))); // random background color +console.log(messageByFnSpread("hello", s[randomStyleString("emphasis")])); // call style list with random style fn +console.log(random("hello")); // get random style on this string (50% chance of color/bg/emphasis) +console.log(random("hello", { color: true })); // get random color on this string +console.log(random("hello", randomOpts({ color: true }))); // get random color 100%, (50% chance for others) ``` -### Complex +**Complex** ```typescript // import the class and style helpers -import { Color as C, styles as s } from 'https://deno.land/x/trailmix@1.0.1/mod.ts'; -import type { Styles } from 'https://deno.land/x/trailmix@1.0.1/mod.ts'; +import { + Color as C, + styles as s, +} from "https://deno.land/x/trailmix@1.0.4/mod.ts"; +import type { Styles } from "https://deno.land/x/trailmix@1.0.4/mod.ts"; // you can use defined or anon functions function test(str: string) { - return str + 'defined function'; + return str + "defined function"; } const byFnConfAlpha = [ C.randomStyleFn(), // randoms return a random text color by default test, - C.randomStyleFn('bgColor'), + C.randomStyleFn("bgColor"), (str: string) => { // anon functions can be used - return str + C.random('anon function', { emphasis: true }); + return str + C.random("anon function", { emphasis: true }); }, ]; const rConf = { color: true, bgColor: true, emphasis: false }; const byFnConfBeta = [ C.stylesMap.color.brightBlue, // stylesMap is ordered by color|bgColor|emphasis (str: string) => { - return str + 'anon function'; + return str + "anon function"; }, C.stylesMap.color.yellow, C.stylesMap.bgColor.bgBrightCyan, @@ -75,23 +122,79 @@ const byFnConfBeta = [ C.stylesMap.bgColor.bgBrightYellow, test, (str: string) => { - return 'anon function' + str; + return "anon function" + str; }, C.styles.bgBrightYellow, ]; -const _sList: Styles[] = ['cyan', 'bgMagenta', 'underline']; // list of Style strings -console.log(C.messageByFnSpread('test', ...byFnConfAlpha)); // spread StyleFns -console.log(C.messageByFnSpread('test', ...byFnConfBeta)); -console.log(C.messageByString('this is not a spring spread', ['cyan', 'bgMagenta', 'underline'])); // no spread -console.log(C.messageByStringSpread('a spring spread', 'green', 'bgBlack', 'strikethrough')); // spreading Style strings -console.log(C.messageByStringSpread('a spring spread again with a var', ..._sList)); -console.log(C.random('test some string', rConf)); // random function +const _sList: Styles[] = ["cyan", "bgMagenta", "underline"]; // list of Style strings +console.log(C.messageByFnSpread("test", ...byFnConfAlpha)); // spread StyleFns +console.log(C.messageByFnSpread("test", ...byFnConfBeta)); +console.log( + C.messageByString("this is not a spring spread", [ + "cyan", + "bgMagenta", + "underline", + ]), +); // no spread +console.log( + C.messageByStringSpread( + "a spring spread", + "green", + "bgBlack", + "strikethrough", + ), +); // spreading Style strings +console.log( + C.messageByStringSpread("a spring spread again with a var", ..._sList), +); +console.log(C.random("test some string", rConf)); // random function ``` -## [CONTRIBUTE](CONTRIBUTE.md) +### Config + + goofus_config goofus config trailmix deno typescript + + +**Simple** + +```typescript +import { EnvConfig, StringConfig } from "https://deno.land/x/trailmix@1.0.4/mod.ts"; + +Deno.env.set("DEFAULT_TEST1", "val1"); // set example env var in DEFAULT namespace +// slurp up env vars +console.log(EnvConfig.parseEnv()); // should have { test1: "val1" } +// something more complex +Deno.env.set("DEFAULT_CONSOLE_LEVEL", "DEBUG"); // set log level in DEFAULT namespace +console.log(EnvConfig.parseEnv()); // should have { test1: "val1", console: { level: "DEBUG" } } +// this is good for cmd line arguments (--consoleLevel DEBUG) +console.log(StringConfig.parseEnv({ test1: "val1", consoleLevel: "DEBUG" })); // should have same as above +``` + +**Complex** + +```typescript +import { Config, EnvConfig, StringConfig } from "https://deno.land/x/trailmix@1.0.4/mod.ts"; -[goofus]: https://trailmix-images.s3.amazonaws.com/gooface/gooface-color.png -[art]: https://img.shields.io/badge/art-djkittyplayz-yellow -[codecov]: https://codecov.io/gh/trailmix/utilities/branch/master/graph/badge.svg?token=96CJ5IPAAN -[downloads]: https://img.shields.io/github/downloads/trailmix/utilities/total -[svg]: https://codecov.io/gh/trailmix/utilities/branch/master/graphs/tree.svg +// lets use our own namespace with a config file +const c = await new Config({ + namespace: "TRAILMIX", + prefix: "trailmixString.config", +}).init(); +// inside trailmixString.config.ts/tsx +export default { + consoleFormat: "json", +}; +console.log(new StringConfig(c).parseLog()); // will give a log config with {console: { format: "json" } } +// now lets take into account env vars +Deno.env.set("TRAILMIX_CONSOLE_FORMAT", "console"); +console.log(new EnvConfig(c).parseLog()); // will give a log config with {console: { format: "console" } } +``` + +### Log + +### Watch + +## [CONTRIBUTE](CONTRIBUTE.md) diff --git a/color/Color.d.ts b/color/Color.d.ts deleted file mode 100644 index 380038d..0000000 --- a/color/Color.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { styleEnum, EnumColor, EnumBgColor, EnumEmphasis } from 'trailmix/color/enum.ts'; - -export type StyleTypes = Exclude; -// list of all style strings -export type Styles = keyof typeof EnumColor | keyof typeof EnumBgColor | keyof typeof EnumEmphasis; - -// generic style function string return string -export type StyleFn = (str: string) => string; - -// for each style type use the styleEnum to get each name -export type StylesMap = { - [key in StyleTypes]: { - [e in keyof typeof styleEnum[key] as Styles]: StyleFn; - }; -}; - -// map of all styles to a function -export type StyleMap = Record; - -// options by string -export type StyleOptions = { - [key in StyleTypes]?: keyof typeof styleEnum[key]; -}; -// random options bools -export type RandomStyleOptions = { - [key in StyleTypes]?: boolean; -}; diff --git a/color/Color.ts b/color/Color.ts deleted file mode 100644 index ce9c1c5..0000000 --- a/color/Color.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as colors from 'fmt/colors.ts'; -import type { StylesMap, StyleMap, StyleFn, Styles, StyleTypes, RandomStyleOptions } from 'trailmix/color/Color.d.ts'; -import { EnumColor, EnumBgColor, EnumEmphasis } from 'trailmix/color/enum.ts'; - -export default class Color { - public static stylesMap: StylesMap = { - color: Color._get_style_map(EnumColor), - bgColor: Color._get_style_map(EnumBgColor), - emphasis: Color._get_style_map(EnumEmphasis), - }; - public static styles: StyleMap = { - ...Color.stylesMap.color, - ...Color.stylesMap.bgColor, - ...Color.stylesMap.emphasis, - }; - // list of style strings - private static _styleList: Record = { - color: Object.keys(Color.stylesMap.color) as Styles[], - bgColor: Object.keys(Color.stylesMap.bgColor) as Styles[], - emphasis: Object.keys(Color.stylesMap.emphasis) as Styles[], - }; - - /** - * pass in string and formatting fns to format string with color and style - // * @public - // * @static - // * @param str string to format - // * @param fns functions to use - // * @returns formatted string - // * @example - // * console.log(Color.messageByFn('hello', [Color.color.cyan, Color.bgColor.bgRed])) - // */ - public static messageByFn(str: string, styles?: (StyleFn | undefined)[]): string { - let msg = str; - if (styles !== undefined) - styles.forEach((style) => { - if (style !== undefined) msg = style(msg); - }); - return msg; - } - public static messageByFnSpread(str: string, ...styles: (StyleFn | undefined)[]): string { - let msg = str; - if (styles !== undefined) - styles.forEach((style) => { - if (style !== undefined) msg = style(msg); - }); - return msg; - } - public static messageByString(str: string, styles: (Styles | undefined)[]): string { - let msg = str; - if (styles !== undefined) - styles.forEach((style) => { - if (style !== undefined) msg = Color.styles[style](msg); - }); - return msg; - } - public static messageByStringSpread(str: string, ...styles: (Styles | undefined)[]): string { - let msg = str; - if (styles !== undefined) - styles.forEach((style) => { - if (style !== undefined) msg = Color.styles[style](msg); - }); - return msg; - } - - public static random(str: string, { color, bgColor, emphasis }: RandomStyleOptions = Color.randomOpts()): string { - const c = [undefined, false].includes(color) ? undefined : Color.randomStyleFn(); - const bgC = [undefined, false].includes(bgColor) ? undefined : Color.randomStyleFn('bgColor'); - const e = [undefined, false].includes(emphasis) ? undefined : Color.randomStyleFn('emphasis'); - const r: Array = new Array(c ?? undefined, bgC ?? undefined, e ?? undefined); - return Color.messageByFn(str, r); - } - public static randomOpts({ color, bgColor, emphasis }: RandomStyleOptions = {}): RandomStyleOptions { - const ret: RandomStyleOptions = { - color: color ?? Math.random() >= 0.5 ? true : false, - bgColor: bgColor ?? Math.random() >= 0.5 ? true : false, - emphasis: emphasis ?? Math.random() >= 0.5 ? true : false, - }; - return ret; - } - /** - * - * @param type pass in a string type of style - * @returns {StyleFn} random function of type EnumColor|EnumBgColor|EnumEmphasis - */ - public static randomStyleFn(type: StyleTypes = 'color'): StyleFn { - return Color.styles[Color.randomStyleString(type)]; - } - public static randomStyleString(type: StyleTypes = 'color'): Styles { - const styleNum = Color._randomNumber(Color._styleList[type].length); - return Color._styleList[type][styleNum]; - } - // get map of name, style function - private static _get_style_map(s: Object): StyleMap { - return Object.fromEntries( - Object.entries(colors) - .concat([['clear', (str: string) => str]]) - .flatMap(([style, fn]) => { - return [ - ...(s !== undefined && Object.values(s).filter((_style) => _style === style).length > 0 - ? [[String(style), fn]] - : []), - ]; - }), - ); - } - /** - * @param max max number to find random number (min is 0) - * @returns random number within len - */ - private static _randomNumber(max = 1): number { - return Number(((max - 1) * Number(Math.random())).toFixed(0)); - } -} -export const messageByFn = Color.messageByFn; -export const messageByFnSpread = Color.messageByFnSpread; -export const messageByString = Color.messageByString; -export const messageByStringSpread = Color.messageByStringSpread; -export const random = Color.random; -export const randomOpts = Color.randomOpts; -export const randomStyleFn = Color.randomStyleFn; -export const randomStyleString = Color.randomStyleString; -export const stylesMap: StylesMap = Color.stylesMap; -export const styles: StyleMap = Color.styles; diff --git a/color/Color_test.ts b/color/Color_test.ts deleted file mode 100644 index 007297b..0000000 --- a/color/Color_test.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { - default as Color, - messageByFn, - messageByFnSpread, - messageByString, - messageByStringSpread, - random, - randomOpts, - randomStyleFn, - randomStyleString, - stylesMap, -} from 'trailmix/color/Color.ts'; -import { styleEnum } from 'trailmix/color/enum.ts'; -import type { Styles, StyleFn } from 'trailmix/color/Color.d.ts'; -import { assertStrictEquals, assertNotEquals } from 'testing/asserts.ts'; -import { Table, Row, Cell } from 'cliffy/table'; - -let testCases: string[] = []; -let testName: string; -const ogConsole = console.log; -let table = resetTable(); -function resetTable(table?: []): Table { - return ( - new Table() - .body(table ?? []) - // .maxColWidth(100) - .border(true) - .padding(1) - .indent(2) - ); -} -function consoleMock(...data: string[]) { - const expected = Array.isArray(testCases) ? testCases.filter((test) => test === data.join(''))[0] : testCases; - const actual = data.join(''); - try { - assertNotEquals(expected, '', `Did not find matching string in [testCases]\n ${JSON.stringify(testCases)}`); - assertStrictEquals( - actual, - expected, - `console.log() messages failure: (actual !== expected)\n "${actual}" !== "${expected}"`, - ); - if (typeof JSON.parse(actual) !== 'object') - assertStrictEquals( - JSON.parse(actual), - JSON.parse(expected), - `console.log() JSON.parse() messages failure: (actual !== expected)\n "${actual}" !== "${expected}"`, - ); - table.push( - Row.from([ - Cell.from('🧪🧪🧪🧪\t\x1b[1m\x1b[92m\x1b[4m' + testName.trim() + '\x1b[24m\x1b[39m\x1b[22m\n').colSpan(3), - ]).border(false), - [actual, '===', expected], - ); - if (typeof JSON.parse(actual) !== 'object') table.push([JSON.parse(actual), '===', JSON.parse(expected)]); - } catch (e) { - table.push( - Row.from([ - Cell.from('🚨🚨🚨🚨\t\x1b[1m\x1b[91m\x1b[4m' + testName.trim() + '\x1b[24m\x1b[39m\x1b[22m' + e + '\n').colSpan( - 3, - ), - ]).border(false), - [actual, '!==', expected], - [JSON.parse(actual ?? []), '!==', JSON.parse(expected ?? [])], - ); - } -} - -const tests = { - string: { - random: { - color: { - color: false, - }, - bgColor: { - bgColor: false, - }, - emphasis: { - emphasis: false, - }, - }, - randomOpts: { ...Object.keys(styleEnum).filter((key) => key !== 'suffix') }, - randomStyleFn: { ...Object.keys(styleEnum).filter((key) => key !== 'suffix') }, - randomStyleString: { ...Object.keys(styleEnum).filter((key) => key !== 'suffix') }, - }, - stringEmpty: { - random: { - color: {}, - }, - messageByFn: { - fixed: [], - }, - messageByString: { - fixed: [], - }, - }, - undefined: { - random: undefined, - }, - stringUndefined: { - random: { - color: { - color: undefined, - }, - bgColor: { - bgColor: undefined, - }, - emphasis: { - emphasis: undefined, - }, - }, - messageByFn: { - fixed: [undefined], - fixedU: [stylesMap.color.red, undefined], - }, - messageByString: { - fixedU: ['red', undefined], - fixed: [undefined], - }, - }, - stringColor: { - random: { - color: { - color: true, - }, - }, - messageByFn: { - fixed: [stylesMap.color.green], - fixedU: [stylesMap.color.red, undefined], - random: [randomStyleFn('color')], - randomU: [randomStyleFn('color'), undefined], - }, - messageByString: { - fixed: ['green'], - fixedU: ['red', undefined], - random: [randomStyleString('color')], - randomU: [randomStyleString('color'), undefined], - }, - }, - stringBgColor: { - random: { - color: { - bgColor: true, - }, - }, - messageByFn: { - fixed: [stylesMap.bgColor.bgBrightRed], - random: [randomStyleFn('bgColor')], - }, - messageByString: { - fixed: ['bgBrightRed'], - random: [randomStyleString('bgColor')], - }, - }, - stringEmphasis: { - random: { - color: { - emphasis: true, - }, - }, - messageByFn: { - fixed: [stylesMap.emphasis.bold], - random: [randomStyleFn('emphasis')], - }, - messageByString: { - fixed: ['bold'], - random: [randomStyleString('emphasis')], - }, - }, - stringColorBgColor: { - random: { - color: { - color: true, - bgColor: true, - }, - }, - messageByFn: { - fixed: [stylesMap.color.green, stylesMap.bgColor.bgBrightRed], - random: [randomStyleFn('color'), randomStyleFn('bgColor')], - }, - messageByString: { - fixed: ['green', 'bgBrightRed'], - random: [randomStyleString('color'), randomStyleString('bgColor')], - }, - }, - stringColorBgColorEmphasis: { - random: { - color: { - color: true, - bgColor: true, - emphasis: true, - }, - }, - messageByFn: { - fixed: [stylesMap.color.green, stylesMap.bgColor.bgBrightRed, stylesMap.emphasis.bold], - random: [randomStyleFn('color'), randomStyleFn('bgColor'), randomStyleFn('emphasis')], - }, - messageByString: { - fixed: ['green', 'bgBrightRed', 'bold'], - random: [randomStyleString('color'), randomStyleString('bgColor'), randomStyleString('emphasis')], - }, - }, - stringBgColorEmphasis: { - random: { - color: { - bgColor: true, - emphasis: true, - }, - }, - messageByFn: { - fixed: [stylesMap.bgColor.bgBrightRed, stylesMap.emphasis.bold], - random: [randomStyleFn('bgColor'), randomStyleFn('emphasis')], - }, - messageByString: { - fixed: ['bgBrightRed', 'bold'], - random: [randomStyleString('bgColor'), randomStyleString('emphasis')], - }, - }, - stringColorEmphasis: { - random: { - color: { - color: true, - emphasis: true, - }, - }, - messageByFn: { - fixed: [stylesMap.color.green, stylesMap.emphasis.bold], - random: [randomStyleFn('color'), randomStyleFn('emphasis')], - }, - messageByString: { - fixed: ['green', 'bold'], - random: [randomStyleString('color'), randomStyleString('emphasis')], - }, - }, -}; - -for (const style of Object.keys(stylesMap)) { - // @ts-ignore - for (const fn of Object.keys(stylesMap[style])) { - Deno.test({ - name: `Color.ts`, - fn: () => { - testName = `style:${style}, test:${fn}`; - // @ts-ignore - const args = stylesMap[style][fn]; - let msg = ''; - msg = JSON.stringify(args(style)); - console.log = consoleMock; - testCases = [msg]; - console.log(msg); - console.log = ogConsole; - if ( - Object.keys(stylesMap).length - 1 === Object.keys(stylesMap).indexOf(style) && - // @ts-ignore - Object.keys(stylesMap[style]).length - 1 === Object.keys(stylesMap[style]).indexOf(fn) - ) { - table.render(); - table = resetTable(); - } - }, - }); - } -} -for (const test of Object.keys(tests)) { - // @ts-ignore - for (const fn of Object.keys(tests[test])) { - for (const obj of [true, false]) { - // @ts-ignore - for (const stylefn of Object.keys(tests[test][fn] ?? { undefined: undefined })) { - for (const spread of [true, false]) { - Deno.test({ - name: `Color.ts`, - fn: () => { - testName = `${test}, fn:${fn}, styleFn:${stylefn}, spread:${spread}, fromObj:${obj}\n`; - ogConsole(testName); - // @ts-ignore - const args = stylefn === 'undefined' ? tests[test][fn] : tests[test][fn][stylefn]; - let TmessageByStringSpread = messageByStringSpread; - let TmessageByString = messageByString; - let TmessageByFnSpread = messageByFnSpread; - let TmessageByFn = messageByFn; - let TrandomOpts = randomOpts; - let TrandomStyleFn = randomStyleFn; - let TrandomStyleString = randomStyleString; - let Trandom = random; - if (obj) { - TmessageByStringSpread = Color.messageByStringSpread; - TmessageByString = Color.messageByString; - TmessageByFnSpread = Color.messageByFnSpread; - TmessageByFn = Color.messageByFn; - TrandomOpts = Color.randomOpts; - TrandomStyleFn = Color.randomStyleFn; - TrandomStyleString = Color.randomStyleString; - Trandom = Color.random; - } - let msg = ''; - if (fn === 'messageByString') { - if (spread) msg = JSON.stringify(TmessageByStringSpread(test, ...(args as Styles[]))); - else msg = JSON.stringify(TmessageByString(test, args as Styles[])); - } - if (fn === 'messageByFn') { - if (spread) msg = JSON.stringify(TmessageByFnSpread(test, ...(args as StyleFn[]))); - else msg = JSON.stringify(TmessageByFn(test, args as StyleFn[])); - } - if (fn === 'randomOpts') msg = JSON.stringify(TrandomOpts(args)); - if (fn === 'randomStyleFn') msg = JSON.stringify(TrandomStyleFn(args)(test)); - if (fn === 'randomStyleString') msg = JSON.stringify(TrandomStyleString(args)); - if (fn === 'random') msg = JSON.stringify(Trandom(test, args)); - console.log = consoleMock; - testCases = [msg]; - console.log(msg); - console.log = ogConsole; - if ( - Object.keys(tests).length - 1 === Object.keys(tests).indexOf(test) && - // @ts-ignore - Object.keys(tests[test]).length - 1 === Object.keys(tests[test]).indexOf(fn) && - // @ts-ignore - Object.keys(tests[test][fn]).length - 1 === Object.keys(tests[test][fn]).indexOf(stylefn) && - !spread - ) { - table.render(); - table = resetTable(); - } - }, - }); - } - } - } - } -} diff --git a/import_map.json b/import_map.json index 4f6f0b0..00a5c69 100644 --- a/import_map.json +++ b/import_map.json @@ -1,9 +1,13 @@ { "imports": { - "trailmix/": "./", - "trailmix/color": "./color/mod.ts", + "trailmix/": "./src/", + "test/": "./test/", + "uuid/": "https://deno.land/std@0.91.0/uuid/", + "fs/": "https://deno.land/std@0.91.0/fs/", + "path/": "https://deno.land/std@0.91.0/path/", "testing/": "https://deno.land/std@0.91.0/testing/", "fmt/": "https://deno.land/std@0.91.0/fmt/", + "log/": "https://deno.land/std@0.84.0/log/", "cliffy/table": "https://deno.land/x/cliffy@v0.18.1/table/mod.ts" } } diff --git a/mod.ts b/mod.ts index 766c58f..f2a10fe 100644 --- a/mod.ts +++ b/mod.ts @@ -1,15 +1,3 @@ -export type { Styles } from 'trailmix/color/mod.ts'; -export { - Color, - messageByFn, - messageByFnSpread, - messageByString, - messageByStringSpread, - random, - randomOpts, - randomStyleFn, - randomStyleString, - styleEnum, - styles, - stylesMap, -} from 'trailmix/color/mod.ts'; +export * as config from "trailmix/config/mod.ts"; +export * as color from "trailmix/color/mod.ts"; +export * as common from "trailmix/common/mod.ts"; diff --git a/package.json b/package.json deleted file mode 100644 index 841e6b7..0000000 --- a/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "utilities", - "version": "1.0.1", - "description": "A lib of utilities for trailmix.", - "main": "mod.ts", - "scripts": { - "test": "deno test --unstable --allow-net --import-map=import_map.json **/*_test.ts", - "test-one": "deno test --unstable --allow-net --import-map=import_map.json", - "test-inspect": "deno test --unstable --allow-net --import-map=import_map.json --inspect **/*_test.ts", - "test-coverage": "deno test --unstable --allow-net --import-map=import_map.json --coverage=./coverage/output **/*_test.ts", - "coverage": "deno coverage --unstable ./coverage --lcov > ./coverage/lcov.info", - "coverage-html": "genhtml -o coverage/html ./coverage/lcov.info" - }, - "author": "trilom ", - "license": "MIT", - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^4.11.0", - "@typescript-eslint/parser": "^4.11.0", - "codecov": "^3.8.1", - "eslint": "^7.16.0", - "eslint-config-alloy": "^3.9.0", - "eslint-plugin-react": "^7.21.5", - "npm-run-all": "^4.1.5", - "prettier": "^2.2.1", - "typescript": "^4.1.3" - } -} diff --git a/src/color/Color.d.ts b/src/color/Color.d.ts new file mode 100644 index 0000000..a3a340d --- /dev/null +++ b/src/color/Color.d.ts @@ -0,0 +1,35 @@ +import type { + EnumBgColor, + EnumColor, + EnumEmphasis, + styleEnum, +} from "trailmix/color/enum.ts"; + +export type StyleType = Exclude; +// list of all style strings +export type Style = + | keyof typeof EnumColor + | keyof typeof EnumBgColor + | keyof typeof EnumEmphasis; + +// generic style function string return string +export type StyleFn = (str: string) => string; + +// for each style type use the styleEnum to get each name +export type StyleTypeMap = { + [key in StyleType]: { + [e in keyof typeof styleEnum[key] as Style]: StyleFn; + }; +}; + +// map of all styles to a function +export type StyleMap = Record; + +// options by string +export type StyleOptions = { + [key in StyleType]?: keyof typeof styleEnum[key]; +}; +// random options bools +export type RandomStyleOptions = { + [key in StyleType]?: boolean | Style; +}; diff --git a/src/color/Color.ts b/src/color/Color.ts new file mode 100644 index 0000000..9862775 --- /dev/null +++ b/src/color/Color.ts @@ -0,0 +1,172 @@ +import { colors } from "trailmix/deps.ts"; +import { + EnumBgColor, + EnumColor, + EnumEmphasis, + EnumSuffix, +} from "trailmix/color/enum.ts"; +import type { + RandomStyleOptions, + Style, + StyleFn, + StyleMap, + StyleType, + StyleTypeMap, +} from "trailmix/color/Color.d.ts"; +export const styleEnum = { + color: EnumColor, + bgColor: EnumBgColor, + emphasis: EnumEmphasis, + suffix: EnumSuffix, +}; + +export default class Color { + public static styleTypeMap: StyleTypeMap = { + color: Color._get_style_map(EnumColor), + bgColor: Color._get_style_map(EnumBgColor), + emphasis: Color._get_style_map(EnumEmphasis), + }; + public static styleMap: StyleMap = { + ...Color.styleTypeMap.color, + ...Color.styleTypeMap.bgColor, + ...Color.styleTypeMap.emphasis, + }; + // list of style strings + private static _styleList: Record = { + color: Object.keys(Color.styleTypeMap.color) as Style[], + bgColor: Object.keys(Color.styleTypeMap.bgColor) as Style[], + emphasis: Object.keys(Color.styleTypeMap.emphasis) as Style[], + }; + private static _styleNames: Style[] = [ + ...Color._styleList.color, + ...Color._styleList.bgColor, + ...Color._styleList.emphasis, + ]; + /** + * pass in string and formatting fns to format string with color and style + // * @public + // * @static + // * @param str string to format + // * @param fns functions to use + // * @returns formatted string + // * @example + // * console.log(Color.messageByFn('hello', [Color.color.cyan, Color.bgColor.bgRed])) + // */ + public static messageByFn( + str: string, + styles?: (StyleFn | undefined)[], + ): string { + let msg = str; + if (styles !== undefined) { + styles.forEach((style) => { + if (style !== undefined) msg = style(msg); + }); + } + return msg; + } + public static messageByFnSpread( + str: string, + ...styles: (StyleFn | undefined)[] + ): string { + let msg = str; + if (styles !== undefined) { + styles.forEach((style) => { + if (style !== undefined) msg = style(msg); + }); + } + return msg; + } + public static messageByString( + str: string, + styles: (Style | undefined)[], + ): string { + let msg = str; + if (styles !== undefined) { + styles.forEach((style) => { + if (style !== undefined) msg = Color.styleMap[style](msg); + }); + } + return msg; + } + public static messageByStringSpread( + str: string, + ...styles: (Style | undefined)[] + ): string { + let msg = str; + if (styles !== undefined) { + styles.forEach((style) => { + if (style !== undefined) msg = Color.styleMap[style](msg); + }); + } + return msg; + } + + public static random( + str: string, + { color, bgColor, emphasis }: RandomStyleOptions = Color.randomOpts(), + ): string { + const c = Color._styleNames.includes(color as Style) + ? Color.styleMap[color as Style] + : Color.randomStyleFn(); + const bgC = Color._styleNames.includes(bgColor as Style) + ? Color.styleMap[bgColor as Style] + : Color.randomStyleFn("bgColor"); + const e = Color._styleNames.includes(emphasis as Style) + ? Color.styleMap[emphasis as Style] + : Color.randomStyleFn("emphasis"); + return Color.messageByFn(str, [c, bgC, e]); + } + public static randomOpts( + { color, bgColor, emphasis }: RandomStyleOptions = {}, + ): RandomStyleOptions { + return { + color: color ?? (Math.random() >= 0.5 ? true : false), + bgColor: bgColor ?? (Math.random() >= 0.5 ? true : false), + emphasis: emphasis ?? (Math.random() >= 0.5 ? true : false), + }; + } + /** + * + * @param type pass in a string type of style + * @returns {StyleFn} random function of type EnumColor|EnumBgColor|EnumEmphasis + */ + public static randomStyleFn(type: StyleType = "color"): StyleFn { + return Color.styleMap[Color.randomStyleString(type)]; + } + public static randomStyleString(type: StyleType = "color"): Style { + const styleNum = Color._randomNumber(Color._styleList[type].length); + return Color._styleList[type][styleNum]; + } + // get map of name, style function + private static _get_style_map(s: Record): StyleMap { + return Object.fromEntries( + Object.entries(colors) + .concat([["clear", (str: string) => str]]) + .flatMap(([style, fn]) => { + return [ + ...(s !== undefined && + Object.values(s).filter((_style) => _style === style).length > 0 + ? [[String(style), fn]] + : []), + ]; + }), + ); + } + /** + * @param max max number to find random number (min is 0) + * @returns random number within len + */ + private static _randomNumber(max = 1): number { + return Number(((max - 1) * Number(Math.random())).toFixed(0)); + } +} +export const messageByFn = Color.messageByFn; +export const messageByFnSpread = Color.messageByFnSpread; +export const messageByString = Color.messageByString; +export const messageByStringSpread = Color.messageByStringSpread; +export const random = Color.random; +export const randomOpts = Color.randomOpts; +export const randomStyleFn = Color.randomStyleFn; +export const randomStyleString = Color.randomStyleString; +export const stylesMap: StyleTypeMap = Color.styleTypeMap; +export const styles: StyleMap = Color.styleMap; diff --git a/src/color/Color_test.ts b/src/color/Color_test.ts new file mode 100644 index 0000000..9862c6d --- /dev/null +++ b/src/color/Color_test.ts @@ -0,0 +1,337 @@ +// import { Table, Row, Cell, assertStrictEquals, assertNotEquals } from 'testType/deps.ts'; +import { resetTable, testFunction } from "trailmix/common/table.ts"; +import { s_p, s_s } from "trailmix/common/enum.ts"; +import { + Color, + messageByFn, + messageByFnSpread, + messageByString, + messageByStringSpread, + random, + randomOpts, + randomStyleFn, + randomStyleString, + stylesMap, + StyleType, +} from "trailmix/color/mod.ts"; +import type { Style, StyleFn } from "trailmix/color/mod.ts"; +import { assertEquals, assertMatch } from "trailmix/deps.ts"; + +let table = resetTable(); + +// pass in fn name, optional: (class bool, spread bool) +// return function to testType +function getTarget( + fn: string, + c = false, + s = false, +): (...args: unknown[]) => unknown { + const fns: Record = { + messageByFn: s + ? (c ? Color.messageByFnSpread : messageByFnSpread) + : c + ? Color.messageByFn + : messageByFn, + messageByString: s + ? c ? Color.messageByStringSpread : messageByStringSpread + : c + ? Color.messageByString + : messageByString, + randomOpts: c ? Color.randomOpts : randomOpts, + randomStyleFn: c ? Color.randomStyleFn : randomStyleFn, + randomStyleString: c ? Color.randomStyleString : randomStyleString, + random: c ? Color.random : random, + }; + return fns[fn] as (...args: unknown[]) => unknown; +} +function testString( + str: string, + opts: (keyof typeof s_s | keyof typeof s_p)[] = [], +) { + let ret = str; + for (const opt in opts) { + ret = s_p[opts[opt]] + ret + s_s[opts[opt]]; + } + return ret; +} + +function testRegExp(prefix?: string, suffix?: string) { + let ret = new RegExp( + /(\\u001b\[[0-9]{1,3}m)*(color|bgColor|emphasis)+(\\u001b\[[0-9]{1,3}m)*/, + ); + if (prefix !== undefined && suffix !== undefined) { + ret = new RegExp( + "\\S*(\\u001b\\[" + prefix + + "m){1}\\S*(color|emphasis|bgColor){1}\\S*(\\u001b\\[" + suffix + + "m){1}\\S*", + ); + } + return ret; +} +const randomTests: Record< + string, + Record< + string, + Record< + string, + Record< + "i" | "o", + Record | string | boolean | RegExp + > + > + > +> = { + random: { + string: { + color: { + i: { color: "green", bgColor: false, emphasis: false }, + o: testRegExp("32", "39"), + }, + bgColor: { + i: { color: false, bgColor: "bgRed", emphasis: false }, + o: testRegExp("41", "49"), + }, + emphasis: { + i: { color: false, bgColor: false, emphasis: "bold" }, + o: testRegExp("1", "22"), + }, + }, + boolean: { + color: { + i: { color: true, bgColor: false, emphasis: false }, + o: testRegExp(), + }, + bgColor: { + i: { color: false, bgColor: true, emphasis: false }, + o: testRegExp(), + }, + emphasis: { + i: { color: false, bgColor: false, emphasis: true }, + o: testRegExp(), + }, + }, + }, + randomOpts: { + string: { + color: { i: { color: "green" }, o: "green" }, + bgColor: { i: { bgColor: "bgRed" }, o: "bgRed" }, + emphasis: { i: { emphasis: "bold" }, o: "bold" }, + }, + false: { + color: { i: { color: false }, o: false }, + bgColor: { i: { bgColor: false }, o: false }, + emphasis: { i: { emphasis: false }, o: false }, + }, + true: { + color: { i: { color: true }, o: true }, + bgColor: { i: { bgColor: true }, o: true }, + emphasis: { i: { emphasis: true }, o: true }, + }, + }, +}; +const newTests: Record< + string, + Record< + string, + Record< + "i" | "o", + (string | StyleFn | undefined)[] | undefined[] | string | undefined + > + > +> = { + messageByFn: { + stringEmpty: { + i: "", + o: "", + }, + stringUndefined: { + i: undefined, + o: "undefined", + }, + stringUndefinedSet: { + i: [stylesMap.color.red, undefined], + o: testString("stringUndefinedSet", ["r"]), + }, + stringColor: { + i: [stylesMap.color.green], + o: testString("stringColor", ["g"]), + }, + stringBgColor: { + i: [stylesMap.bgColor.bgRed], + o: testString("stringBgColor", ["bg_r"]), + }, + stringEmphasis: { + i: [stylesMap.emphasis.bold], + o: testString("stringEmphasis", ["B"]), + }, + stringColorBgColor: { + i: [stylesMap.color.yellow, stylesMap.bgColor.bgGreen], + o: testString("stringColorBgColor", ["y", "bg_g"]), + }, + stringBgColorEmphasis: { + i: [stylesMap.bgColor.bgRed, stylesMap.emphasis.bold], + o: testString("stringBgColorEmphasis", ["bg_r", "B"]), + }, + stringColorEmphasis: { + i: [stylesMap.color.red, stylesMap.emphasis.underline], + o: testString("stringColorEmphasis", ["r", "U"]), + }, + stringColorBgColorEmphasis: { + i: [ + stylesMap.color.red, + stylesMap.bgColor.bgYellow, + stylesMap.emphasis.underline, + ], + o: testString("stringColorBgColorEmphasis", ["r", "bg_y", "U"]), + }, + }, + messageByString: { + stringEmpty: { i: [], o: "" }, + stringUndefined: { i: [undefined], o: "" }, + stringUndefinedSet: { + i: ["red", undefined], + o: testString("stringUndefinedSet", ["r"]), + }, + stringColor: { i: ["green"], o: testString("stringColor", ["g"]) }, + stringBgColor: { i: ["bgRed"], o: testString("stringBgColor", ["bg_r"]) }, + stringEmphasis: { i: ["bold"], o: testString("stringEmphasis", ["B"]) }, + stringColorBgColor: { + i: ["yellow", "bgGreen"], + o: testString("stringColorBgColor", ["y", "bg_g"]), + }, + stringBgColorEmphasis: { + i: ["bgRed", "bold"], + o: testString("stringBgColorEmphasis", ["bg_r", "B"]), + }, + stringColorEmphasis: { + i: ["red", "underline"], + o: testString("stringColorEmphasis", ["r", "U"]), + }, + stringColorBgColorEmphasis: { + i: ["red", "bgYellow", "underline"], + o: testString("stringColorBgColorEmphasis", ["r", "bg_y", "U"]), + }, + }, +}; +for (const style of Object.keys(stylesMap) as StyleType[]) { + for (const testfn of Object.keys(stylesMap[style]) as Style[]) { + Deno.test({ + name: `Color.ts - styleMap tests...`, + fn: () => { + let fn = stylesMap[style][testfn]; + testFunction( + `style:${style}, testType:${testfn}`, + table, + (i = style) => fn(i), + stylesMap[style][testfn](style), + ); + if ( + Object.keys(stylesMap).length - 1 === + Object.keys(stylesMap).indexOf(style) && + Object.keys(stylesMap[style]).length - 1 === + Object.keys(stylesMap[style]).indexOf(testfn) + ) { + table.render(); + } + }, + }); + } +} +for (const testFn of Object.keys(randomTests)) { + for (const testType of Object.keys(randomTests[testFn])) { + for (const testArg of Object.keys(randomTests[testFn][testType])) { + for (const c of [true, false]) { + Deno.test({ + name: "testType", + // only: true, + fn: () => { + const fn = getTarget(testFn, c); // get function to test + const args = randomTests[testFn][testType][testArg].i; // get input argument + testFunction( + `testFn:${testFn}, testType:${testType}, testArg:${testArg}, fromClass:${c}\n`, + table, + ( + _fn = fn, + _args = args, + _testFn = testFn, + _testArg = testArg, + ) => { + if (_testFn === "random") return _fn(_testArg, _args); + else return _fn(_args); + }, + ( + _actual: any, + _expected = randomTests[testFn][testType][testArg].o, + _testArg = testArg, + _testFn = testFn, + ) => { + let expected = _expected; + if (_testFn === "randomOpts") { + expected = { ..._actual, ...{ [_testArg]: _expected } }; + assertEquals(_actual, expected); + return expected; + } else { + assertMatch(_actual, expected as RegExp); + return _actual; + } + }, + ); + if ( + Object.keys(randomTests).length - 1 === + Object.keys(randomTests).indexOf(testFn) && + Object.keys(randomTests[testFn]).length - 1 === + Object.keys(randomTests[testFn]).indexOf(testType) && + Object.keys(randomTests[testFn][testType]).length - 1 === + Object.keys(randomTests[testFn][testType]).indexOf(testArg) && + !c + ) { + table.render(); + table = resetTable(); + } + }, + }); + } + } + } +} +for (const testfn of Object.keys(newTests)) { + for (const testType of Object.keys(newTests[testfn])) { + for (const c of [true, false]) { + for (const s of [true, false]) { + if (["stringEmpty", "stringUndefined"].includes(testType) && s) break; + Deno.test({ + // only: true, + name: `Color.ts - ${testfn} tests...`, + fn: () => { + const fn = getTarget(testfn, c, s); + const args = newTests[testfn][testType].i; + const e = newTests[testfn][testType].o; + testFunction( + `testFn:${testfn}, testType:${testType}, spread:${s}, fromClass:${c}\n`, + table, + (_fn = fn, _args = args, _s = s, _testType = testType) => { + if (typeof args === "string") return _fn(_args); + if (_s && _args !== undefined) { + return _fn(_testType, ..._args); + } else return _fn(_testType, _args); + }, + e, + ); + if ( + Object.keys(newTests).length - 1 === + Object.keys(newTests).indexOf(testfn) && + // @ts-ignore + Object.keys(newTests[testfn]).length - 1 === + Object.keys(newTests[testfn]).indexOf(testType) && + !c && + !s + ) { + table.render(); + table = resetTable(); + } + }, + }); + } + } + } +} diff --git a/color/enum.ts b/src/color/enum.ts similarity index 100% rename from color/enum.ts rename to src/color/enum.ts diff --git a/color/mod.ts b/src/color/mod.ts similarity index 57% rename from color/mod.ts rename to src/color/mod.ts index 75fc7de..f596864 100644 --- a/color/mod.ts +++ b/src/color/mod.ts @@ -10,15 +10,21 @@ export { randomStyleString, styles, stylesMap, -} from 'trailmix/color/Color.ts'; -export { styleEnum, EnumColor, EnumBgColor, EnumEmphasis, EnumSuffix } from 'trailmix/color/enum.ts'; +} from "trailmix/color/Color.ts"; +export { + EnumBgColor, + EnumColor, + EnumEmphasis, + EnumSuffix, + styleEnum, +} from "trailmix/color/enum.ts"; // @deno-types="./Color.d.ts" export type { - StyleTypes, - Styles, + RandomStyleOptions, + Style, StyleFn, - StylesMap, StyleMap, StyleOptions, - RandomStyleOptions, -} from 'trailmix/color/Color.d.ts'; + StyleType, + StyleTypeMap, +} from "trailmix/color/Color.d.ts"; diff --git a/src/common/array.ts b/src/common/array.ts new file mode 100644 index 0000000..f8364fb --- /dev/null +++ b/src/common/array.ts @@ -0,0 +1,22 @@ +/** Remove same items in an array */ +export function unique(arr: any[]) { + const set = new Set(); + arr.filter((item) => { + let dup = set.has(item); + if (typeof item === "object") { + if (set.size === 0) set.add(item); + else { + set.forEach((set_item) => { + if (JSON.stringify(item) !== JSON.stringify(set_item)) { + dup = false; + return set.add(item); + } + }); + } + } else { + set.add(item); + } + return !dup; + }); + return [...new Set(set)]; +} diff --git a/src/common/array_test.ts b/src/common/array_test.ts new file mode 100644 index 0000000..f979e0e --- /dev/null +++ b/src/common/array_test.ts @@ -0,0 +1,76 @@ +import { unique } from "trailmix/common/array.ts"; +import { resetTable, testFunction } from "trailmix/common/table.ts"; + +let table = resetTable(); +// let testCases: string[] = []; +const tests: Record< + string, + Record< + "i" | "o", + ( + | string + | number + | boolean + | undefined + | Record + | (string | number | boolean)[] + )[] + > +> = { + string: { + i: ["1", "1", "2"], + o: ["1", "2"], + }, + number: { + i: [1, 1, 2], + o: [1, 2], + }, + boolean: { + i: [true, true, false], + o: [true, false], + }, + array: { + i: [ + ["1", 1, true], + ["1", 1, true], + ["2", 2, false], + ], + o: [ + ["1", 1, true], + ["2", 2, false], + ], + }, + object: { + i: [{ test: "test1" }, { test: "test1" }, { test: "test2" }], + o: [{ test: "test1" }, { test: "test2" }], + }, + undefined: { + i: [undefined, undefined, 1], + o: [undefined, 1], + }, +}; +for (const test of Object.keys(tests)) { + Deno.test({ + name: "Array.ts", + fn: () => { + let fn = unique; + try { + testFunction( + test, + table, + (i = tests[test].i) => fn(i), + tests[test].o, + ["string", "number", "boolean", "object", "undefined", "array"] + .includes(test), + ); + } finally { + if ( + Object.keys(tests).length - 1 === Object.keys(tests).indexOf(test) + ) { + table.render(); + table = resetTable(); + } + } + }, + }); +} diff --git a/src/common/enum.ts b/src/common/enum.ts new file mode 100644 index 0000000..63253c0 --- /dev/null +++ b/src/common/enum.ts @@ -0,0 +1,31 @@ +export enum s_p { + B = "\x1b[1m", + U = "\x1b[4m", + r = "\x1b[31m", + br = "\x1b[91m", + bg_r = "\x1b[41m", + g = "\x1b[32m", + bg = "\x1b[92m", + bg_g = "\x1b[42m", + y = "\x1b[33m", + by = "\x1b[93m", + bg_y = "\x1b[43m", +} +export enum s_s { + B = "\x1b[22m", + U = "\x1b[24m", + r = "\x1b[39m", + br = "\x1b[39m", + bg_r = "\x1b[49m", + g = "\x1b[39m", + bg = "\x1b[39m", + bg_g = "\x1b[49m", + y = "\x1b[39m", + by = "\x1b[39m", + bg_y = "\x1b[49m", +} +export enum t_e { + br = "🚨🚨🚨🚨", + by = "⚠️ ⚠️ ⚠️ ⚠️", + bg = "🧪🧪🧪🧪", +} diff --git a/src/common/file.d.ts b/src/common/file.d.ts new file mode 100644 index 0000000..1fb934b --- /dev/null +++ b/src/common/file.d.ts @@ -0,0 +1,9 @@ +export interface ImportOptions { + reload?: boolean; +} + +export type FileExtension = + | "ts" + | "yaml" + | "json" + | "js"; diff --git a/src/common/file.ts b/src/common/file.ts new file mode 100644 index 0000000..369c17c --- /dev/null +++ b/src/common/file.ts @@ -0,0 +1,66 @@ +import { exists, extname, resolve } from "trailmix/deps.ts"; + +import type { FileExtension, ImportOptions } from "trailmix/common/file.d.ts"; + +const files: Record = { + ts: ["ts", "tsx"], + yaml: ["yaml", "yml"], + json: ["json"], + js: ["js", "jsx"], +}; + +export async function validPath( + file: string, + ext: FileExtension, + dir = ".", +) { + let found = false; + let path = ""; + for (const _ext of files[ext]) { + path = resolve(dir, `${file}.${_ext}`); + if ((await exists(path))) { + found = true; + break; + } + } + if (found) return path; + else { + throw new Error(`${file}.${files[ext].join("/")} does not exist`); + } +} +/** Replacement of dynamic import default */ +export async function importDefault( + importPath: string, + options: ImportOptions = {}, + cache: Record = {}, +): Promise { + const mod = await import_<{ default: T }>(importPath, options, cache); + return mod.default; +} +/** Replacement of dynamic import, enable cache by default, support reload options */ +export async function import_( + importPath: string, + options: ImportOptions = {}, + cache: Record = {}, +): Promise { + let finalImportPath = importPath; + if (finalImportPath.startsWith("/") || finalImportPath.substr(1, 1) === ":") { + finalImportPath = `file://${finalImportPath}`; + } + if (!options.reload) { + if (cache[finalImportPath]) { + return cache[finalImportPath] as T; + } + } + let versionQuery = ""; + if (options.reload) { + versionQuery = `?version=${Math.random().toString().slice(2)}${ + extname(importPath) + }`; + } + + const mod = await import(`${finalImportPath}${versionQuery}`); + + cache[finalImportPath] = mod; + return mod; +} diff --git a/src/common/file_test.ts b/src/common/file_test.ts new file mode 100644 index 0000000..fd8ae0c --- /dev/null +++ b/src/common/file_test.ts @@ -0,0 +1,177 @@ +import { importDefault, validPath } from "trailmix/common/file.ts"; +import type { FileExtension, ImportOptions } from "trailmix/common/file.d.ts"; +import { resetTable, testFunction } from "trailmix/common/table.ts"; +import { resolve } from "trailmix/deps.ts"; + +let table = resetTable(); + +const tests: Record< + string, + Record< + "i" | "o", + | string + | unknown + | Record + > +> = { + validPath: { + i: { + file: "testConfig", + ext: "ts", + dir: ".", + }, + o: resolve(Deno.cwd(), "testConfig.ts"), + }, + file: { + i: { + importPath: resolve(Deno.cwd(), "testConfig.ts"), + options: {}, + cache: {}, + }, + o: { consoleFormat: "json" }, + }, + cache: { + i: { + importPath: resolve(Deno.cwd(), "testConfig.ts"), + options: { reload: false }, + cache: { + [resolve(Deno.cwd(), "testConfig.ts")]: resolve( + Deno.cwd(), + "testConfig.ts", + ), + }, + }, + o: { consoleFormat: "json" }, + }, + nofile: { + i: { + importPath: resolve(Deno.cwd(), "Error.ts"), + options: {}, + cache: {}, + }, + o: TypeError.name, + }, + // number: { + // i: [1, 1, 2], + // o: [1, 2], + // }, + // boolean: { + // i: [true, true, false], + // o: [true, false], + // }, + // array: { + // i: [ + // ["1", 1, true], + // ["1", 1, true], + // ["2", 2, false], + // ], + // o: [ + // ["1", 1, true], + // ["2", 2, false], + // ], + // }, + // object: { + // i: [{ test: "test1" }, { test: "test1" }, { test: "test2" }], + // o: [{ test: "test1" }, { test: "test2" }], + // }, + // undefined: { + // i: [undefined, undefined, 1], + // o: [undefined, 1], + // }, +}; +async function writeFile() { + return await Deno.writeFile( + Deno.cwd() + "/testConfig.ts", + new TextEncoder().encode('export default {consoleFormat: "json"};'), + ); +} +Deno.test({ + name: "File.ts", + fn: async () => { + await writeFile().then(async (v) => { + await testFunction( + "validPath", + table, + async ( + i = tests.validPath.i as Record, + ) => { + return await validPath( + i.file as string, + i.ext as FileExtension, + i.dir as string, + ); + }, + tests.validPath.o, + ); + table.render(); + table = resetTable(); + }); + }, +}); +Deno.test({ + name: "File.ts", + fn: async () => { + await writeFile().then(async (v) => { + await testFunction( + "importDefault - file", + table, + async ( + i = tests.file.i as Record, + ) => { + return await importDefault( + i.importPath as string, + i.options as ImportOptions, + i.cache as Record, + ); + }, + tests.file.o, + ); + table.render(); + table = resetTable(); + }); + }, +}); +Deno.test({ + name: "File.ts", + fn: async () => { + await writeFile().then(async (v) => { + await testFunction( + "importDefault - cache", + table, + async ( + i = tests.cache.i as Record, + ) => { + return await importDefault( + i.importPath as string, + i.options as ImportOptions, + i.cache as Record, + ); + }, + tests.cache.o, + ); + table.render(); + table = resetTable(); + }); + }, +}); +Deno.test({ + name: "File.ts", + fn: async () => { + await testFunction( + "importDefault - nofile", + table, + ( + i = tests.nofile.i as Record, + ) => { + return importDefault( + i.importPath as string, + i.options as ImportOptions, + i.cache as Record, + ); + }, + tests.nofile.o, + ); + table.render(); + table = resetTable(); + }, +}); diff --git a/src/common/mod.ts b/src/common/mod.ts new file mode 100644 index 0000000..984fd78 --- /dev/null +++ b/src/common/mod.ts @@ -0,0 +1,8 @@ +export { unique } from "trailmix/common/array.ts"; + +export { importDefault, validPath } from "trailmix/common/file.ts"; + +// @deno-types="./file.d.ts" +export type { FileExtension, ImportOptions } from "trailmix/common/file.d.ts"; + +export { resetTable, testFunction } from "trailmix/common/table.ts"; diff --git a/src/common/table.d.ts b/src/common/table.d.ts new file mode 100644 index 0000000..b50ba96 --- /dev/null +++ b/src/common/table.d.ts @@ -0,0 +1,24 @@ +import type { Table } from "trailmix/deps.ts"; +export type { Table }; +export type { Cell, Row } from "cliffy/table"; +import type { ITableOptions } from "trailmix/deps.ts"; + +export interface Result { + testName: string; + table: Table; + actual?: any | any[]; + expected?: any | any[]; + e?: string; +} +export type TableConfig = ITableOptions & Record<"table", Table>; + +export type TestType = "unimplemented" | "success" | "failure"; +export type FailureResult = Required; +export type UnimplementedResult = Required>; +export type SuccessResult = Required>; + +export type TestExpectedFunction = + | ((...any: Result | any[] | any) => any) + | any[] + | any; +export type TestActualFunction = ((...any: any[] | any) => any) | any[] | any; diff --git a/src/common/table.ts b/src/common/table.ts new file mode 100644 index 0000000..f96b689 --- /dev/null +++ b/src/common/table.ts @@ -0,0 +1,157 @@ +// import {} from '/config/mod.ts'; +import { + assertEquals, + Cell, + Row, + Table, + unimplemented, +} from "trailmix/deps.ts"; +import { s_p, s_s, t_e } from "trailmix/common/enum.ts"; +import type { + FailureResult, + Result, + SuccessResult, + TableConfig, + TestActualFunction, + TestExpectedFunction, + TestType, + UnimplementedResult, +} from "trailmix/common/table.d.ts"; + +function cell(s: string, colSpan?: number) { + let cell = Cell.from(String(s)); + cell = colSpan !== undefined ? cell.colSpan(colSpan) : cell; + return cell; +} +function row(c: Cell[], border?: boolean) { + let row = Row.from(c); + row = border !== undefined ? row.border(border) : row; + return row; +} +export function resetTable( + config?: TableConfig, +): Table { + const t: Table = Table.from(config?.table ?? []); + if (config?.maxColWidth !== undefined) t.maxColWidth(config?.maxColWidth); + if (config?.minColWidth !== undefined) t.minColWidth(config?.minColWidth); + return t.border(true).padding(1).indent(2); +} +function testTitle(type: TestType, testName: string) { + const e: "br" | "by" | "bg" = type === "success" + ? "bg" + : type === "failure" + ? "br" + : "by"; + return t_e[e] + "\t" + s_p.B + s_p.U + s_p[e] + testName.trim() + s_s[e] + + s_s.U + s_s.B + " " + type; +} +function testUnimplemented({ table, testName }: UnimplementedResult) { + table.push(...buildTestResult("unimplemented", { testName: testName })); +} +function testSuccess({ table, testName, actual, expected }: SuccessResult) { + table.push( + ...buildTestResult("success", { + testName: testName, + actual: actual, + expected: expected, + }), + ); +} +function testFailure({ table, testName, actual, expected, e }: FailureResult) { + table.push( + ...buildTestResult("failure", { + testName: testName, + actual: actual, + expected: expected, + e: e, + }), + ); + // throw new AssertionError(`Test failure: ${testName}\n${e}`); +} +function buildTestResult( + type: TestType, + { testName, actual, expected, e }: Omit, +): Table { + const eq = type === "failure" ? "!==" : "==="; + const eqCell = cell(eq, 3); + const ret = [row([cell(testTitle(type, testName), 5)], false)] as Table; + if (type === "unimplemented") return ret; + if (type === "failure" && e !== undefined) ret.push(row([cell(e, 5)], false)); + ret.push( + row([cell(JSON.stringify(actual)), eqCell, cell(JSON.stringify(expected))]), + ); + // console.log(actual.split("")); + // console.log(actual); + // console.log(p(actual)); + if ( + typeof actual === "string" && typeof expected === "string" && + ['"', actual.split(""), '"'] !== p(actual) && + ['"', expected.split(""), '"'] !== p(expected) + ) { + ret.push(row([cell(p(actual)), eqCell, cell(p(expected))])); + } + return ret; +} +function p(s: string) { + return JSON.parse(JSON.stringify(s)); +} + +// eslint-disable-next-line max-params +export async function testFunction( + testName: string, + table: Table, + actual: TestActualFunction, + expected: TestExpectedFunction, + implemented = true, +) { + let result: Result = { + table: table, + testName: testName, + }; + if (!implemented) { + unimplemented(`Function type ${testName} not implemented`); + } + try { + if (typeof actual === "function") result.actual = await actual(); + else result.actual = actual; + } catch (e) { + if (typeof e === "object") { + result.e = String(e.stack); + if (result.e.includes("not implemented")) { + testUnimplemented(result as UnimplementedResult); + } else if (result.e.split(":")[0].includes("AssertionError")) { + testFailure(result as FailureResult); + resetTable({ table, maxColWidth: 300, minColWidth: 50 }).render(); + throw e; + } else if (result.e.split(":")[0].includes("Error")) { + result.actual = result.e.split(":")[0]; + } else testFailure(result as FailureResult); + } + } finally { + if (typeof expected === "function") { + result.expected = await expected(result.actual); + } else { + result.expected = expected; + } + defaultTestCase(result); + } + testSuccess(result as SuccessResult); +} +// function defaultErrorTestCase +function defaultTestCase({ actual, expected, testName }: Result) { + assertEquals( + JSON.stringify(actual), + JSON.stringify(expected), + `${testName} failure: (actual !== expected)`, + ); + if ( + typeof actual === "string" && actual !== p(actual) && + expected !== p(expected) + ) { + assertEquals( + p(actual), + p(expected), + `${testName} JSON.parse() messages failure: (actual !== expected)`, + ); + } +} diff --git a/src/config/Config.d.ts b/src/config/Config.d.ts new file mode 100644 index 0000000..affa471 --- /dev/null +++ b/src/config/Config.d.ts @@ -0,0 +1,15 @@ +export type Environment = Record; +export type CommandOptions = Record< + string, + string | boolean | number | undefined +>; +export interface ConfigOptions { + namespace?: string; + prefix?: string; + env?: Record; +} +export type ConfigNames = + | "Config" + | "ObjectConfig" + | "EnvConfig" + | "StringConfig"; diff --git a/src/config/Config.ts b/src/config/Config.ts new file mode 100644 index 0000000..17402ca --- /dev/null +++ b/src/config/Config.ts @@ -0,0 +1,100 @@ +import { importDefault, validPath } from "trailmix/common/mod.ts"; +import type { FileExtension } from "trailmix/common/mod.ts"; + +import type { ConfigOptions } from "trailmix/config/Config.d.ts"; +import type { LogConfigMap } from "trailmix/log/mod.ts"; +export default class Config { + // should suck in a namespace and optional config file + public static env: Record = {}; + public static log: LogConfigMap = Config.parseLog(); + public env: Record = Config.env; + public log: LogConfigMap = Config.log; + // public get log(): LogConfigMap { + // return this._log; + // } + // public _log: LogConfigMap = Config.log; + // public get test(): LogConfigMap { + // return Config.log; + // } + public static namespace = "DEFAULT"; + public static prefix = "trailmix.config"; + public namespace = Config.namespace; + public path = ""; + public prefix = Config.namespace; + private _importCache: Record = {}; + public constructor( + { + namespace = Config.namespace, + prefix = Config.prefix, + env = Config.env, + }: ConfigOptions, + ) { + this.namespace = namespace; + this.prefix = prefix; + this.env = env; + this.log = this.parseLog(); + // read srcDir from env vars here? + // this.getConfigurationPath(prefix) + // suck up file to understand env config + // spit out understanding of config + // ingest remaining config (env vars, cmd, file config) + } + public async init() { + await this.getConfigurationPath(); + await this.getConfiguration(); + return this; + } + public async getConfigurationPath( + file = this.prefix, + ext: FileExtension = "ts", + srcDir = ".", + ) { + try { + this.path = await validPath(file, ext, srcDir) ?? ""; + return this.path; + } catch (e) { + throw new Error(e); + } + } + public async getConfiguration(path = this.path) { + try { + this.env = await importDefault(path, { + reload: true, + }, this._importCache); + return this.env; + } catch (e) { + throw new Error(e); + } + } + // import { parse } from "https://raw.githubusercontent.com/hashicorp/terraform-cdk/main/packages/%40cdktf/hcl2json/lib/index.ts"; + // public async getConfiguration() { + // const cfg = await Deno.readTextFile(this.path); + // // TODO: for HCL support this will need to be converted to use deno std libs + // // https://github.com/hashicorp/terraform-cdk/tree/main/packages/%40cdktf/hcl2json/lib + // const hcl = await parse( + // "trailmix.config.hcl", + // await Deno.readTextFile("trailmix.config.hcl"), + // ); + // console.log(cfg); + // } + public static parseLog(): LogConfigMap { + return { + console: { + level: "ERROR", + format: "string", + color: true, + date: true, + }, + file: { + level: "ERROR", + format: "string", + path: ".", + date: false, + }, + }; + } + public parseLog(): LogConfigMap { + this.log = Config.parseLog(); + return this.log; + } +} diff --git a/src/config/Config_test.ts b/src/config/Config_test.ts new file mode 100644 index 0000000..d4a7724 --- /dev/null +++ b/src/config/Config_test.ts @@ -0,0 +1,396 @@ +import { + Config, + ConfigNames, + ConfigOptions, + EnvConfig, + ObjectConfig, + StringConfig, +} from "trailmix/config/mod.ts"; +import { resetTable, testFunction } from "trailmix/common/mod.ts"; +import type { LogConfigMap } from "trailmix/log/Log.d.ts"; +import { assertEquals } from "trailmix/deps.ts"; +let table = resetTable(); + +const testVars = { + strParse: { + TEST: { + testWord: { + TestPhrase: { + A: { + B: "hello", + }, + }, + }, + }, + }, + stringConfig: { + env1: { + test1: "hello", + }, + env2: { + test2: { + testword: { testphrase: { testname: { test: "hello" } } }, + }, + }, + env3: { test3: { testword: { testphrase: { a: { b: "hello" } } } } }, + }, + env: { + test1: "val1", + test2: "true", + test3: JSON.stringify(["val1", "val2"]), + test4: { + a: { + b: "Hello", + }, + }, + test5: { + testword: { + testphrase: { + a: { + b: "hello", + }, + }, + }, + }, + console: { + level: "DEBUG", + }, + }, + log: { + console: { + level: "ERROR", + format: "string", + color: true, + date: true, + }, + file: { + level: "ERROR", + format: "string", + path: ".", + date: false, + }, + }, + config: { + namespace: "TRAILMIX", // prefixed to all env vars + vars: { + consoleLevel: { + command: "base", + global: true, + description: "Explicitly set console log level", + // object will be created as log.console.level + env: "LOG_CONSOLE_LEVEL", // namespace+ENV == TRAILMIX_LOG_CONSOLE_LEVEL + }, + }, + }, + namespace: "DEFAULT", + prefix: "trailmix.config", + _definitionPathRegexp: new RegExp( + /\S*(\/|\\)+(trailmix.config.(ts|tsx){1}){1}/, + ), +}; + +const testObjs = { + Config: "Config", + ObjectConfig: "ObjectConfig", + EnvConfig: "EnvConfig", + StringConfig: "StringConfig", +}; +// const testObjs: Record = { +// Config: Config, +// ObjectConfig: ObjectConfig, +// EnvConfig: EnvConfig, +// StringConfig: StringConfig, +// }; +function objFactory(type: ConfigNames = "Config", opts: ConfigOptions = {}) { + if (type === "ObjectConfig") return new ObjectConfig(opts); + if (type === "EnvConfig") return new EnvConfig(opts); + if (type === "StringConfig") return new StringConfig(opts); + else return new Config(opts); +} +function objFactoryStatic( + type: ConfigNames = "Config", +) { + if (type === "ObjectConfig") return ObjectConfig; + if (type === "EnvConfig") return EnvConfig; + if (type === "StringConfig") return StringConfig; + else return Config; +} +for (let obj of Object.keys(testObjs) as ConfigNames[]) { + // const o = testObjs[obj]; + Deno.test({ + name: `Config.ts - ${obj} default namespace`, + fn: () => { + const cfg = objFactory(obj); + assertEquals( + cfg.namespace, + testVars.namespace, + "Config.namespace is not the default namespace of " + + testVars.namespace, + ); + }, + }); + const namespace = "TRAILMIX"; + Deno.test({ + name: `Config.ts - ${obj} named namespace`, + fn: () => { + const cfg = objFactory(obj, { namespace }); + assertEquals( + cfg.namespace, + namespace, + "Config.namespace is not the named namespace of " + namespace, + ); + }, + }); + Deno.test({ + name: `Config.ts - ${obj} default prefix`, + fn: () => { + const cfg = objFactory(obj, { namespace }); + assertEquals( + cfg, + { + ...cfg, + ...{ prefix: testVars.prefix }, + }, + "Config._definitionPrefix is not the default prefix of " + + testVars.prefix, + ); + }, + }); + const prefix = "trilom.config"; + Deno.test({ + name: `Config.ts - ${obj} named prefix`, + fn: () => { + const cfg = objFactory(obj, { namespace, prefix }); + assertEquals( + cfg, + { + ...cfg, + ...{ prefix: prefix }, + }, + `Config.prefix:${ + JSON.stringify(cfg, null, 2) + } is not the named prefix of ` + + prefix, + ); + }, + }); + // Deno.test({ + // name: `Config.ts - ${obj} configuration path`, + // fn: async () => { + // const cfg = objFactory(obj, { namespace }); + // const path = await cfg.getConfigurationPath(); + // assertMatch( + // path, + // testVars._definitionPathRegexp, + // "default Config._definition_path is not resolvable, or doesn't exist at " + + // "./trailmix.config.ts", + // ); + // }, + // }); + // const definitionPathRegexp = new RegExp( + // /\S*(\/|\\)+(trilom.config.(ts|tsx){1}){1}/, + // ); + // Deno.test({ + // name: `Config.ts - ${obj} configuration path`, + // fn: async () => { + // const cfg = objFactory(obj, { namespace }); + // const path = await cfg.getConfigurationPath(prefix); + // assertMatch( + // path, + // definitionPathRegexp, + // "named Config._definition_path is not resolvable, or doesn't exist at ./" + + // prefix, + // ); + // }, + // }); + // Deno.test({ + // name: `Config.ts - ${obj} throw error for missing configuration`, + // fn: async () => { + // const cfg = objFactory(obj, { namespace }); + // await assertThrows( + // () => cfg.getConfigurationPath("nope.config"), + // Error, + // ); + // }, + // }); + Deno.test({ + name: "Config.ts", + fn: async () => { + const cfg = objFactory(obj, { namespace }); + await testFunction( + `${obj} throw error for missing configuration`, + table, + (i = "nope.config") => { + return cfg.getConfigurationPath(i); + }, + Error.name, + ); + table.render(); + table = resetTable(); + }, + }); + Deno.test({ + name: `Config.ts - ${obj}.log is the correct default`, + fn: () => { + const log: LogConfigMap = objFactoryStatic(obj).log; + assertEquals( + log, + testVars.log, + "Config.log is not the correct default of " + + testVars.log, + ); + }, + }); + Deno.test({ + name: `Config.ts - ${obj}.parseLog() returns default log`, + fn: () => { + Deno.env.delete("DEFAULT_CONSOLE_LEVEL"); + const log: LogConfigMap = objFactoryStatic(obj).parseLog(); + assertEquals( + log, + testVars.log, + `Config.parseLog(): ${ + JSON.stringify(log, null, 2) + } is not the correct default of ` + + JSON.stringify(testVars.log, null, 2), + ); + }, + }); + // Deno.test({ + // name: `Config.ts - ${obj}.getConfiguration() to ingest cmd config`, + // fn: async () => { + // const cfg = await objFactory(obj, { namespace }).getConfigurationPath(); + // const config = await cfg.getConfiguration(); + // console.log(config); + // assertEquals( + // config, + // testVars.config, + // "Config.getConfiguration() cannot ingest command config" + + // config, + // ); + // }, + // }); + if (obj === "EnvConfig") { + Deno.test({ + name: `Config.ts - ${obj}.parseEnv() returns env`, + fn: () => { + // pass string + Deno.env.set("DEFAULT_TEST1", "val1"); + // pass boolean true + Deno.env.set( + "DEFAULT_TEST2", + (String(true) === "true" ? "true" : "false"), + ); + // pass list + Deno.env.set( + "DEFAULT_TEST3", + JSON.stringify(["val1", "val2"]), + ); + Deno.env.set( + "DEFAULT_TEST4_A_B", + "Hello", + ); + Deno.env.set( + "DEFAULT_TEST5_testWord_TestPhrase_A_B", + "hello", + ); + Deno.env.set( + "DEFAULT_CONSOLE_LEVEL", + "DEBUG", + ); + const env: Record = EnvConfig.parseEnv(); + assertEquals( + env, + testVars.env, + `Config.parseEnv(): ${ + JSON.stringify(env, null, 2) + } is not the correct default of ` + + JSON.stringify(testVars.env, null, 2), + ); + }, + }); + Deno.test({ + name: `Config.ts - ${obj}.strParse() doesn't change key case`, + fn: () => { + const env: Record = EnvConfig.strParse( + "DEFAULT_TEST_testWord_TestPhrase_A_B", + "hello", + "DEFAULT", + "_", + false, + ); + assertEquals( + env, + testVars.strParse, + `Config.parseEnv(): ${ + JSON.stringify(env, null, 2) + } is not the correct default of ` + + JSON.stringify(testVars.strParse, null, 2), + ); + }, + }); + Deno.test({ + name: `Config.ts - ${obj}.parseLog() merges env log config`, + fn: () => { + Deno.env.set("DEFAULT_CONSOLE_LEVEL", "DEBUG"); + const ex = { + ...testVars.log, + ...{ console: { ...testVars.log.console, ...{ level: "DEBUG" } } }, + }; + const log: LogConfigMap = EnvConfig.parseLog(); + assertEquals( + log, + ex, + `Config.parseEnv(): ${ + JSON.stringify(log, null, 2) + } is not the correct default of ` + + JSON.stringify(ex, null, 2), + ); + }, + }); + } + if (obj === "StringConfig") { + Deno.test({ + name: `Config.ts - ${obj}.parseEnv() returns env`, + fn: () => { + const test = { + test1: "val1", + test2: (String(true) === "true" ? "true" : "false"), + test3: JSON.stringify(["val1", "val2"]), + test4AB: "Hello", + test5TestwordTestphraseAB: "hello", + consoleLevel: "DEBUG", + }; + const env: Record = StringConfig.parseEnv(test); + assertEquals( + env, + testVars.env, + `Config.parseEnv(): ${ + JSON.stringify(env, null, 2) + } is not the correct default of ` + + JSON.stringify(testVars.env, null, 2), + ); + }, + }); + Deno.test({ + name: `Config.ts - ${obj}.parseLog() merges env log config`, + fn: () => { + const ex = { + ...testVars.log, + ...{ console: { ...testVars.log.console, ...{ level: "DEBUG" } } }, + }; + const log: LogConfigMap = StringConfig.parseLog({ + consoleLevel: "DEBUG", + }); + assertEquals( + log, + ex, + `Config.parseEnv(): ${ + JSON.stringify(log, null, 2) + } is not the correct default of ` + + JSON.stringify(ex, null, 2), + ); + }, + }); + } +} diff --git a/src/config/EnvConfig.ts b/src/config/EnvConfig.ts new file mode 100644 index 0000000..88b4bbe --- /dev/null +++ b/src/config/EnvConfig.ts @@ -0,0 +1,91 @@ +import { default as Config } from "trailmix/config/Config.ts"; +import type { default as StringConfig } from "trailmix/config/StringConfig.ts"; +import { ConfigOptions } from "trailmix/config/Config.d.ts"; +import type { + ConsoleLogConfig, + FileLogConfig, + LogConfigMap, +} from "trailmix/log/mod.ts"; + +export default class EnvConfig extends Config { + public static log: LogConfigMap = EnvConfig.parseLog(); + public static env: Record = EnvConfig.parseEnv(); + public constructor(opts?: ConfigOptions | Config | StringConfig) { + let _opts = opts ?? { namespace: Config.namespace, prefix: Config.prefix }; + super(_opts); + } + /** + * turn a string{str}(TEST_ABC_A_B_C) into an object excluding a string{ex}(TEST) + * while carrying a final string{value}(hello) with a string deliminator{delim}(_) + * @param str string parse + * @param value value of key + * @param ex string to exclude + * @param delim delimiter string + * @returns {Record} Usually string=> string, can be string=> Record + */ + public static strParse( + str: string, + value: string, + ex: string, + delim = "_", + lower = true, + ): Record> { + const strReplace = str.replace(ex + delim, ""); + const nextI = strReplace.indexOf(delim, 0); + const nextV = nextI === -1 ? value : EnvConfig.strParse( + strReplace, + value, + strReplace.slice(0, nextI), + delim, + lower, + ); + const nextK = nextI === -1 ? strReplace : strReplace.slice(0, nextI); + return Object.fromEntries([[ + lower ? nextK.toLowerCase() : nextK, + nextV, + ]]); + } + /** + * pass in env, return vars within object namespace + * @param env environment env object + * @param namespace namespace of env + * @returns + */ + public static parseEnv( + namespace = this.namespace, + env: Record = Deno.env.toObject(), + ): Record { + return Object.fromEntries( + Object.keys(env).filter((key: string) => + (new RegExp(`^(${namespace}){1}`)).test(key) + ).flatMap((key: string) => { + return Object.entries( + EnvConfig.strParse(key, Deno.env.toObject()[key], namespace), + ); + }), + ); + } + public static parseLog(namespace = this.namespace): LogConfigMap { + return { + console: { + ...Config.parseLog().console, + ...EnvConfig.parseEnv(namespace).console as ConsoleLogConfig, + }, + file: { + ...Config.parseLog().file, + ...EnvConfig.parseEnv(namespace).file as FileLogConfig, + }, + } as LogConfigMap; + } + public parseEnv( + namespace = this.namespace, + env: Record = {}, + ): Record { + this.env = EnvConfig.parseEnv(namespace, env); + return this.env; + } + public parseLog(namespace = this.namespace): LogConfigMap { + this.log = EnvConfig.parseLog(namespace); + return this.log; + } +} diff --git a/src/config/ObjectConfig.ts b/src/config/ObjectConfig.ts new file mode 100644 index 0000000..fb1024a --- /dev/null +++ b/src/config/ObjectConfig.ts @@ -0,0 +1,24 @@ +// subclass to ingest object config format +// export default { +// log: { +// console: { +// level: 'ERROR', +// format: 'string', +// color: true, +// }, +// file:{ +// level: 'ERROR', +// format: 'json', +// path: '.' +// } +// } + +import { default as Config } from "trailmix/config/Config.ts"; +import { ConfigOptions } from "trailmix/config/Config.d.ts"; + +// } +export default class ObjectConfig extends Config { + public constructor(opts: ConfigOptions) { + super(opts); + } +} diff --git a/src/config/StringConfig.ts b/src/config/StringConfig.ts new file mode 100644 index 0000000..4bfb1fb --- /dev/null +++ b/src/config/StringConfig.ts @@ -0,0 +1,82 @@ +import { default as Config } from "trailmix/config/Config.ts"; +import type { default as EnvConfig } from "trailmix/config/EnvConfig.ts"; +import { ConfigOptions } from "trailmix/config/Config.d.ts"; +import type { + ConsoleLogConfig, + FileLogConfig, + LogConfigMap, +} from "trailmix/log/mod.ts"; + +export default class StringConfig extends Config { + public static log: LogConfigMap = StringConfig.parseLog(); + public static env: Record = StringConfig.parseEnv(); + public constructor(opts?: ConfigOptions | Config | EnvConfig) { + let _opts = opts ?? { namespace: Config.namespace, prefix: Config.prefix }; + super(_opts); + } + /** + * turn a string{str}(test5TestwordTestphraseTestnameTest) into an object based on capital letters + * while carrying a final string{value}(hello) with a string deliminator{delim}(_) + * @param str string parse + * @param value value of key + * @returns {Record} Usually string=> string, can be string=> Record + */ + public static strParse( + str: string, + value: unknown, + ): Record> { + // init is the starting value for finding strings later + let nextI = 0; + // for each letter in string find first capital letter + for (const letter of str.split("")) { + if (letter !== letter.toUpperCase()) { + nextI += 1; + } else break; + } + // if nextI is number or 0, add one to nextI + if (nextI === 0 || Number(str[nextI])) nextI += 1; + const nextV = nextI === str.length ? value : StringConfig.strParse( + str.slice(nextI, nextI + 1).toLowerCase() + + str.slice(nextI + 1), + value, + ); + const nextK = nextI === str.length ? str : str.slice(0, nextI); + return Object.fromEntries([[ + nextK, + nextV as string, + ]]); + } + public static parseEnv( + env: Record = {}, + ): Record { + return Object.fromEntries( + Object.keys(env).flatMap((key: string) => { + return Object.entries( + StringConfig.strParse(key, env[key]), + ); + }), + ); + } + public static parseLog(env: Record = {}): LogConfigMap { + return { + console: { + ...Config.parseLog().console, + ...StringConfig.parseEnv(env).console as ConsoleLogConfig, + }, + file: { + ...Config.parseLog().file, + ...StringConfig.parseEnv(env).file as FileLogConfig, + }, + } as LogConfigMap; + } + public parseEnv( + env: Record = this.env, + ): Record { + this.env = StringConfig.parseEnv(env); + return this.env; + } + public parseLog(): LogConfigMap { + this.log = StringConfig.parseLog(this.env); + return this.log; + } +} diff --git a/src/config/mod.ts b/src/config/mod.ts new file mode 100644 index 0000000..c9ee242 --- /dev/null +++ b/src/config/mod.ts @@ -0,0 +1,12 @@ +export { default as Config } from "trailmix/config/Config.ts"; +export { default as EnvConfig } from "trailmix/config/EnvConfig.ts"; +export { default as StringConfig } from "trailmix/config/StringConfig.ts"; +export { default as ObjectConfig } from "trailmix/config/ObjectConfig.ts"; + +// @deno-types="./Config.d.ts" +export type { + CommandOptions, + ConfigNames, + ConfigOptions, + Environment, +} from "trailmix/config/Config.d.ts"; diff --git a/src/deps.ts b/src/deps.ts new file mode 100644 index 0000000..e259a67 --- /dev/null +++ b/src/deps.ts @@ -0,0 +1,36 @@ +// watcher deps +// export { bytesToUuid } from "uuid/_common.ts"; +export { v4 } from "uuid/mod.ts"; +export { extname, relative, resolve } from "path/mod.ts"; +export { exists, existsSync } from "fs/mod.ts"; + +// color deps +export * as colors from "fmt/colors.ts"; + +// logger deps +export { + getLogger, + handlers as stdHandlers, + Logger as stdLogger, + LoggerConfig as stdLoggerConfig, + setup as setupLogger, +} from "log/mod.ts"; +export type { BaseHandler, FileHandler } from "log/handlers.ts"; +export type { LogConfig as stdLogConfig } from "log/mod.ts"; +export { getLevelByName, LogLevels } from "log/levels.ts"; +export { LogRecord } from "log/logger.ts"; + +// test deps +export { + assertEquals, + AssertionError, + assertMatch, + assertNotEquals, + assertObjectMatch, + assertStrictEquals, + assertThrows, + assertThrowsAsync, + unimplemented, +} from "testing/asserts.ts"; +export { Cell, Row, Table } from "cliffy/table"; +export type { ICell, IRow, ITableOptions } from "cliffy/table"; diff --git a/src/log/Log.d.ts b/src/log/Log.d.ts new file mode 100644 index 0000000..23760b8 --- /dev/null +++ b/src/log/Log.d.ts @@ -0,0 +1,40 @@ +import type { BaseHandler, FileHandler, LogLevels } from "trailmix/deps.ts"; +import type { + EnumBgColor, + EnumColor, + EnumEmphasis, +} from "trailmix/color/mod.ts"; +export type Handler = BaseHandler | FileHandler; +export type LogColor = Record< + LogLevel, + keyof typeof EnumColor | keyof typeof EnumBgColor +>; +export type LogStyle = Record; +export type LogLevel = keyof typeof LogLevels; +// export type Loggers = 'default' | 'test' | string; +export type LogFormat = "json" | "function" | "string"; +export type LogHandler = "console" | "file"; +// export type { LogConfigMap, LogConfig } from '/config/mod.ts'; +export type { Style } from "trailmix/color/mod.ts"; +export type { + BaseHandler, + FileHandler, + stdLogConfig, + stdLogger, + stdLoggerConfig, +} from "trailmix/deps.ts"; +export interface LogConfig { + level: LogLevel; + format: LogFormat; + path?: string; + color?: boolean; + date?: boolean; +} + +export type ConsoleLogConfig = Omit; +export type FileLogConfig = Omit; +export type LogConfigType = ConsoleLogConfig | FileLogConfig; +export interface LogConfigMap { + console: ConsoleLogConfig; + file?: FileLogConfig; +} diff --git a/src/log/Log.ts b/src/log/Log.ts new file mode 100644 index 0000000..551dc4a --- /dev/null +++ b/src/log/Log.ts @@ -0,0 +1,338 @@ +import type { + Handler, + LogColor, + LogConfig, + LogConfigMap, + LogFormat, + LogHandler, + LogLevel, + LogStyle, +} from "trailmix/log/Log.d.ts"; +import { logColors, loggerNames, logStyles } from "trailmix/log/enum.ts"; +// import type { } from 'trailmix/config/mod.ts'; +import { Config } from "trailmix/config/mod.ts"; +import { Color as m, messageByStringSpread as sS } from "trailmix/color/mod.ts"; +import type { + stdLogConfig, + stdLogger, + stdLoggerConfig, +} from "trailmix/deps.ts"; +import { + getLogger, + LogRecord, + setupLogger, + stdHandlers, +} from "trailmix/deps.ts"; +// #region logging + +// #endregion +export function stringifyBigInt(key: string, value: any): string { + return typeof value === "bigint" ? String(value) : value; +} +export function parseMessage(value: unknown): string { + // console.log(typeof value); + if (typeof value === "string") return value; + else if ( + value === null || + typeof value === "number" || + typeof value === "bigint" || + typeof value === "boolean" || + typeof value === "undefined" || + typeof value === "symbol" + ) { + return String(value); + } else if (value instanceof Error) { + return value.stack!; + } else if (typeof value === "object") { + return JSON.stringify(value, stringifyBigInt); + } + return "undefined"; +} +/** Construct a Pagic Logger. + * @example + * // returns default logger + * const l = new Log() + * // returns Pagic logger + * const l = await new Log().init('Pagic') + * // log success _message oneliner + * (await new Log().init('Pagic')).success('main','_message') + * // log success _message with object + * const l = await new Log().init('Pagic') + * l.success('main','_message') + */ +export default class Log { + private static _loggerNames: string[] = loggerNames; // init static logger list + public name = "default"; + public logger: stdLogger = getLogger(); // set logger to default logger + // public config: PagicLogConfigMap = Log._config; + // public set config(config: LogConfig) { + // this._config = config; + // } + // public get config(): LogConfig { + // return this._config; + // } + public pConfig: LogConfigMap = Config.log; // init static log config + private _config: stdLogConfig; + private _loggerNames: string[] = Log._loggerNames; + // private handlers: { [x: string]: BaseHandler | FileHandler }; + /** Construct the default logger. + * @public + * @constructor + */ + public constructor( + name = "default", + config?: LogConfigMap, + loggerNames = Log._loggerNames, + ) { + if (config !== undefined) { + this.pConfig = config; + } + this._config = { handlers: this._handlers, loggers: this._loggers }; + this._loggerNames = loggerNames; + this.set(name); + } + public set(name = "default") { + this.name = name; + this.logger = getLogger(name); + } + /** Initialize the loggers and handlers. + * @public + * @example + * // returns Pagic logger + * const l = await new Log().init('Pagic') + */ + public async init(name = this.name): Promise { + await setupLogger(this._config); + if (this.name !== name) this.set(name); + return this; + } + /** DEBUG _message + * @public + * @example + * const l = await new Log().init('Pagic') + * l.debug('main','_message') + */ + public debug(first: unknown, ...args: unknown[]): string | string[] { + let ret = this._log(10, first, ...args); + // console.log(ret); + if (this.name === "test") { + const dedebug = this._log(0, first, ...args); + // console.log(dedebug); + if (Array.isArray(ret)) { + ret.concat(Array.isArray(dedebug) ? dedebug : [dedebug]); + } else [ret].concat(Array.isArray(dedebug) ? dedebug : [dedebug]); + } + // console.log('ret ' + ret); + return ret.length === 1 ? ret[0] : ret; + } + /** INFO _message + * @public + * @example + * const l = await new Log().init('Pagic') + * l.info('main','_message') + */ + public info(first: unknown, ...args: unknown[]): string | string[] { + return this._log(20, first, ...args); + } + /** WARN _message + * @public + * @example + * const l = await new Log().init('Pagic') + * l.warn('main','_message') + */ + public warn(first: unknown, ...args: unknown[]): string | string[] { + return this._log(30, first, ...args); + } + /** ERROR _message + * @public + * @example + * const l = await new Log().init('Pagic') + * l.error('main','_message') + */ + public error(first: unknown, ...args: unknown[]): string | string[] { + // console.log(...args); + // console.log(args); + return this._log(40, first, ...args); + } + /** SUCCESS _message + * @public + * @example + * const l = await new Log().init('Pagic') + * l.success('main','_message') + */ + public success(first: unknown, ...args: unknown[]): string | string[] { + return this._log(50, first, ...args); + } + /** deDEBUG _message - only works in 'test' + * @private + * @example + * const l = await new Log('test').init('Pagic') + * l.debug('main','_message') + */ + private _log( + level: number, + msg: unknown, + ...args: unknown[] + ): string | string[] { + let messages: string[] = []; + let record = new LogRecord({ + level, + msg: level === 0 && this.name === "test" + ? "deDEBUG:" + parseMessage(msg) + : parseMessage(msg), + args: args, + loggerName: this.name, + }); + Object.entries(this._config.handlers ?? {}).forEach( + (logger: [string, Handler]) => { + if (level >= logger[1].level || (this.name === "test" && level === 0)) { + const _msg = logger[1].format(record); + // messages.push(_msg); + if (logger[0] === "console") { + messages.push(_msg); + console.log(_msg); + } else { + logger[1].handle(record); + } + } + // logger[1].handle(record); + // // (logger[1] as FileHandler).flush(); + // } + }, + {}, + ); + // console.log(messages); + return messages.length === 1 ? messages[0] : messages; + } + private get _loggers(): { [name: string]: stdLoggerConfig } { + const loggers = Object.fromEntries( + this._loggerNames.map((logger) => { + return [ + logger, + this._getLogger( + logger, + Object.keys(this.pConfig) as LogHandler[], + this.pConfig.console.level, + ), + ]; + }), + ); + return loggers; + } + private get _handlers(): { [name: string]: Handler } { + return Object.entries(this.pConfig).reduce((prev: any, current: any, i) => { + return { + ...(i === 0 ? {} : prev), + ...{ + [current[0]]: this._getHandler(current[0], current[1]), + }, + }; + }, {}); + } + + private _getLogger( + name = this.name, + handlers: LogHandler[] = ["console"], + level: LogLevel = "ERROR", + ): stdLoggerConfig { + return { + level: level, + handlers: handlers, + }; + } + private _getHandler( + type: LogHandler = "console", + config: LogConfig, + ): Handler { + if (type === "file") { + return new stdHandlers.FileHandler(config.level, { + mode: "w", + filename: config.path + + `/Pagic.${config.format === "json" ? "json" : "log"}`, + formatter: (logRecord: LogRecord, handler: LogConfig = config) => + this._formatter(logRecord, handler), + }); + } else { + return new stdHandlers.BaseHandler(config.level, { + formatter: (logRecord: LogRecord, handler: LogConfig = config) => { + let args = this._parseArgs(handler.format, logRecord.args); + let msg = this._message(logRecord, handler); + return msg + (args !== undefined ? args : ""); + }, + }); + } + } + private _formatter(logRecord: LogRecord, handler: LogConfig): string { + let msg = this._message(logRecord, handler); + let args = this._parseArgs(handler.format, logRecord.args); + if (handler.format === "json") { + return JSON.stringify( + { + logger: this.name, + date: logRecord.datetime, + level: handler.level, + msg: msg, + args: args, + }, + null, + 2, + ); + } else if (handler.format === "function") { + return logRecord.level + " " + msg + (args !== undefined ? args : ""); + } else { + return (handler.date ? logRecord.datetime + " " : "") + msg + + (args !== undefined ? args : ""); + } + } + private _message(logRecord: LogRecord, handler: LogConfig): string { + let msg = `[${this.name}] ${logRecord.msg}`; + // let args: string | undefined = this._parseArgs(handler.format, logRecord.args); + // console.log('logrecord.Args: ' + logRecord.args); + // console.log('after' + args); + // console.log(consoleMsg); + if ( + handler.format !== "function" && handler.color && + logRecord.levelName !== "DEBUG" + ) { + const style = logStyles[logRecord.levelName as LogLevel]; + const color = logColors[logRecord.levelName as LogLevel]; + const colored = sS(logRecord.msg, style, color); + const name = sS(this.name, style, color); + // const colored = logFunctions[logColors[logRecord.levelName as LogLevel]](logRecord.msg); + // const name = logFunctions[logColors[logRecord.levelName as LogLevel]](this.name); + if (logRecord.levelName === "CRITICAL") { + msg = `[${sS(name, "bold")}] ${sS(colored, "bold")}`; + } else { + msg = `[${name}] ${colored}`; + } + } + return msg; + } + private _parseArgs(format: LogFormat, ...args: unknown[]) { + let msg: string | undefined; + if (args !== null && args.toString() !== "") { + if (format === "function") { + args.forEach((arg, index) => { + msg += `, arg${index}: ${arg}`; + }); + } else if (format === "string") { + msg = " \nArguments:" + + JSON.stringify( + JSON.parse(JSON.stringify(args[0], stringifyBigInt))[0], + null, + 2, + ); + } else if (format === "json") { + msg = JSON.parse(JSON.stringify(args[0], stringifyBigInt))[0]; + } + } + return msg; + } +} + +// class PagicMessage {} + +// "Log.ts - Init test logger with json format" +// 'r' == 'e' +// 'r' == 'e' +// 'r' != 'e' diff --git a/src/log/Log_test.ts b/src/log/Log_test.ts new file mode 100644 index 0000000..db49cde --- /dev/null +++ b/src/log/Log_test.ts @@ -0,0 +1,353 @@ +// import { Config } from '/config/mod.ts'; +// import { Log, logLevels, loggerNames, stringifyBigInt } from '/log/mod.ts'; +// import type { LogLevel, LogConfigMap } from '/log/mod.ts'; + +// // import { Table, Row, Cell, getLevelByName, assertNotEquals, assertStrictEquals } from '/deps.ts'; + +// import { logString, strings, colorLog } from 'test/utils/mod.ts'; + +// let testCases: string[] = []; +// const ogConsole = console.log; + +// let table = resetTable(); +// function resetTable(table?: []): Table { +// return new Table().header(Row.from(['Log.ts'])).body([new Row('test', 'test', 'test')]); +// // .maxColWidth(100) +// // .border(true) +// // .padding(1) +// // .indent(2); +// } +// /** +// * test logger based on logger name and level +// * then test messages to ensure that +// * messages counts are correct per level +// * @param logger logger name string +// * @param level LogLevel object +// * @param l Log object +// */ +// // eslint-disable-next-line max-params +// function testLoggerLevels( +// logger = 'default', +// level: LogLevel = 'ERROR', +// colorMsg = true, +// l: Log, +// msg: unknown, +// ...args: unknown[] +// ) { +// let levelNum = getLevelByName(level); +// let actual = 0; +// let message: string = +// typeof msg === 'string' +// ? msg +// : msg instanceof Error +// ? msg.stack! +// : typeof msg === 'object' +// ? JSON.stringify(msg, stringifyBigInt) +// : String(msg); +// // ogConsole(messages); +// if (logger === 'test') { +// testCases = [logString(message, 'NOTSET', logger, colorMsg, ...args)]; +// actual++; +// } +// if (levelNum <= 10) { +// testCases.push(logString(message, 'DEBUG', logger, colorMsg, ...args)); +// l.debug(msg, ...args); +// actual++; +// } +// if (levelNum <= 20) { +// testCases = [logString(message, 'INFO', logger, colorMsg, ...args)]; +// l.info(msg, ...args); +// actual++; +// } +// if (levelNum <= 30) { +// testCases = [logString(message, 'WARNING', logger, colorMsg, ...args)]; +// l.warn(msg, ...args); +// actual++; +// } +// if (levelNum <= 40) { +// testCases = [logString(message, 'ERROR', logger, colorMsg, ...args)]; +// l.error(msg, ...args); +// actual++; +// } +// if (levelNum <= 50) { +// testCases = [logString(message, 'CRITICAL', logger, colorMsg, ...args)]; +// l.success(msg, ...args); +// actual++; +// } +// // divide level by 10 +// let expected = levelNum / 10; +// // subtract max(50/10)+1 from sum +// expected = 6 - expected; +// // add 1 if 'test' to sum for deDEBUG messages +// expected += logger === 'test' ? 1 : 0; +// // subtract 1 from sum if NOTSET, default is INFO +// expected -= levelNum === 0 ? 1 : 0; +// assertStrictEquals(actual, expected, `Message count failure:\t ${actual} !== ${expected}`); +// } +// /** +// * this function is meant to be used to override +// * console.log() so you can ensure it is messaging +// * the console correctly with custom colored strings +// * or bold for example +// * @param data string array of console.log messages +// */ +// function consoleMock(...data: string[]) { +// // const expected = testCases[testCases.length - 1]; +// // ogConsole(data); +// // ogConsole(testCases[testCases.length - 1]); +// // ogConsole(testCases); +// const expected = Array.isArray(testCases) ? testCases.filter((test) => test === data.join(''))[0] : testCases; +// assertNotEquals(expected, '', `Did not find matching string in [testCases]\n ${JSON.stringify(testCases)}`); +// const actual = data.join(''); +// // table.push([Cell.from(actual), Cell.from('==='), Cell.from(expected)]); +// // ogConsole(`\n${ && table.render()}`); +// assertStrictEquals( +// actual, +// expected, +// `console.log() messages failure: (actual !== expected)\n "${actual}" !== "${expected}"`, +// ); +// table.push([actual, '===', expected]); +// } + +// const messages = { +// string: ['string', `${Deno.env.get('HOME')}`, Object.keys(Deno)[0]], +// numbers: [ +// 1, +// Number.MAX_SAFE_INTEGER, // max number +// 9007199254740999007199254740990n, // bigint +// ], +// boolean: [true, false], +// undefined: [undefined], +// null: [null], +// object: [ +// new RangeError('Uh-oh!'), +// { +// test1: 'test', +// }, +// { +// test2: ['a', true, 3], +// }, +// { +// test3: { testInner: 'test' }, +// }, +// Deno.version, +// { +// deno: { ...Deno.version, ...Deno.build }, +// }, +// { +// deno: [Deno.version, Deno.build], +// }, +// { +// deno: { +// version: Deno.version, +// build: Deno.build, +// }, +// }, +// ], +// }; +// const args = [ +// ...messages.string, +// ...messages.numbers, +// ...messages.boolean, +// ...messages.undefined, +// ...messages.null, +// ...messages.object, +// messages.string, +// messages.numbers, +// messages.boolean, +// messages.undefined, +// messages.null, +// messages.object, +// [messages.string, messages.numbers, messages.boolean, messages.undefined, messages.null, messages.object], +// ]; +// /** +// * Functional tests +// */ +// console.log = consoleMock; +// Deno.test({ +// name: `Log.ts - Init default logger w/o configuration\n`, +// fn: async () => { +// // create default logger with default ERROR level +// const l: Log = new Log(); +// // CRITICAL is used for success messages +// testCases = [logString('success', 'CRITICAL'), logString('error', 'ERROR')]; +// l.success('success'); +// l.error('error'); +// }, +// }); +// Deno.test({ +// name: `Log.ts - Init default logger with level configuration\n`, +// fn: async () => { +// // set level to WARNING +// let log: LogConfigMap = new Config({ +// consoleLevel: 'WARNING', +// }).log; +// // create 'default' logger with WARNING level +// const l: Log = new Log('default', log); +// testCases = [logString('success', 'CRITICAL'), logString('error', 'ERROR'), logString('warn', 'WARNING')]; +// l.success('success'); +// l.error('error'); +// l.warn('warn'); +// }, +// }); +// Deno.test({ +// name: `Log.ts - Init test logger with INFO level configuration to use see debug with deDEBUG\n`, +// fn: async () => { +// // set level to INFO +// let log: LogConfigMap = new Config({ +// consoleLevel: 'INFO', +// }).log; +// // create 'test' logger with INFO level +// const l: Log = new Log('test', log); +// testCases = [logString('debug', 'NOTSET', 'test')]; +// // calling a DEBUG message will not yield a normal debug message +// // it will yield a deDEBUG message only in the 'test' logger +// l.debug('debug'); +// }, +// }); +// Deno.test({ +// name: `Log.ts - Init test logger with DEBUG level configuration to ensure there is no color\n`, +// fn: async () => { +// // set level to DEBUG and color to false +// let log: LogConfigMap = new Config({ +// consoleLevel: 'DEBUG', +// consoleColor: false, +// }).log; +// // create 'test' logger with DEBUG level +// const l: Log = new Log('test', log); +// testCases = [ +// logString('debug', 'NOTSET', 'test', false), +// logString('debug', 'DEBUG', 'test', false), +// logString('info', 'INFO', 'test', false), +// logString('warn', 'WARNING', 'test', false), +// logString('error', 'ERROR', 'test', false), +// logString('success', 'CRITICAL', 'test', false), +// ]; +// // calling a DEBUG message will not yield a normal debug message +// // it will yield a deDEBUG message only in the 'test' logger +// l.success('success'); +// l.error('error'); +// l.warn('warn'); +// l.info('info'); +// l.debug('debug'); +// }, +// }); +// Deno.test({ +// name: `Log.ts - Init test logger with json format \n`, +// only: true, +// fn: async () => { +// // set level to DEBUG and color to false +// let log: LogConfigMap = new Config({ +// consoleLevel: 'DEBUG', +// consoleFormat: 'json', +// }).log; +// // create 'test' logger with DEBUG level +// const l: Log = new Log('test', log); +// ogConsole(log); +// ogConsole(l); +// testCases = [ +// logString('debug', 'NOTSET', 'test'), +// logString('debug', 'DEBUG', 'test'), +// logString('info', 'INFO', 'test'), +// logString('warn', 'WARNING', 'test'), +// logString('error', 'ERROR', 'test'), +// logString('success', 'CRITICAL', 'test'), +// ]; +// // calling a DEBUG message will not yield a normal debug message +// // it will yield a deDEBUG message only in the 'test' logger +// l.success('success'); +// l.error('error'); +// l.warn('warn'); +// l.info('info'); +// l.debug('debug'); +// }, +// }); +// /** +// * Logger Tests +// * For each LogLevel, for each Logger, with or without Args +// */ +// for await (const logger of loggerNames.concat('trailmix')) { +// // table = resetTable([Cell.from(logger).colSpan(3)]); +// for await (const level of logLevels) { +// // table.push([Cell.from(level).border(true).colSpan(3)]); +// for await (const arg of [undefined]) { +// table.push([ +// Cell.from(arg ?? 'undefined') +// .border(true) +// .colSpan(3), +// ]); +// Deno.test({ +// only: true, +// sanitizeResources: false, +// sanitizeExit: false, +// sanitizeOps: false, +// name: 'Log.ts', +// // name: `Log.ts Logger test for \x1b[47m\x1b[30m${logger}${strings.ansi_reset} at level \x1b[${colorLog( +// // level as LogLevel, +// // logger, +// // )}m${level}${strings.color_suffix}${ +// // arg !== undefined ? ' with args ' + JSON.stringify(arg, stringifyBigInt) : '' +// // }\n`, +// async fn() { +// console.log = consoleMock; +// const log: LogConfigMap = new Config({ +// consoleLevel: level, +// logPath: '.', +// logLevel: level, +// }).log; +// assertStrictEquals(level, log.console.level, `Config logLevel not set: ${level} !== ${log.console.level}`); +// const l: Log = await new Log(logger, log).init(); +// assertStrictEquals( +// level, +// l.pConfig.console.level, +// `Log logLevel not set: ${level} !== ${l.pConfig.console.level}`, +// ); +// testLoggerLevels(logger, level as LogLevel, true, l, level, arg); +// testCases = []; +// }, +// }); +// } +// // ogConsole(table.render()); +// // table = resetTable(table); +// } +// } +// /** +// * Message Tests +// * For each LogLevel, for each primitive type, with or without Args +// * // uses test logger to see deDEBUG messages +// */ +// for await (const level of logLevels) { +// for await (const primitive of Object.entries(messages)) { +// for await (const arg of args) { +// for await (const value of primitive[1]) { +// Deno.test({ +// sanitizeResources: false, +// sanitizeExit: false, +// sanitizeOps: false, +// name: `Log.ts Message test primitive:value \x1b[47m\x1b[30m${primitive[0]}:${value}${ +// strings.ansi_reset +// } at level \x1b[${colorLog(level as LogLevel, 'default')}m${level}${strings.color_suffix}${ +// arg !== undefined ? ' with args ' + JSON.stringify(arg, stringifyBigInt) : '' +// }\n`, +// async fn() { +// console.log = consoleMock; +// const log: LogConfigMap = new Config({ +// consoleLevel: level, +// logPath: '.', +// logLevel: level, +// }).log; +// assertStrictEquals(level, log.console.level, `Config logLevel not set: ${level} !== ${log.console.level}`); +// const l: Log = await new Log('test', log).init(); +// assertStrictEquals( +// level, +// l.pConfig.console.level, +// `Log logLevel not set: ${level} !== ${l.pConfig.console.level}`, +// ); +// testLoggerLevels('test', level as LogLevel, true, l, value, arg); +// testCases = []; +// }, +// }); +// } +// } +// } +// } diff --git a/src/log/enum.ts b/src/log/enum.ts new file mode 100644 index 0000000..c235c60 --- /dev/null +++ b/src/log/enum.ts @@ -0,0 +1,43 @@ +import { LogLevels as EnumLogLevel } from "trailmix/deps.ts"; +export { EnumLogLevel }; +import type { LogColor, LogLevel, LogStyle } from "trailmix/log/Log.d.ts"; + +export const logLevels = Object.values(EnumLogLevel).filter((key) => + typeof key === "string" +) as LogLevel[]; +export const loggerNames = ["default", "test"]; + +// export type Styles = 'bold' | 'italic' | 'dim' | 'underline' | 'strikethrough' | 'hidden' | 'inverse' | 'clear'; +export const logColors: LogColor = { + NOTSET: "white", + DEBUG: "clear", + INFO: "blue", + WARNING: "yellow", + ERROR: "red", + CRITICAL: "green", +}; +export const logStyles: LogStyle = { + NOTSET: "clear", + DEBUG: "clear", + INFO: "clear", + WARNING: "clear", + ERROR: "clear", + CRITICAL: "bold", +}; + +export enum EnumLogStyle { + NOTSET = "clear", + DEBUG = "clear", + INFO = "clear", + WARNING = "clear", + ERROR = "clear", + CRITICAL = "bold", +} +export enum EnumLogColors { + NOTSET = "white", + DEBUG = "clear", + INFO = "blue", + WARNING = "yellow", + ERROR = "red", + CRITICAL = "green", +} diff --git a/src/log/mod.ts b/src/log/mod.ts new file mode 100644 index 0000000..b596003 --- /dev/null +++ b/src/log/mod.ts @@ -0,0 +1,18 @@ +// @deno-types="./Log.d.ts" +export type { + ConsoleLogConfig, + FileLogConfig, + LogConfig, + LogConfigMap, + LogFormat, + LogHandler, + LogLevel, +} from "trailmix/log/Log.d.ts"; +export { + EnumLogColors, + EnumLogLevel, + EnumLogStyle, + loggerNames, + logLevels, +} from "trailmix/log/enum.ts"; +export { default as Log, stringifyBigInt } from "trailmix/log/Log.ts"; diff --git a/src/watch/Watch.ts b/src/watch/Watch.ts new file mode 100644 index 0000000..bf3cfad --- /dev/null +++ b/src/watch/Watch.ts @@ -0,0 +1,45 @@ +import { resolve, v4 } from "trailmix/deps.ts"; +// import { logger, underline } from 'test/utils/mod.ts'; +export default class Watch { + // #region properties + // @ts-ignore + public watcher: AsyncIterableIterator = {}; + public watchDirs: string | string[] = ""; + public id = ""; + // #endregion + + public constructor(watchDirs: string | string[]) { + this.id = v4.generate().substring(28, 36); + // logger.success(this.id); + this.watchDirs = watchDirs; + try { + // logger.success(this.id); + this.watcher = this.watch(); + // logger.success('watcher', 'client', this.id.substring(28, 36), underline(this.watchDirs)); + } catch (e) { + if (e.name === "NotFound") { + // logger.error( + // 'watcher', + // 'client', + // this.id.substring(28, 36), + // underline(this.watchDirs), + // `<- These files were not found.`, + // ); + } else { + throw e; + } + } + } + + public watch(): AsyncIterableIterator { + // logger.success(this.id); + // logger.success('watcher', 'client', this.id.substring(28, 36), 'watching', underline(this.watchDirs)); + let ret: AsyncIterableIterator; + ret = Deno.watchFs( + Array.isArray(this.watchDirs) + ? this.watchDirs.map((dir) => resolve(dir)) + : resolve(this.watchDirs), + ); + return ret; + } +} diff --git a/src/watch/WatchFactory.ts b/src/watch/WatchFactory.ts new file mode 100644 index 0000000..283a9ac --- /dev/null +++ b/src/watch/WatchFactory.ts @@ -0,0 +1,157 @@ +import { Watch } from "trailmix/watch/mod.ts"; +import type { Config } from "trailmix/config/mod.ts"; +import { unique } from "trailmix/common/mod.ts"; +export const REGEXP_UPDIR = /^(\.\.\/){1}([a-zA-Z0-9_\\\/-])*(\/){1}/; +// checks if the directory is a hidden updir +// hidden = '/.github/' +// hidden updir = '../.github/' +export const REGEXP_HIDDEN_UPDIR = /^(\.\.\/){1}([a-zA-Z0-9_\\\/-])*(\/\.){1}/; + +import { + // colors, + existsSync, + // extname, + relative, + resolve, + v4, +} from "trailmix/deps.ts"; +export default class WatchFactory { + // #region properties + public watchers: Array = []; + private config: Partial = {}; + private pagicConfigPath = ""; + private timeoutHandler: number | undefined; + private changedPaths: string[] = []; + private srcDir = ""; + private theme = ""; + private id = ""; + // #endregion + public constructor(config: Partial = {}, pagicConfigPath: string) { + this.id = v4.generate().substring(28, 36); + this.init(config, pagicConfigPath); + } + // figures out srcDir, and theme location + // if theme is not bundled will add a watcher to theme location + public init(config: Partial = {}, pagicConfigPath: string) { + this.config = config; + // logger.info('watcher', `factory:${colors.red(this.id)}`, 'init', underline([this.srcDir, this.pagicConfigPath])); + // construct watcher and optional theme watcher if theme is not bundled + this.addWatcher([this.srcDir, this.pagicConfigPath]); + } + // add a watcher to the factory with a dir, file, or list of either. (this.watchers.push(dirs)) + // if providing a dir, you must end with '/.' for example './Pagic/.' or 'Pagic/.' + // will check if watcher exists, but doesn't know if another watcher might share the file/dir + public addWatcher(dirs: string | string[]) { + if ( + this.watchers.filter((watcher) => + watcher.watchDirs === (Array.isArray(dirs) ? dirs : [dirs]) + ).length !== 1 + ) { + // logger.info('watcher', `factory:${colors.red(this.id)}`, 'addWatcher', `${underline(dirs)}`); + this.watchers.push(new Watch(dirs)); + } + } + // remove all watchers in the factory (this.watchers.pop(all)) + public removeWatchers() { + while (this.watchers.length) { + this.watchers.pop(); + } + // logger.info('watcher', `factory:${colors.red(this.id)}`, 'removeWatchers', `finalCount:${this.watchers.length}`); + } + // call watchers that have been init'ed to watch their dirs + // pass in a callback to handle FsEvents in Pagic object. ex: "rebuild" + public async watch(callback: (status: string) => void) { + this.pagicCallback = callback; + this.watchers.forEach(async (watcher: Watch) => { + for await (const event of watcher.watcher) { + // handle the watcher event + await this.handleEvent(event, watcher); + } + }); + } + // watchers call this when an event occurs from watch + // pass in an FsEvent and a PagicWatcher to handle and event that the watcher causes + private async handleEvent(event: Deno.FsEvent, watcher: Watch) { + // get original paths length + const pathLength = this.changedPaths.length; + // set changedPaths to new paths if they don't exist + this.parseEventPaths( + event.paths.map((eventPath: string) => relative(this.srcDir, eventPath)), + ).forEach( + (path) => { + if (this.changedPaths.indexOf(path) === -1) { + this.changedPaths.push(path); + } + }, + ); + switch (event.kind) { + case "any": // not sure what 'any' case applies to + // logger.error('watcher', `${colors.red(this.id)}${colors.red(watcher.id)}`, event.kind, underline(event.paths)); + break; + case "create": // if a watched file is created, rebuild? + // logger.info(watcher.id, event.kind, underline(event.paths)); + break; + case "access": // access shouldn't be tracked afaik + break; + case "modify": // if a watched file is modified, reload + break; + case "remove": // if a watched file is removed, reload + break; + default: + // logger.error(watcher.id, 'unknown event', event.kind, underline(event.paths)); + break; + } + // if length changed, handle change + if (unique(this.changedPaths).length !== pathLength) { + this.handleFileChange(); + } + } + // use current changedPaths to call the pagicCallback to trigger a rebuild or reload + private handleFileChange() { + // this.changedPaths = unique([...this.changedPaths, ...filePaths]); + clearTimeout(this.timeoutHandler); + this.timeoutHandler = setTimeout(async () => { + // loop through changed files + for await (const changedPath of this.changedPaths) { + // resolve changed path/dir + const fullChangedPath = resolve(this.srcDir, changedPath); + if (!existsSync(fullChangedPath)) { + // changed path/dir + // logger.warn(`${changedPath} removed, start rebuild`); + this.pagicCallback("rebuild"); + break; + } else if (fullChangedPath.includes(this.pagicConfigPath)) { + // changed config file + this.pagicCallback("rebuild"); + } else if (Deno.statSync(fullChangedPath).isDirectory) { + // changed file is a directory + // logger.warn(`Directory ${colors.underline(changedPath)} changed, start rebuild`); + this.pagicCallback("rebuild"); + break; + } + } + }, 100); + } + // pass in list of paths, will output paths that pass include and exclude filters + private parseEventPaths(eventPaths: string[]): string[] { + let paths: string[] = []; + // this.config.include?.forEach((glob: any) => { + // paths = eventPaths.filter( + // (eventPath) => path.globToRegExp(glob).test(eventPath) || path.globToRegExp(`${glob}/**`).test(eventPath), + // ); + // }); + // this.config.exclude?.forEach((glob: any) => { + // paths = eventPaths.filter( + // (eventPath) => + // // if it matches exclude glob + // !path.globToRegExp(glob).test(eventPath) && + // // if prefixed with ../somedir/ then ignore glob/** test and only check if hidden dir + // ((REGEXP_UPDIR.test(eventPath) && !REGEXP_HIDDEN_UPDIR.test(eventPath)) || + // (!REGEXP_UPDIR.test(eventPath) && !path.globToRegExp(`${glob}/**`).test(eventPath))), + // ); + // }); + return paths; + } + // empty function for a callback to the Pagic object for watcher changes (rebuild/plugins) + private pagicCallback: (status: string, path?: string) => void = () => {}; +} diff --git a/src/watch/Watch_test.ts b/src/watch/Watch_test.ts new file mode 100644 index 0000000..53b7065 --- /dev/null +++ b/src/watch/Watch_test.ts @@ -0,0 +1,170 @@ +// import { assertStrictEquals, AssertionError, assertThrows } from '/deps.ts'; +// import { WatchFactory, Watch } from '/watch/mod.ts'; +// import { color, logString, colors } from 'test/utils/mod.ts'; +// let testCases: string[] | string | any = []; +// const ogConsole = console.log; +// // eslint-disable-next-line max-params +// // function color(s: string, prefix: string, underline = false, suffix: strings | string = strings.color_suffix) { +// // return `${underline ? strings.underline_prefix : ''}${Number(prefix) > 0 ? `\x1b[${prefix}m` : ''}${s}${suffix}${ +// // underline ? strings.underline_suffix : '' +// // }`; +// // } +// // enum colors { +// // clear = '0', +// // red = '31', +// // green = '32', +// // } +// const testPaths: { [key: string]: string } = { +// watcher_Found: '.', +// watcher_FoundNamed: '/etc', +// watcher_FoundRelative: '../.', +// }; +// const tests = { +// consoleMock: ['mockSuccess', 'mockFailure'], + +// watcher_NotFound: [ +// logString(`client ${color('NOT', colors.clear, true, '')} <- These files were not found.`, 'ERROR', 'Pagic'), +// ], +// ...Object.fromEntries( +// Object.entries(testPaths).map((t) => [ +// t[0], +// `${color('[Pagic]', colors.green)} ${color('watcher', colors.green)} client ${color( +// t[1], +// colors.clear, +// true, +// '', +// )}`, +// ]), +// ), +// factory_Init: [ +// `[Pagic] watcher factory init ${color('.', colors.clear, true, '')} | ${color( +// '/Users/bkillian/repos/pagic/pagic.config.tsx', +// colors.clear, +// true, +// '', +// )}`, +// // '\x1b[32m[Pagic]\x1b[39m \x1b[32mwatcher\x1b[39m client \x1b[4m.\x1b[24m | \x1b[4m/Users/bkillian/repos/testpagic/pagic.config.tsx\x1b[24m', +// `${color('[Pagic]', colors.green)} ${color('watcher', colors.green)} client ${color( +// '.', +// colors.clear, +// true, +// '', +// )} | ${color('/Users/bkillian/repos/pagic/pagic.config.tsx', colors.clear, true, '')}`, +// ], +// factory_Init_themelocal: [ +// `[Pagic] watcher factory init ${color('.', colors.clear, true, '')} | ${color( +// '/Users/bkillian/repos/pagic/pagic.config.tsx', +// colors.clear, +// true, +// '', +// )}`, +// `[Pagic] watcher factory init theme ${color('/Users/bkillian/repos/pagic-docs/.', colors.clear, true, '')}`, +// // '\x1b[32m[Pagic]\x1b[39m \x1b[32mwatcher\x1b[39m client \x1b[4m.\x1b[24m | \x1b[4m/Users/bkillian/repos/testpagic/pagic.config.tsx\x1b[24m', +// `${color('[Pagic]', colors.green)} ${color('watcher', colors.green)} client ${color( +// '.', +// colors.clear, +// true, +// '', +// )} | ${color('/Users/bkillian/repos/pagic/pagic.config.tsx', colors.clear, true, '')}`, +// `${color('[Pagic]', colors.green)} ${color('watcher', colors.green)} client ${color( +// '/Users/bkillian/repos/pagic-docs/.', +// colors.clear, +// true, +// '', +// )}`, +// ], +// }; +// function consoleMock(...data: string[]) { +// let value = Array.isArray(testCases) ? testCases.filter((test) => test === data.join(' ')).toString() : testCases; +// ogConsole(`ogConsole: ${value}`); +// if (value !== 'mockFailure') { +// assertStrictEquals(data.join(' '), value); +// } else assertStrictEquals(data.join(' '), 'NOT'); +// } + +// Object.entries(tests).forEach((test) => { +// Deno.test({ +// name: `[${test[0]}]`, +// fn: async () => { +// testCases = test[1]; +// console.log = consoleMock; +// ogConsole(`${test[0]}: testing ${testCases}`); +// let watcher: Watch | undefined | any; +// switch (test[0]) { +// case 'consoleMock': +// // console doesn't match +// assertThrows(() => console.log('mockFailure'), AssertionError); +// // console matches +// console.log('mockSuccess'); +// break; +// case 'watcher_NotFound': +// // dir not found +// watcher = new Watch('NOT'); +// break; +// case 'watcher_Found': +// // dir found +// watcher = new Watch('.'); +// break; +// case 'watcher_FoundNamed': +// // dir found +// watcher = new Watch('/etc'); +// break; +// case 'watcher_FoundRelative': +// // dir found +// watcher = new Watch('../.'); +// break; +// case 'factory_Init': +// // dir found +// watcher = new WatchFactory( +// { +// srcDir: '.', +// theme: 'docs', +// include: [], +// exclude: [], +// }, +// '/Users/bkillian/repos/pagic/pagic.config.tsx', +// ); +// break; +// case 'factory_Init_themelocal': +// watcher = new WatchFactory( +// { +// srcDir: '.', +// theme: '../pagic-docs', +// include: [], +// exclude: [], +// themelocal: true, +// }, +// '/Users/bkillian/repos/pagic/pagic.config.tsx', +// ); +// break; +// default: +// break; +// } +// testCases = []; +// console.log = ogConsole; +// watcher = undefined; +// }, +// sanitizeResources: false, +// sanitizeOps: false, +// }); +// }); +// // Deno.test('[watcher]', async () => { +// // const watchers = new Watch(''); +// // assertThrows((): void => { +// // console.log('throwing'); +// // }); +// // }); + +// // Deno.test('[factory]', async () => { +// // console.log = consoleMock; +// // assertThrows( +// // () => { +// // return new WatchFactory({ srcDir: '', theme: '' }, ''); +// // }, +// // AssertionError, +// // 'assert', +// // ); +// // // assertThrows((): void => { +// // // console.log('throwing'); +// // // }); +// // }); diff --git a/src/watch/mod.ts b/src/watch/mod.ts new file mode 100644 index 0000000..0328df3 --- /dev/null +++ b/src/watch/mod.ts @@ -0,0 +1,2 @@ +export { default as Watch } from "trailmix/watch/Watch.ts"; +export { default as WatchFactory } from "trailmix/watch/WatchFactory.ts"; diff --git a/test/common/mod.ts b/test/common/mod.ts new file mode 100644 index 0000000..a394909 --- /dev/null +++ b/test/common/mod.ts @@ -0,0 +1 @@ +export * from "test/common/utils.ts"; diff --git a/test/common/utils.ts b/test/common/utils.ts new file mode 100644 index 0000000..37c9f30 --- /dev/null +++ b/test/common/utils.ts @@ -0,0 +1,127 @@ +import type { LogLevel } from "trailmix/log/mod.ts"; +import { stringifyBigInt } from "trailmix/log/mod.ts"; + +export enum strings { + ansi_reset = "\x1b[0m", + bold_prefix = "\x1b[1m", + bold_suffix = "\x1b[22m", + underline_prefix = "\x1b[4m", + underline_suffix = "\x1b[24m", + color_suffix = "\x1b[39m", +} +export enum colors { + clear = "0", + black = "30", + red = "31", + green = "32", + yellow = "33", + blue = "34", + magenta = "35", + cyan = "36", + white = "37", + BGblack = "40", + BGred = "41", + BGgreen = "42", + BGyellow = "43", + BGblue = "44", + BGmagenta = "45", + BGcyan = "46", + BGwhite = "47", +} +/** + * pass in logger level, name, and message and get a parsed message + * @param log log message to log + * @param level LogLevel object + * @param logger logger name string + * @returns formatted log message + */ +// eslint-disable-next-line max-params +export function logString( + log: string, + level: LogLevel = "ERROR", + logger = "default", + colorMsg = true, + ...args: unknown[] +): string { + const logColor = colorLog(level, logger); + const colorSuffix = logColor === "0" ? "0" : strings.color_suffix; + const bold = level === "CRITICAL" ? true : false; + const _log = level === "NOTSET" && logger === "test" ? "deDEBUG:" + log : log; + let msg = `[${logger}] ${_log}`; + if (colorMsg) { + msg = `[${color(logger, logColor, colorSuffix, bold)}] ${ + color(_log, logColor, colorSuffix, bold) + }`; + } + // console.log(JSON.stringify(args, null, 2)); + if (args !== null && args !== undefined && args.toString() !== "") { + // console.log('inside args'); + // msg = msg + ' \nArguments:\t' + JSON.stringify(JSON.parse(JSON.stringify(args, stringifyBigInt))[0], null, 2); + msg = msg + " \nArguments:" + JSON.stringify(args[0], stringifyBigInt, 2); + } + // console.log(msg); + return msg; +} +// eslint-disable-next-line max-params +export function color( + s: string, + prefix: strings | colors = colors.clear, + suffix: strings | string = strings.color_suffix, + bold = false, + underline = false, +) { + const _underline = underline ? strings.underline_prefix : ""; + const _bold = bold ? strings.bold_prefix : ""; + const _prefix = Number(prefix) > 0 ? `\x1b[${prefix}m` : ""; + const _suffix = suffix !== "0" ? suffix : ""; + const _underline_suffix = underline ? strings.underline_suffix : ""; + const _bold_suffix = bold ? strings.bold_suffix : ""; + let msg = + `${_bold}${_underline}${_prefix}${s}${_suffix}${_underline_suffix}${_bold_suffix}`; + return msg; +} +/** + * pass in logger name and level and get a string color + * @param level LogLevel object + * @param logger logger name string + * @returns colors + */ +export function colorLog( + level: LogLevel = "ERROR", + logger = "default", +): colors { + let color = colors.red; + switch (level) { + case "CRITICAL": + color = logger === "undefined" ? colors.red : colors.green; + break; + case "ERROR": + color = colors.red; + break; + case "WARNING": + color = colors.yellow; + break; + case "INFO": + color = colors.blue; + break; + case "DEBUG": + color = colors.clear; + break; + case "NOTSET": + color = colors.white; + break; + } + return color; +} +// export function successConsoleMock(...data: string[]) { +// asserts.assertStrictEquals(data.join(' '), consoleMock(...data)); +// } +// export function failureConsoleMock(...data: string[]) { +// // ogConsole(...data); +// asserts.assertStrictEquals(data.join(' '), 'NOTa'); +// } +// export function consoleMock(...data: string[]) { +// let value = Array.isArray(testCases) ? testCases.filter((test) => test === data.join(' ')).toString() : testCases; +// // console.log(`\nogConsole.data ${data}\t===\togConsole.value ${value}`); +// return value; +// } diff --git a/test/deps.ts b/test/deps.ts new file mode 100644 index 0000000..e69de29 diff --git a/trailmix.config.ts b/trailmix.config.ts new file mode 100644 index 0000000..f32e8ea --- /dev/null +++ b/trailmix.config.ts @@ -0,0 +1,12 @@ +export default { + namespace: "TRAILMIX", // prefixed to all env vars + vars: { + consoleLevel: { + command: "base", + global: true, + description: "Explicitly set console log level", + // object will be created as log.console.level + env: "LOG_CONSOLE_LEVEL", // namespace+ENV == TRAILMIX_LOG_CONSOLE_LEVEL + }, + }, +}; diff --git a/trilom.config.ts b/trilom.config.ts new file mode 100644 index 0000000..f32e8ea --- /dev/null +++ b/trilom.config.ts @@ -0,0 +1,12 @@ +export default { + namespace: "TRAILMIX", // prefixed to all env vars + vars: { + consoleLevel: { + command: "base", + global: true, + description: "Explicitly set console log level", + // object will be created as log.console.level + env: "LOG_CONSOLE_LEVEL", // namespace+ENV == TRAILMIX_LOG_CONSOLE_LEVEL + }, + }, +}; diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index cbdc69d..0000000 --- a/yarn.lock +++ /dev/null @@ -1,1636 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== - -"@babel/highlight@^7.10.4": - version "7.13.10" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" - integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@eslint/eslintrc@^0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" - integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog== - dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@nodelib/fs.scandir@2.1.4": - version "2.1.4" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" - integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== - dependencies: - "@nodelib/fs.stat" "2.0.4" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": - version "2.0.4" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" - integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.6" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" - integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== - dependencies: - "@nodelib/fs.scandir" "2.1.4" - fastq "^1.6.0" - -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@types/json-schema@^7.0.3": - version "7.0.7" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== - -"@typescript-eslint/eslint-plugin@^4.11.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.18.0.tgz#50fbce93211b5b690895d20ebec6fe8db48af1f6" - integrity sha512-Lzkc/2+7EoH7+NjIWLS2lVuKKqbEmJhtXe3rmfA8cyiKnZm3IfLf51irnBcmow8Q/AptVV0XBZmBJKuUJTe6cQ== - dependencies: - "@typescript-eslint/experimental-utils" "4.18.0" - "@typescript-eslint/scope-manager" "4.18.0" - debug "^4.1.1" - functional-red-black-tree "^1.0.1" - lodash "^4.17.15" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@4.18.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.18.0.tgz#ed6c955b940334132b17100d2917449b99a91314" - integrity sha512-92h723Kblt9JcT2RRY3QS2xefFKar4ZQFVs3GityOKWQYgtajxt/tuXIzL7sVCUlM1hgreiV5gkGYyBpdOwO6A== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.18.0" - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/typescript-estree" "4.18.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^4.11.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.18.0.tgz#a211edb14a69fc5177054bec04c95b185b4dde21" - integrity sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA== - dependencies: - "@typescript-eslint/scope-manager" "4.18.0" - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/typescript-estree" "4.18.0" - debug "^4.1.1" - -"@typescript-eslint/scope-manager@4.18.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.18.0.tgz#d75b55234c35d2ff6ac945758d6d9e53be84a427" - integrity sha512-olX4yN6rvHR2eyFOcb6E4vmhDPsfdMyfQ3qR+oQNkAv8emKKlfxTWUXU5Mqxs2Fwe3Pf1BoPvrwZtwngxDzYzQ== - dependencies: - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/visitor-keys" "4.18.0" - -"@typescript-eslint/types@4.18.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.18.0.tgz#bebe323f81f2a7e2e320fac9415e60856267584a" - integrity sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A== - -"@typescript-eslint/typescript-estree@4.18.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz#756d3e61da8c16ab99185532c44872f4cd5538cb" - integrity sha512-wt4xvF6vvJI7epz+rEqxmoNQ4ZADArGQO9gDU+cM0U5fdVv7N+IAuVoVAoZSOZxzGHBfvE3XQMLdy+scsqFfeg== - dependencies: - "@typescript-eslint/types" "4.18.0" - "@typescript-eslint/visitor-keys" "4.18.0" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/visitor-keys@4.18.0": - version "4.18.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz#4e6fe2a175ee33418318a029610845a81e2ff7b6" - integrity sha512-Q9t90JCvfYaN0OfFUgaLqByOfz8yPeTAdotn/XYNm5q9eHax90gzdb+RJ6E9T5s97Kv/UHWKERTmqA0jTKAEHw== - dependencies: - "@typescript-eslint/types" "4.18.0" - eslint-visitor-keys "^2.0.0" - -acorn-jsx@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== - -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -agent-base@5: - version "5.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - -agent-base@6: - version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^7.0.2: - version "7.2.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-7.2.3.tgz#ca78d1cf458d7d36d1c3fa0794dd143406db5772" - integrity sha512-idv5WZvKVXDqKralOImQgPM9v6WOdLNa0IY3B3doOjw/YxRGT8I+allIJ6kd7Uaj+SF1xZUSU+nPM5aDNBVtnw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argv@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" - integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= - -array-includes@^3.1.1, array-includes@^3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" - integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - get-intrinsic "^1.1.1" - is-string "^1.0.5" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.flatmap@^1.2.3: - version "1.2.4" - resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" - integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - function-bind "^1.1.1" - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0, chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -codecov@^3.8.1: - version "3.8.1" - resolved "https://registry.npmjs.org/codecov/-/codecov-3.8.1.tgz#06fe026b75525ed1ce864d4a34f1010c52c51546" - integrity sha512-Qm7ltx1pzLPsliZY81jyaQ80dcNR4/JpcX0IHCIWrHBXgseySqbdbYfkdiXd7o/xmzQpGRVCKGYeTrHUpn6Dcw== - dependencies: - argv "0.0.2" - ignore-walk "3.0.3" - js-yaml "3.14.0" - teeny-request "6.0.1" - urlgrey "0.4.4" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@4, debug@^4.0.1, debug@^4.1.1: - version "4.3.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: - version "1.18.0" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" - integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.2" - is-callable "^1.2.3" - is-negative-zero "^2.0.1" - is-regex "^1.1.2" - is-string "^1.0.5" - object-inspect "^1.9.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-config-alloy@^3.9.0: - version "3.10.0" - resolved "https://registry.npmjs.org/eslint-config-alloy/-/eslint-config-alloy-3.10.0.tgz#b2d85ba3bd7dddcc6d7fc79088c192a646f4f246" - integrity sha512-V34DUmW5n9NU2KbqKw6ow6qHt4RKksuvLKaAAC64ZMPnzwLH8ia7s0N4pEjeVzdtVL77jehCJkupLo8eUdKGYA== - -eslint-plugin-react@^7.21.5: - version "7.22.0" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz#3d1c542d1d3169c45421c1215d9470e341707269" - integrity sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA== - dependencies: - array-includes "^3.1.1" - array.prototype.flatmap "^1.2.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.4.1 || ^3.0.0" - object.entries "^1.1.2" - object.fromentries "^2.0.2" - object.values "^1.1.1" - prop-types "^15.7.2" - resolve "^1.18.1" - string.prototype.matchall "^4.0.2" - -eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0, eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== - -eslint@^7.16.0: - version "7.22.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f" - integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.21" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.4" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.1.1: - version "3.2.5" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastq@^1.6.0: - version "1.11.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" - integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -glob-parent@^5.0.0, glob-parent@^5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.1.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globals@^13.6.0: - version "13.7.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz#aed3bcefd80ad3ec0f0be2cf0c895110c0591795" - integrity sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.1: - version "11.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" - integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -graceful-fs@^4.1.2: - version "4.2.6" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - -has-bigints@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== - -http-proxy-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" - integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== - dependencies: - agent-base "5" - debug "4" - -ignore-walk@3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-bigint@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz#6923051dfcbc764278540b9ce0e6b3213aa5ebc2" - integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg== - -is-boolean-object@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" - integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== - dependencies: - call-bind "^1.0.0" - -is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== - -is-core-module@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== - dependencies: - has "^1.0.3" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-regex@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" - integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== - dependencies: - call-bind "^1.0.2" - has-symbols "^1.0.1" - -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.0" - resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" - integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q== - dependencies: - array-includes "^3.1.2" - object.assign "^4.1.2" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-fetch@^2.2.0: - version "2.6.1" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -npm-run-all@^4.1.5: - version "4.1.5" - resolved "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" - integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== - dependencies: - ansi-styles "^3.2.1" - chalk "^2.4.1" - cross-spawn "^6.0.5" - memorystream "^0.3.1" - minimatch "^3.0.4" - pidtree "^0.3.0" - read-pkg "^3.0.0" - shell-quote "^1.6.1" - string.prototype.padend "^3.0.0" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-inspect@^1.9.0: - version "1.9.0" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.entries@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz#c601c7f168b62374541a07ddbd3e2d5e4f7711a6" - integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - has "^1.0.3" - -object.fromentries@^2.0.2: - version "2.0.4" - resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" - integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" - -object.values@^1.1.1: - version "1.1.3" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" - integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pidtree@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" - integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz#abf64491e6ecf0f38a6502403d4cda04f372dfd3" - integrity sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg== - -react-is@^16.8.1: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -regexpp@^3.0.0, regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.10.0, resolve@^1.18.1: - version "1.20.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -"semver@2 || 3 || 4 || 5", semver@^5.5.0: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^7.2.1, semver@^7.3.2: - version "7.3.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.6.1: - version "1.7.2" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.7" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" - integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -stream-events@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" - integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== - dependencies: - stubs "^3.0.0" - -string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.matchall@^4.0.2: - version "4.0.4" - resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz#608f255e93e072107f5de066f81a2dfb78cf6b29" - integrity sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has-symbols "^1.0.1" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" - side-channel "^1.0.4" - -string.prototype.padend@^3.0.0: - version "3.1.2" - resolved "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" - integrity sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -stubs@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" - integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -table@^6.0.4: - version "6.0.7" - resolved "https://registry.npmjs.org/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" - integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== - dependencies: - ajv "^7.0.2" - lodash "^4.17.20" - slice-ansi "^4.0.0" - string-width "^4.2.0" - -teeny-request@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz#9b1f512cef152945827ba7e34f62523a4ce2c5b0" - integrity sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g== - dependencies: - http-proxy-agent "^4.0.0" - https-proxy-agent "^4.0.0" - node-fetch "^2.2.0" - stream-events "^1.0.5" - uuid "^3.3.2" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.17.1: - version "3.21.0" - resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typescript@^4.1.3: - version "4.2.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" - integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== - -unbox-primitive@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz#eeacbc4affa28e9b3d36b5eaeccc50b3251b1d3f" - integrity sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.0" - has-symbols "^1.0.0" - which-boxed-primitive "^1.0.1" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urlgrey@0.4.4: - version "0.4.4" - resolved "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" - integrity sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8= - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -which-boxed-primitive@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==