From e1c62582cb5279c732f56675b7bcf7eab5fbd735 Mon Sep 17 00:00:00 2001
From: pietervdvn <pietervdvn@posteo.net>
Date: Fri, 25 Mar 2022 15:47:14 +0100
Subject: [PATCH] Improve doctests

---
 README.md                         |  138 +---
 examples/OtherClass.ts            |    9 +
 examples/example0.ts              |   24 -
 examples/someClass.ts             |   27 +
 package.json                      |   17 +-
 src/ExtractComments.ts            |   97 +++
 src/TestCreator.ts                |  131 ++++
 src/TestSuite.ts                  |   17 +
 src/UnitTest.ts                   |  150 ++++
 src/internal.ts                   |  276 -------
 src/main.ts                       |   93 +--
 test/hasFoo.ts                    |   13 -
 test/test.ts                      |  152 ----
 tsconfig.json                     |   38 +-
 unused-test-files/c.ts            |    7 -
 unused-test-files/ex.ts           |   11 -
 unused-test-files/example.ts      |   89 ---
 unused-test-files/i.ts            |   23 -
 unused-test-files/main2.ts        |  417 ----------
 unused-test-files/visitor_test.ts |   46 --
 yarn.lock                         | 1173 ++++++++++++-----------------
 21 files changed, 1019 insertions(+), 1929 deletions(-)
 create mode 100644 examples/OtherClass.ts
 delete mode 100644 examples/example0.ts
 create mode 100644 examples/someClass.ts
 create mode 100644 src/ExtractComments.ts
 create mode 100644 src/TestCreator.ts
 create mode 100644 src/TestSuite.ts
 create mode 100644 src/UnitTest.ts
 delete mode 100644 src/internal.ts
 delete mode 100644 test/hasFoo.ts
 delete mode 100644 test/test.ts
 delete mode 100644 unused-test-files/c.ts
 delete mode 100644 unused-test-files/ex.ts
 delete mode 100644 unused-test-files/example.ts
 delete mode 100644 unused-test-files/i.ts
 delete mode 100644 unused-test-files/main2.ts
 delete mode 100644 unused-test-files/visitor_test.ts

diff --git a/README.md b/README.md
index 879ddd5..a3aba0a 100644
--- a/README.md
+++ b/README.md
@@ -1,124 +1,30 @@
-# doctest-ts: doctests for TypeScript
+# doctest-ts-improved: doctests for TypeScript
 
-Say you have a file src/hasFoo.ts with a function like hasFoo:
+Easy doctests for typescript modules, including private methods and extra imports:
 
-```typescript
-function hasFoo(s: string): boolean {
-  return null != s.match(/foo/i)
+```
+export default class SomeClass {
+    /**
+     * Gets the field doubled
+     * @example xyz
+     *
+     * import OtherClass from "./OtherClass";
+     * 
+     * // Should equal 42
+     * SomeClass.get() // => 42
+     *
+     * SomeClass.get() + 1 // => 43
+     * 
+     * new OtherClass().doSomething(new SomeClass()) // => 5
+     */
+    private static get() : number{
+        // a comment
+        // @ts-ignore
+        return 42
+    }
 }
 ```
 
-You can now make documentation and unit tests for this function in one go:
-
-```typescript
-/** Does this string contain foo, ignoring case?
-
-    hasFoo('___foo__') // => true
-    hasFoo('   fOO  ') // => true
-    hasFoo('Foo.') // => true
-    hasFoo('bar') // => false
-    hasFoo('fo') // => false
-    hasFoo('oo') // => false
-
-*/
-function hasFoo(s: string): boolean {
-  return null != s.match(/foo/i)
-}
-```
-
-Since the function is not exported we can only test this by either editing or copying the entire file and gluing on tests at the end.
-This library goes for the second approach: making a copy of the file with the translated tests at the end. Run it like so:
-
-```sh
-$ doctest-ts src/hasFoo.ts
-Writing src/hasFoo.doctest.ts
-```
-
-The contents of `src/hasFoo.doctest.ts` is the original file prepended to the doctests rewritten as unit tests.
-
-```typescript
-/** Does this string contain foo, ignoring case?
-
-    hasFoo('___foo__') // => true
-    hasFoo('   fOO  ') // => true
-    hasFoo('Foo.') // => true
-    hasFoo('bar') // => false
-    hasFoo('fo') // => false
-    hasFoo('oo') // => false
-
-*/
-function hasFoo(s: string): boolean {
-  return null != s.match(/foo/i)
-}
-
-import * as __test from "tape"
-__test("hasFoo", t => {t.deepEqual(hasFoo("___foo__"), true, "true")
-t.deepEqual(hasFoo("   fOO  "), true, "true")
-t.deepEqual(hasFoo("Foo."), true, "true")
-t.deepEqual(hasFoo("bar"), false, "false")
-t.deepEqual(hasFoo("fo"), false, "false")
-t.deepEqual(hasFoo("oo"), false, "false")
-;t.end()})
-```
-
-This can now be run with the tape runner or ts-node:
-
-```
-$ ts-node src/hasFoo.doctest.ts | tap-diff
-  hasFoo
-    ✔  true
-    ✔  true
-    ✔  true
-    ✔  false
-    ✔  false
-    ✔  false
-        Done in 0.37s.
-
-passed: 6  failed: 0  of 6 tests  (171ms)
-
-All of 6 tests passed!
-```
-
-There are four different outputs available:
-
-* tape
-* AVA
-* jest
-* mocha (using chai)
-
-Pull requests for other test runners are welcome.
-
-## Watching file changes
-
-We can tell `doctest-ts` to watch for file changes and report which files it has written.
-It tries to be a good unix citizen and thus writes the files it has created on stdout (and some info on stderr).
-This makes it possible to run test runners on each line on stdout like so:
-
-```sh
-ts-node src/main.ts --watch src/hasFo.ts |
-while read file; do echo running tape on $file; ts-node $file | tap-diff; done
-```
-
-Let's say we remove the ignore case `i` flag from the regex in `hasFoo`. We get this output (automatically):
-```
-Writing src/hasFoo.doctest.ts
-running tape on src/hasFoo.doctest.ts
-
-  hasFoo
-    ✔  true
-    ✖  true at Test.t (src/hasFoo.doctest.ts:18:3)
-        [-false-][+true+]
-    ✖  true at Test.t (src/hasFoo.doctest.ts:19:3)
-        [-false-][+true+]
-    ✔  false
-    ✔  false
-    ✔  false
-
-passed: 4  failed: 2  of 6 tests  (264ms)
-
-2 of 6 tests failed.
-```
-
 # License
 
 MIT
diff --git a/examples/OtherClass.ts b/examples/OtherClass.ts
new file mode 100644
index 0000000..5979587
--- /dev/null
+++ b/examples/OtherClass.ts
@@ -0,0 +1,9 @@
+import SomeClass from "./someClass";
+
+export default class OtherClass {
+    
+    public doSomething(c: SomeClass){
+        return c.xyz()
+    }
+    
+}
\ No newline at end of file
diff --git a/examples/example0.ts b/examples/example0.ts
deleted file mode 100644
index a31f73b..0000000
--- a/examples/example0.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-export default class Example0 {
-    
-    /**
-     * Gets the field doubled
-     * @example xyz
-     * 
-     * // Should equal 42
-     * Example0.get() // => 42
-     * 
-     * Example0.get() + 1 // => 43
-     */
-    private static get(){
-        // a comment
-        // @ts-ignore
-        return 42
-    }
-    
-    public testMore(){
-        return ({} as any) ?.xyz?.abc ?? 0
-    }
-    
-}
\ No newline at end of file
diff --git a/examples/someClass.ts b/examples/someClass.ts
new file mode 100644
index 0000000..a671254
--- /dev/null
+++ b/examples/someClass.ts
@@ -0,0 +1,27 @@
+
+export default class SomeClass {
+
+    /**
+     * Gets the field doubled
+     * @example xyz
+     *
+     * import OtherClass from "./OtherClass";
+     * 
+     * // Should equal 42
+     * SomeClass.get() // => 42
+     *
+     * SomeClass.get() + 1 // => 43
+     * 
+     * new OtherClass().doSomething(new SomeClass()) // => 5
+     */
+    private static get() : number{
+        // a comment
+        // @ts-ignore
+        return 42
+    }
+    
+    public xyz(){
+        return 5
+    }
+
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 305cc69..05bd59d 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,16 @@
 {
   "$schema": "http://json.schemastore.org/package",
-  "name": "doctest-ts",
-  "version": "0.6.0",
-  "description": "doctest support for typescript",
+  "name": "doctest-ts-improved",
+  "version": "0.7.0",
+  "description": "doctest support for typescript with Mocha",
   "main": "src/main.ts",
   "bin": {
-    "doctest-ts": "dist/src/main.js"
+    "doctest-ts-improved": "dist/src/main.js"
   },
   "scripts": {
     "build": "tsc && chmod 755 dist/src/main.js",
-    "test": "ts-node src/main.ts --tape src/*ts test/*ts && ts-node node_modules/.bin/tape test/*.ts src/*doctest*.ts | tap-diff",
     "doctest:watch": "ts-node src/main.ts --tape --watch {src,test}/*.ts | while read file; do echo tape $file; ts-node $file | tap-diff; done",
-    "debug": "ts-node src/main.ts --mocha examples/example0.ts",
+    "test": "ts-node src/main.ts examples/ && ts-node src/main.ts src/ && mocha --require ts-node/register examples/*.ts src/*.ts",
     "prettier": "rm -v -f {src,test}/*doctest.ts && prettier --list-different --write src/*ts* test/*ts*"
   },
   "repository": {
@@ -30,14 +29,16 @@
   },
   "homepage": "https://github.com/danr/doctest-ts#readme",
   "dependencies": {
-    "chokidar": "^2.0.1",
+    "@types/chai": "^4.3.0",
+    "chai": "^4.3.6",
     "global": "^4.3.2",
-    "minimist": "^1.2.0",
+    "mocha": "^9.2.2",
     "typescript": "^4.6.2"
   },
   "devDependencies": {
     "@types/chokidar": "^1.7.5",
     "@types/minimist": "^1.2.0",
+    "@types/mocha": "^9.1.0",
     "@types/node": "^9.4.6",
     "@types/tape": "^4.2.31",
     "faucet": "^0.0.1",
diff --git a/src/ExtractComments.ts b/src/ExtractComments.ts
new file mode 100644
index 0000000..7d47660
--- /dev/null
+++ b/src/ExtractComments.ts
@@ -0,0 +1,97 @@
+import * as ts from "typescript";
+import {JSDocComment} from "typescript";
+import {SyntaxKind} from "typescript/lib/tsserverlibrary";
+
+export interface Context {
+    filepath: string,
+    linenumber?: number,
+    classname?: string,
+    functionname?: string,
+    testname?: string
+}
+
+/**
+ * Responsible for extracting the testfiles from the .ts files
+ *
+ */
+export default class ExtractComments {
+
+    private readonly results: { comment: string, context: Context }[] = []
+    private readonly code: string;
+
+    constructor(filepath: string, code: string) {
+        this.code = code;
+        const ast = ts.createSourceFile('_.ts', code, ts.ScriptTarget.Latest)
+        this.traverse(ast, {filepath: filepath})
+    }
+
+    public getComments(): { comment: string, context: Context }[] {
+        return this.results
+    }
+
+    private getLineNumber(pos: number) {
+        let line = 0;
+        for (let i = 0; i < pos; i++) {
+            if (this.code[i] === "\n") {
+                line++
+            }
+        }
+        return line;
+    }
+
+    private registerComment(context: Context, comment: string | ts.NodeArray<JSDocComment> | undefined, position: number) {
+        if (comment === undefined) {
+            return
+        }
+        context = {...context, linenumber: this.getLineNumber(position)}
+        if (typeof comment === "string") {
+            this.results.push({comment: comment || '', context});
+        } else {
+            comment.forEach(jsDocComment => {
+                this.results.push({comment: jsDocComment.text || '', context});
+            })
+        }
+    }
+
+    private traverse(node: ts.Node, context: Context) {
+        if (SyntaxKind.ClassDeclaration === node.kind) {
+            context = {...context, classname: (node as any)["name"].escapedText};
+        }
+        const jsdocs = (node as any).jsDoc || []
+        if (jsdocs.length > 0) {
+            let declName = undefined
+            try {
+                declName = (node as any).name.escapedText
+            } catch (e) {
+                try {
+                    const decls = (node as any).declarationList.declarations
+                    if (decls.length == 1) {
+                        declName = decls[0].name.escapedText || null
+                    }
+                } catch (e) {
+                    declName = ts.isConstructorDeclaration(node) ? 'constructor' : undefined
+                }
+            }
+
+            context = {...context, functionname: declName}
+
+            jsdocs.forEach((doc: ts.JSDoc) => {
+                this.registerComment(context, doc.comment, doc.pos)
+
+                // A part of the comment might be in the tags; we simply add those too and figure out later if they contain doctests
+                const tags = doc.tags;
+                if (tags !== undefined) {
+                    tags.forEach(tag => {
+                        this.registerComment(context, tag.comment, tag.pos)
+                    });
+                }
+            })
+
+        }
+
+
+        ts.forEachChild(node, n => this.traverse(n, context))
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/TestCreator.ts b/src/TestCreator.ts
new file mode 100644
index 0000000..aa5ef90
--- /dev/null
+++ b/src/TestCreator.ts
@@ -0,0 +1,131 @@
+import UnitTest from "./UnitTest";
+import * as ts from "typescript";
+import ExtractComments from "./ExtractComments";
+import * as fs from 'fs'
+import * as path from 'path'
+
+/**
+ * Responsible for creating a '.doctest.ts'-file
+ */
+export default class TestCreator {
+    private _originalFilepath: string;
+
+    constructor(originalFilepath: string) {
+        this._originalFilepath = originalFilepath;
+        if (originalFilepath.includes('doctest')) {
+            throw "Not creating a doctest for a file which already is a doctest"
+        }
+    }
+
+    private static exposePrivates(s: string): string {
+        const ast = ts.createSourceFile('_.ts', s, ts.ScriptTarget.Latest) as ts.SourceFile
+
+        const transformer = <T extends ts.Node>(context: ts.TransformationContext) =>
+            (rootNode: T) => {
+                function visit(node: ts.Node): ts.Node {
+                    if (node.kind === ts.SyntaxKind.PrivateKeyword) {
+                        return ts.createModifier(ts.SyntaxKind.PublicKeyword)
+                    }
+                    return ts.visitEachChild(node, visit, context);
+                }
+
+                return ts.visitNode(rootNode, visit);
+            };
+
+        const transformed = ts.transform(ast, [transformer]).transformed[0]
+
+        const pwoc = ts.createPrinter({removeComments: false})
+        return pwoc.printNode(ts.EmitHint.Unspecified, transformed, ast)
+    }
+
+
+    private static testCode(tests: UnitTest[]): string[] {
+        const code: string[] = []
+        const exportedTests = new Set<UnitTest>()
+       
+        function show(s: string) {
+            return JSON.stringify(s)
+        }
+
+        function emit(test: UnitTest, indent: string = "") {
+            if (exportedTests.has(test)) {
+                return;
+            }
+            const testCode = "\n" + test.generateCode()
+            code.push(testCode.replace(/\n/g, "\n" + indent))
+            exportedTests.add(test)
+        }
+
+        function emitAllForFunction(functionname: string | undefined, indent: string) {
+            tests.filter(t => t.context.functionname === functionname).forEach(c => emit(c, "    " + indent))
+        }
+
+        function emitAllForClass(classname: string | undefined, indent: string) {
+            const forClass: UnitTest[] = tests.filter(t => t.context.classname === classname)
+            for (const test of forClass) {
+                if (exportedTests.has(test)) {
+                    continue
+                }  
+                
+                if (test.context.functionname !== undefined) {
+                    code.push(indent+"describe(" + show(test.context.functionname) + ", () => {")
+                    emitAllForFunction(test.context.functionname, "    " + indent)
+                    code.push(indent+"})")
+                }
+                
+            }
+            emitAllForFunction(undefined, indent)
+        }
+
+        for (const test of tests) {
+            if (exportedTests.has(test)) {
+                continue
+            }
+            if (test.context.classname !== undefined) {
+                code.push("describe(" + show(test.context.classname) + ", () => {")
+                emitAllForClass(test.context.classname, "    ")
+                code.push("})")
+            }
+        }
+
+        emitAllForClass(undefined, "")
+        return code
+    }
+
+    /**
+     * Creates a new file with the doctests.
+     *
+     * Returns the number of found tests
+     */
+    public createTest(): number {
+        const file = this._originalFilepath
+        const {base, ext, ...u} = path.parse(file)
+        const buffer = fs.readFileSync(file, {encoding: 'utf8'})
+        const comments = new ExtractComments(file, buffer).getComments()
+        const tests: UnitTest[] = UnitTest.FromComments(comments)
+
+        const outfile = path.format({...u, ext: '.doctest' + ext})
+        if (tests.length == 0) {
+            return 0
+        }
+
+        const code = []
+        const imports = new Set<string>()
+        for (const test of tests) {
+            test.getImports().forEach(i => imports.add(i))
+        }
+
+        // Add imports needed by the tests
+        code.push(...Array.from(imports))
+        // Adds the original code where the private keywords are removed
+        code.push(TestCreator.exposePrivates(buffer))
+
+        // At last, we add all the doctests
+        code.push(...TestCreator.testCode(tests))
+
+        fs.writeFileSync(outfile, code.join("\n"))
+        return tests.length
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/TestSuite.ts b/src/TestSuite.ts
new file mode 100644
index 0000000..4293bb7
--- /dev/null
+++ b/src/TestSuite.ts
@@ -0,0 +1,17 @@
+export default interface TestDescription {
+
+    /**
+     * The name of the module under test
+     */
+    moduleName?: string;
+
+    /**
+     * The name of the function under testing
+     */
+    functionName?: string
+
+    /**
+     * The name of the singular test
+     */
+    testName?: string
+}
\ No newline at end of file
diff --git a/src/UnitTest.ts b/src/UnitTest.ts
new file mode 100644
index 0000000..9cc11d2
--- /dev/null
+++ b/src/UnitTest.ts
@@ -0,0 +1,150 @@
+import {Context} from "./ExtractComments";
+import * as ts from "typescript";
+
+type Script = (Statement | Equality)[]
+interface Equality {
+    tag: '=='
+    lhs: string
+    rhs: string
+}
+
+interface Statement {
+    tag: 'Statement'
+    stmt: string
+}
+
+class ScriptExtraction {
+    /**
+     * ScriptExtraction.is_doctest('// => true') // => true
+     * ScriptExtraction.is_doctest('// true') // => false
+     */
+    public static is_doctest(s: string): boolean {
+        return s.match(/\/\/[ \t]*=>/) != null
+    }
+
+    /**
+     * Extracts the expected value
+     *
+     * const m = ScriptExtraction.doctest_rhs('// => true') || []
+     * m[1] // => ' true'
+     */
+    public static doctest_rhs(s: string) {
+        return s.match(/^\s*\/\/[ \t]*=>([^\n]*)/m);
+    }
+
+    public static extractImports(docstring: string){
+        return docstring.split("\n").filter(s => s.startsWith("import "));
+    }
+    
+    public static extractScripts(docstring: string): { script: Script, name?: string, line: number }[] {
+        const out = [] as { script: Script, name?: string, line: number }[]
+        let line = 0;
+        for (const s of docstring.split(/\n\n+/m)) {
+            const p: number = line;
+            line += s.split(/\r\n|\r|\n/).length
+
+            if (!ScriptExtraction.is_doctest(s)) {
+                continue;
+            }
+
+            const script = ScriptExtraction.extractScript(s)
+            let name = undefined
+            const match = s.match(/^[ \t]*\/\/([^\n]*)/)
+            if (match !== null) {
+                name = match[1].trim()
+            }
+            out.push({script, name, line: p})
+        }
+        return out
+    }
+
+    /**
+     * ScriptExtraction.extractScript('s') // => [{tag: 'Statement', stmt: 's;'}]
+     * ScriptExtraction.extractScript('e // => 1') // => [{tag: '==', lhs: 'e', rhs: '1'}]
+     * ScriptExtraction.extractScript('s; e // => 1') // => [{tag: 'Statement', stmt: 's;'}, {tag: '==', lhs: 'e', rhs: '1'}]
+     */
+    private static extractScript(s: string): Script {
+        const pwoc = ts.createPrinter({removeComments: true})
+        const ast = ts.createSourceFile('_.ts', s, ts.ScriptTarget.Latest)
+        return ast.statements.map((stmt, i): Statement | Equality => {
+            if (ts.isExpressionStatement(stmt)) {
+                const next = ast.statements[i + 1] // zip with next
+                const [a, z] = next ? [next.pos, next.end] : [stmt.end, ast.end]
+                const after = ast.text.slice(a, z)
+                const m = ScriptExtraction.doctest_rhs(after)
+                if (m && m[1]) {
+                    const lhs = pwoc.printNode(ts.EmitHint.Expression, stmt.expression, ast)
+                    const rhs = m[1].trim()
+                    return {tag: '==', lhs, rhs}
+                }
+            }
+
+
+
+            return {tag: 'Statement', stmt: pwoc.printNode(ts.EmitHint.Unspecified, stmt, ast)}
+        })
+    }
+}
+
+/**
+ * Represents a single unit test somewhere in a file.
+ */
+export default class UnitTest {
+
+
+    public body: Script;
+    public context: Context;
+    private _extraImports: string[];
+
+    private constructor(body: Script, context: Context, extraImports: string[]) {
+        this.body = body;
+        this.context = context;
+        this._extraImports = extraImports;
+    }
+
+    public static FromComment(comment: string, context: Context): UnitTest[] {
+        const imports = ScriptExtraction.extractImports(comment)
+        return ScriptExtraction.extractScripts(comment).map(({script, line, name}, i) =>
+            new UnitTest(script, {
+                ...context,
+                linenumber: (context.linenumber ?? 0) + line,
+                testname: name ?? 'doctest ' + i
+            },imports))
+    }
+
+    public static FromComments(comms: { comment: string, context: Context }[]): UnitTest[] {
+        const result: UnitTest[] = []
+        for (const comm of comms) {
+            result.push(...UnitTest.FromComment(comm.comment, comm.context))
+        }
+        return result
+    }
+
+    public getImports(): string[] {
+        return [...this._extraImports, 'import "mocha"', 'import {expect as __expect} from "chai"']
+    }
+
+    /**
+     * Generates the mocha test code for this unit test.
+     * Will only construct the 'it('should ....') { __expect(x).deep.eq(y) } part
+     */
+    public generateCode() {
+        const script = this.body
+            .map(s => {
+                if (s.tag == 'Statement') {
+                    return s.stmt
+                } else {
+                    return `__expect(${s.lhs}, "failed at ${this.context.functionname} (${this.context.filepath}:${this.context.linenumber}:1)").to.deep.equal(${s.rhs})`
+                }
+            })
+            .map(x => '\n        ' + x)
+            .join('')
+        return `it(${this.getName()}, () => {${script}\n})`
+    }
+
+    private getName() {
+        return JSON.stringify(this.context.testname ?? this.context.functionname)
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/internal.ts b/src/internal.ts
deleted file mode 100644
index 78697c5..0000000
--- a/src/internal.ts
+++ /dev/null
@@ -1,276 +0,0 @@
-import * as ts from 'typescript'
-import {JSDocComment} from 'typescript'
-import * as fs from 'fs'
-import * as path from 'path'
-
-////////////////////////////////////////////////////////////
-// Types
-
-export interface Equality {
-  tag: '=='
-  lhs: string
-  rhs: string
-}
-
-export interface Statement {
-  tag: 'Statement'
-  stmt: string
-}
-
-export type Script = (Statement | Equality)[]
-
-export type Context = string | null
-
-export interface Comment {
-  comment: string
-  context: Context
-}
-
-////////////////////////////////////////////////////////////
-// Extracting docstrings from program
-
-export function Comments(s: string): Comment[] {
-  const out: Comment[] = []
-  function registerComment(context: string | null,comment: string | ts.NodeArray<JSDocComment> | undefined){
-      if(comment === undefined){
-        return
-      }
-      if(typeof comment === "string"){  
-        out.push({comment: comment || '', context});
-      }else{
-        comment.forEach(jsDocComment => {
-          out.push({comment: jsDocComment.text || '', context});
-        })
-      }
-  }
-  
-  
-  function traverse(node: ts.Node) {
-    const jsdocs = (node as any).jsDoc || []
-    if (jsdocs.length > 0) {
-      let context: string | null = null
-      try {
-        context = (node as any).name.escapedText || null
-      } catch (e) {
-        try {
-          const decls = (node as any).declarationList.declarations
-          if (decls.length == 1) {
-            context = decls[0].name.escapedText || null
-          }
-        } catch (e) {
-          context = ts.isConstructorDeclaration(node) ? 'constructor' : null
-        }
-      }
-      jsdocs.forEach((doc: ts.JSDoc) => {
-       registerComment(context, doc.comment)
-        
-        // A part of the comment might be in the tags; we simply add those too and figure out later if they contain doctests
-        const tags = doc.tags;
-        if(tags !== undefined){
-          tags.forEach(tag => {
-            registerComment(context, tag.comment)
-          });
-        }
-      })
-      
-    }
-    ts.forEachChild(node, traverse)
-  }
-  
-  const ast = ts.createSourceFile('_.ts', s, ts.ScriptTarget.Latest)
-  traverse(ast)
-
-  return out
-}
-
-////////////////////////////////////////////////////////////
-// Extracting test scripts from docstrings
-
-/**
-
-  is_doctest('// => true') // => true
-  is_doctest('// true') // => false
-
-*/
-const is_doctest = (s: string) => s.match(/\/\/[ \t]*=>/) != null
-
-/**
-
-  const m = doctest_rhs('// => true') || []
-  m[1] // => ' true'
-
-*/
-const doctest_rhs = (s: string) => s.match(/^\s*\/\/[ \t]*=>([^\n]*)/m)
-
-/**
-
-  extractScript('s') // => [{tag: 'Statement', stmt: 's;'}]
-
-  extractScript('e // => 1') // => [{tag: '==', lhs: 'e', rhs: '1'}]
-
-  extractScript('s; e // => 1') // => [{tag: 'Statement', stmt: 's;'}, {tag: '==', lhs: 'e', rhs: '1'}]
-
-*/
-export function extractScript(s: string): Script {
-  const pwoc = ts.createPrinter({removeComments: true})
-  const ast = ts.createSourceFile('_.ts', s, ts.ScriptTarget.Latest)
-  return ast.statements.map((stmt, i): Statement | Equality => {
-    if (ts.isExpressionStatement(stmt)) {
-      const next = ast.statements[i + 1] // zip with next
-      const [a, z] = next ? [next.pos, next.end] : [stmt.end, ast.end]
-      const after = ast.text.slice(a, z)
-      const m = doctest_rhs(after)
-      if (m && m[1]) {
-        const lhs = pwoc.printNode(ts.EmitHint.Expression, stmt.expression, ast)
-        const rhs = m[1].trim()
-        return {tag: '==', lhs, rhs}
-      }
-    }
-
-    return {tag: 'Statement', stmt: pwoc.printNode(ts.EmitHint.Unspecified, stmt, ast)}
-  })
-}
-
-export function extractScripts(docstring: string): {script: Script, name?: string}[] {
-  const out = [] as {script: Script, name?: string}[]
-  docstring.split(/\n\n+/m).forEach(s => {
-    if (is_doctest(s)) {
-      const script = extractScript(s)
-      let name = undefined
-      const match  = s.match(/^[ \t]*\/\/([^\n]*)/)
-      if(match !== null)
-      {
-        name = match[1].trim()
-      }
-      out.push({script, name})
-    }
-  })
-  return out
-}
-
-////////////////////////////////////////////////////////////
-// Showing test scripts
-export interface ShowScript {
-  showImports: string
-  showScript(script: Script, c: Context, name?: string): string
-}
-
-/** show("hello") // => '"hello"' */
-export function show(s: any) {
-  return JSON.stringify(s)
-}
-
-export function showContext(c: Context) {
-  return show(c || 'doctest')
-}
-
-function tapeOrAVA(script: Script, c: Context, name: string | undefined, before_end = (t: string) => '') {
-  const t = `t`
-  const body = script
-    .map(s => {
-      if (s.tag == 'Statement') {
-        return s.stmt
-      } else {
-        return `${t}.deepEqual(${s.lhs}, ${s.rhs}, ${show(s.rhs)})`
-      }
-    })
-    .map(x => '\n      ' + x)
-    .join('')
-  return `
-    __test(${showContext(c)}, ${t} => {
-      ${body}
-      ${before_end(t)}
-    })`
-}
-
-const mochaOrJest = (deepEqual: string): typeof tapeOrAVA => (script, c, name) => {
-  const body = script
-    .map(s => {
-      if (s.tag == 'Statement') {
-        return s.stmt
-      } else {
-        return `__expect(${s.lhs}).${deepEqual}(${s.rhs})`
-      }
-    })
-    .map(x => '\n        ' + x)
-    .join('')
-
-  return `
-    describe(${showContext(c)}, () => {
-      it(${show(name) || showContext(c)}, () => {${body}})
-    })
-  `
-}
-
-export const showScriptInstances: Record<string, ShowScript> = {
-  ava: {
-    showImports: 'import {test as __test} from "ava"',
-    showScript: tapeOrAVA,
-  },
-
-  tape: {
-    showImports: 'import * as __test from "tape"',
-    showScript: (s, c, name) => tapeOrAVA(s, c, name, t => `\n;${t}.end()`),
-  },
-
-  mocha: {
-    showImports: 'import "mocha"\nimport {expect as __expect} from "chai"',
-    showScript: mochaOrJest(`to.deep.equal`),
-  },
-
-  jest: {
-    showImports: 'import "jest"\nconst __expect: jest.Expect = expect',
-    showScript: mochaOrJest(`toEqual`),
-  },
-}
-
-function exposePrivates(s: string): string {
-  const ast = ts.createSourceFile('_.ts', s, ts.ScriptTarget.Latest) as ts.SourceFile
-
-  const transformer = <T extends ts.Node>(context: ts.TransformationContext) =>
-      (rootNode: T) => {
-        function visit(node: ts.Node): ts.Node {
-          if (node.kind === ts.SyntaxKind.PrivateKeyword) {
-            return ts.createModifier(ts.SyntaxKind.PublicKeyword)
-          }
-          return ts.visitEachChild(node, visit, context);
-        }
-        return ts.visitNode(rootNode, visit);
-      };
-
- const transformed = ts.transform(ast, [transformer]).transformed[0]
-  
-  const pwoc = ts.createPrinter({ removeComments: false})
-  return  pwoc.printNode(ts.EmitHint.Unspecified, transformed, ast)
-}
-
-
-export function instrument(d: ShowScript, file: string, mode?: 'watch'): void {
-  const {base, ext, ...u} = path.parse(file)
-  if (base.includes('doctest')) {
-    return
-  }
-  const buffer = fs.readFileSync(file, {encoding: 'utf8'})
-  const withoutPrivates = exposePrivates(buffer)
-  const tests = Doctests(d, buffer)
-  const outfile = path.format({...u, ext: '.doctest' + ext})
-  if (tests.length == 0) {
-    console.error('No doctests found in', file)
-  } else {
-    console.error('Writing', outfile)
-    if (mode == 'watch') {
-      console.log(outfile)
-    }
-    fs.writeFileSync(outfile, withoutPrivates + '\n' + d.showImports + '\n' + tests.join('\n'))
-  }
-}
-
-function Doctests(d: ShowScript, buffer: string): string[] {
-  const out: string[] = []
-  for (const c of Comments(buffer)) {
-    for (const script of extractScripts(c.comment)) {
-      out.push(d.showScript(script.script,  c.context, script.name))
-    }
-  }
-  return out
-}
diff --git a/src/main.ts b/src/main.ts
index b5f765f..72d24ed 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,49 +1,52 @@
 #!/usr/bin/env node
-import * as chokidar from 'chokidar'
-import * as minimist from 'minimist'
-import {instrument, showScriptInstances} from './internal'
-function main() {
-  const outputs = Object.keys(showScriptInstances)
-  const flags = outputs.map(f => '--' + f)
-  const boolean = ['watch'].concat(outputs)
-  const opts = minimist(process.argv.slice(2), {boolean})
-  let output: string | null = null
-  let error: string | null = null
-  outputs.forEach(k => {
-    if (opts[k]) {
-      if (output != null) {
-        error = `Cannot output both ${output} and ${k}`
-      }
-      output = k
+import {lstatSync, readdirSync} from "fs";
+import TestCreator from "./TestCreator";
+
+
+function readDirRecSync(path: string, maxDepth = 999): string[] {
+    const result = []
+    if (maxDepth <= 0) {
+        return []
     }
-  })
-  if (output == null) {
-    error = `Choose an output from ${flags.join(' ')}`
-  }
-  const files = opts._
-  if (files.length == 0 || output == null) {
-    console.error(
-      `
-      Error: ${error || `No files specified!`}
-
-      Usage:
-
-        ${flags.join('|')} [-w|--watch] files globs...
-
-    Your options were:`,
-      opts,
-      `
-    From:`,
-      process.argv
-    )
-    return
-  }
-  const d = showScriptInstances[output]
-  files.forEach(file => instrument(d, file))
-  if (opts.w == true || opts.watch == true) {
-    const watcher = chokidar.watch(files, {ignored: '*.doctest.*'})
-    watcher.on('change', file => global.setTimeout(() => instrument(d, file, 'watch'), 25))
-  }
+    for (const entry of readdirSync(path)) {
+        const fullEntry = path + "/" + entry
+        const stats = lstatSync(fullEntry)
+        if (stats.isDirectory()) {
+            // Subdirectory
+            // @ts-ignore
+            result.push(...ScriptUtils.readDirRecSync(fullEntry, maxDepth - 1))
+        } else {
+            result.push(fullEntry)
+        }
+    }
+    return result;
 }
 
-main()
+function main(){
+    
+const args = process.argv
+console.log(args.join(","))
+const directory = args[2].replace(/\/$/, "")
+if(directory === "--require"){
+    console.error("Probably running the testsuite, detects '--require' as second argument. Quitting now")
+    return;
+}
+if(directory === undefined){
+    console.log("Usage: doctest-ts-improved <directory under test>. This will automatically scan recursively for '.ts'-files, excluding 'node_modules' '*.doctest.ts'-files")
+}
+
+const files = readDirRecSync(directory).filter(p => !p.startsWith("./node_modules") && !p.endsWith(".doctest.ts"))
+const noTests : string[] = []
+for (const file of files) {
+    const generated = new TestCreator(file).createTest()
+    if(generated === 0){
+        noTests.push(file)
+    }else{
+        console.log("Generated tests for "+file+" ("+generated+" tests found)")
+    }
+}
+if(noTests.length > 0){
+    console.log("No tests found in: "+noTests.join(", "))
+}
+}
+main()
\ No newline at end of file
diff --git a/test/hasFoo.ts b/test/hasFoo.ts
deleted file mode 100644
index be80d61..0000000
--- a/test/hasFoo.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/** Does this string contain foo, ignoring case?
-
-    hasFoo('___foo__') // => true
-    hasFoo('   fOO  ') // => true
-    hasFoo('Foo.') // => true
-    hasFoo('bar') // => false
-    hasFoo('fo') // => false
-    hasFoo('oo') // => false
-
-*/
-function hasFoo(s: string): boolean {
-  return null != s.match(/foo/i)
-}
diff --git a/test/test.ts b/test/test.ts
deleted file mode 100644
index b10adfd..0000000
--- a/test/test.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import * as internal from '../src/internal'
-import * as test from 'tape'
-
-test('tests', t => {
-  t.plan(1)
-  t.deepEqual(
-    internal.extractScripts(`*
-
-  foo // => 1
-
-  `),
-    [{ script: [{tag: '==', lhs: `foo`, rhs: `1`}], name: undefined }]
-  )
-})
-
-test('tests', t => {
-  t.plan(1)
-  t.deepEqual(
-    internal.extractScripts(`*
-
-    a
-    b // => 1 + 2 + 3
-    c // => 1
-    d
-
-    */`).map(s => s.script),
-    [
-      [
-        {tag: 'Statement', stmt: 'a;'},
-        {tag: '==', lhs: 'b', rhs: '1 + 2 + 3'},
-        {tag: '==', lhs: 'c', rhs: '1'},
-        {tag: 'Statement', stmt: 'd;'},
-      ],
-    ]
-  )
-})
-
-const c = (comment: string, context: string | null) => ({comment, context})
-
-test('modules and namespace', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** m */
-    namespace m {}
-
-    /** ns */
-    namespace ns {}
-  `)
-  t.deepEqual(cs, [c('m', 'm'), c('ns', 'ns')])
-})
-
-test('const', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** u */
-    const u = 1
-  `)
-  t.deepEqual(cs, [c('u', 'u')])
-})
-
-test('const object', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** k */
-    const k = {
-      /** a */
-      a: 1,
-      /** b */
-      b(x: string) { return x+x }
-    }
-  `)
-  t.deepEqual(cs, [c('k', 'k'), c('a', 'a'), c('b', 'b')])
-})
-
-test('object deconstruction', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** hello */
-    const {u, v} = {u: 1, v: 2}
-  `)
-  t.deepEqual(cs, [c('hello', null)])
-})
-
-test('function', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** v */
-    function v(s: string): number {
-      return s.length + 1
-    }
-  `)
-  t.deepEqual(cs, [c('v', 'v')])
-})
-
-test('class', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** C */
-    class C<A> {
-      /** constructor */
-      constructor() {}
-      /** m */
-      m(s: Array<number>): Array<string> {
-      }
-      /** p */
-      p: Array<number>
-    }
-  `)
-  t.deepEqual(cs, [c('C', 'C'), c('constructor', 'constructor'), c('m', 'm'), c('p', 'p')])
-})
-
-test('interface', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** I */
-    interface I<A> {
-      /** i */
-      i: A,
-      /** j */
-      j(a: A): string
-    }
-  `)
-  t.deepEqual(cs, [c('I', 'I'), c('i', 'i'), c('j', 'j')])
-})
-
-test('type', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    /** T */
-    type T = number
-  `)
-  t.deepEqual(cs, [c('T', 'T')])
-})
-
-test('anywhere', t => {
-  t.plan(1)
-  const cs = internal.Comments(`
-    const $ = () => {
-      /** test1 */
-      const w = 1
-
-      /** test2 */
-      function f(x) {
-        return x * x
-      }
-
-      /** test3 */
-      return f(f(w))
-    }
-  `)
-  t.deepEqual(cs, [c('test1', 'w'), c('test2', 'f'), c('test3',  null)])
-})
diff --git a/tsconfig.json b/tsconfig.json
index b2720aa..a8da009 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,21 +1,23 @@
 {
-    "compilerOptions": {
-        "outDir": "./dist",
-        "sourceMap": true,
-        "noImplicitAny": true,
-        "strict": true,
-        "target": "es6",
-        "module": "commonjs",
-        "moduleResolution": "node",
-        "lib": ["es6"],
-        "noEmitOnError": true,
-        "allowUnreachableCode": true
-    },
-    "include": [
-        "src",
-        "test"
+  "compilerOptions": {
+    "outDir": "./dist",
+    "sourceMap": true,
+    "noImplicitAny": true,
+    "strict": true,
+    "target": "es6",
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "lib": [
+      "es6"
     ],
-    "parcelTsPluginOptions": {
-        "transpileOnly": false
-    }
+    "noEmitOnError": true,
+    "allowUnreachableCode": true
+  },
+  "include": [
+    "src",
+    "test"
+  ],
+  "parcelTsPluginOptions": {
+    "transpileOnly": false
+  }
 }
diff --git a/unused-test-files/c.ts b/unused-test-files/c.ts
deleted file mode 100644
index cbd8a2a..0000000
--- a/unused-test-files/c.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-class X {
-  J: {
-    u: number
-  } = {
-    u: 1
-  }
-}
diff --git a/unused-test-files/ex.ts b/unused-test-files/ex.ts
deleted file mode 100644
index 73be18f..0000000
--- a/unused-test-files/ex.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export const j = 1
-export module A {
-  export const c = 1
-  export const s = 1
-  export interface J {
-    u: number
-  }
-}
-export namespace N {
-  export const d = 1
-}
diff --git a/unused-test-files/example.ts b/unused-test-files/example.ts
deleted file mode 100644
index bf57689..0000000
--- a/unused-test-files/example.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-
-/** I */
-export interface I {
-  /** k */
-  k: number
-}
-
-/** H */
-interface H {
-  /** k */
-  k: number
-}
-
-/** C */
-export class C {
-  /** f */
-  f = 1
-  /** g */
-  g: number
-  /** new */
-  constructor(x: number) { this.g = x }
-  /** s */
-  static s(y: number): I { return {k: y} }
-  /** m */
-  m(z: number): I { return {k: z} }
-}
-
-/** T */
-type T = C
-
-/** c */
-const c = new C(1)
-
-/** M */
-export module M {
-  /** MI */
-  export interface MI {
-    /** M k */
-    k: number
-  }
-
-  /** MC */
-  export class MC {
-    /** M f */
-    f = 1
-    /** M g */
-    g: number
-    /** M new */
-    constructor(x: number) { this.g = x }
-    /** M s */
-    static s(y: number): MI { return {k: y} }
-    /** M m */
-    m(z: number): MI { return {k: z} }
-
-    /** M p */
-    private p(z: number): MI { return {k: z} }
-  }
-
-  type MT = MC
-
-  export const c = new MC(1)
-}
-
-/** HM */
-module HM {
-  /** HMI */
-  interface HMI {
-    /** HM k */
-    k: number
-  }
-
-  /** HMC */
-  class HMC {
-    /** HM f */
-    f = 1
-    /** HM g */
-    g: number
-    /** HM new */
-    constructor(x: number) { this.g = x }
-    /** HM s */
-    static s(y: number): HMI { return {k: y} }
-    /** HM m */
-    m(z: number): HMI { return {k: z} }
-  }
-
-  type HMT = HMC
-
-  const c = new HMC(1)
-}
diff --git a/unused-test-files/i.ts b/unused-test-files/i.ts
deleted file mode 100644
index fe87196..0000000
--- a/unused-test-files/i.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/** The awesome iface
-
-1 // => 1
-
-This is not indentend
-*/
-export interface B {
-  b: number
-}
-
-export class C {
-  /**
-
-  1 // => 1
-  much.to.test()
-  yes()
-
-
-
-  more stuff*/
-  static boo()  { return 1 }
-}
-
diff --git a/unused-test-files/main2.ts b/unused-test-files/main2.ts
deleted file mode 100644
index 03a9916..0000000
--- a/unused-test-files/main2.ts
+++ /dev/null
@@ -1,417 +0,0 @@
-import * as babylon from 'babylon'
-import * as babel from 'babel-types'
-import generate from 'babel-generator'
-import * as fs from 'fs'
-
-import * as util from 'util'
-
-util.inspect.defaultOptions.depth = 5
-util.inspect.defaultOptions.colors = true
-const pp = (x: any) => (console.dir(x), console.log())
-
-const opts: babylon.BabylonOptions = {plugins: [
-    'estree' ,
-    'jsx' ,
-    'flow' ,
-    'classConstructorCall' ,
-    'doExpressions' ,
-    'objectRestSpread' ,
-    'decorators' ,
-    'classProperties' ,
-    'exportExtensions' ,
-    'asyncGenerators' ,
-    'functionBind' ,
-    'functionSent' ,
-    'dynamicImport']}
-
-
-
-
-const is_doctest = (s: string) => s.match(/\/\/[ \t]*=>/) != null
-const doctest_rhs = (s: string) => s.match(/^\s*[ \t]*=>((.|\n)*)$/m)
-
-interface Equality {
-  tag: '==',
-  lhs: string,
-  rhs: string
-}
-
-interface Statement {
-  tag: 'Statement'
-  stmt: string,
-}
-
-type Script = (Statement | Equality)[]
-
-export function test(s: string): Script {
-  const lin = (ast: babel.Node) => generate(ast ,{comments: false, compact: true}).code
-  const ast = babylon.parse(s, opts)
-  return ast.program.body.map((stmt): Statement | Equality => {
-    const comment = (stmt.trailingComments || [{value: ''}])[0].value
-    const rhs = doctest_rhs(comment)
-    if (babel.isExpressionStatement(stmt) && rhs) {
-      const rhs = babylon.parseExpression(comment.replace(/^\s*=>/, ''))
-      return {
-        tag: '==',
-        lhs: lin(stmt.expression),
-        rhs: lin(rhs),
-      }
-    } else {
-      return {tag: 'Statement', stmt: lin(stmt)}
-    }
-  })
-}
-
-export function tests(docstring: string): Script[] {
-  const out = [] as Script[]
-  docstring.split(/\n\n+/m).forEach(s => {
-    if (is_doctest(s)) {
-      out.push(test(s))
-    }
-  })
-  return out
-}
-
-
-export interface Comment {
-  comment: string,
-  context: string | null
-}
-
-export function Comments(s: string): Comment[] {
-  const out: Comment[] = []
-  function add_comment(c: babel.Comment, context: string | null) {
-    out.push({comment: c.value, context})
-  }
-
-  const ast = babylon.parse(s, opts)
-
-  traverse(ast, node => {
-    let context: null | string = null
-    /*
-    if (babel.isDeclaration(node)) {
-      util.inspect.defaultOptions.depth = 1
-      pp({declaration: node})
-    }
-    if (babel.isMethod(node)) {
-      util.inspect.defaultOptions.depth = 1
-      pp({method: node})
-    }
-    if (isObject(node) && 'type' in node && node.type == 'MethodDefinition') {
-      util.inspect.defaultOptions.depth = 2
-      pp({methodDefn: node})
-    }
-    if (isObject(node) && 'type' in node && node.type == 'ObjectProperty') {
-      util.inspect.defaultOptions.depth = 2
-      pp({objProp: node})
-    }
-    if (isObject(node) && 'type' in node && node.type == 'ObjectMethod') {
-      util.inspect.defaultOptions.depth = 2
-      pp({objMethod: node})
-    }
-    if (isObject(node) && 'type' in node && node.type == 'ObjectExpression') {
-      util.inspect.defaultOptions.depth = 5
-      pp({objExpr: node})
-    }
-    if (isObject(node) && 'type' in node && node.type == 'Property') {
-      util.inspect.defaultOptions.depth = 5
-      pp({property: node})
-    }
-    */
-    // context = node as any
-    function has_key(x: any): x is {key: babel.Identifier} {
-      return isObject(x) && 'key' in x && babel.isIdentifier((x as any).key)
-    }
-    function has_id(x: any): x is {id: babel.Identifier} {
-      return isObject(x) && 'id' in x && babel.isIdentifier((x as any).id)
-    }
-    if (babel.isVariableDeclaration(node)) {
-      const ds = node.declarations
-      if (ds.length == 1) {
-        const d = ds[0]
-        if (has_id(d)) {
-          context = d.id.name
-        }
-      }
-    } else if (has_id(node)) {
-      context = node.id.name
-    } else if (has_key(node)) {
-      context = node.key.name
-    }
-    if (isObject(node)) {
-      function add_comments(s: string) {
-        if (s in node && Array.isArray(node[s])) {
-          (node[s] as any[]).forEach(c => {
-            if ('type' in c) {
-              if (c.type == 'CommentBlock' || c.type == 'CommentLine') {
-                add_comment(c, context)
-                if (context == null) {
-                  // pp({c, node})
-                }
-              }
-            }
-          })
-        }
-      }
-      if (isObject(node)) {
-        add_comments('leadingComments')
-        add_comments('innerComments')
-        // add_comments('trailingComments')
-      }
-    }
-  })
-
-  return out
-}
-
-function isObject(x: any): x is object {
-  return x !== null && typeof x === 'object' && !Array.isArray(x)
-}
-
-function traverse(x: any, f: (x: any) => void): void {
-  f(x)
-    if (Array.isArray(x)) {
-      x.map(y => traverse(y, f))
-    }
-    if (isObject(x)) {
-      for (const k in x) {
-        traverse((x as any)[k], f)
-      }
-    }
-
-}
-
-false && pp(Comments(`/** test */ function f(x: string): number { return 1 }
-
-class Apa {
-  /** something something */
-
-  /** attached to nothing! */
-
-  /** returns important stuff
-
-  j(5) // => 6
-
-  j(9) // => 10
-  */
-  j(x: number) {
-    /** important stuff */
-    return x + 1
-  }
-}
-
-interface B {
-  /** x docstring */
-  x: 1
-}
-
-/** u docstring */
-const u = {
-  /** ux docstring */
-  ux: 1
-}
-`))
-
-function script(filename: string, s: string): string[] {
-  return []
-  /*
-  const pwoc = ts.createPrinter({removeComments: true})
-  const f = ts.createSourceFile('_doctest_' + filename, s, ts.ScriptTarget.ES5, true, ts.ScriptKind.TS)
-  const out =
-    f.statements.map(
-      (now, i) => {
-        if (ts.isExpressionStatement(now)) {
-          const next = f.statements[i+1] // zip with next
-          const [a, z] = next ? [next.pos, next.end] : [now.end, f.end]
-          const after = f.text.slice(a, z)
-          const m = doctest_rhs(after)
-          if (m && m[1]) {
-            const lhs = pwoc.printNode(ts.EmitHint.Expression, now.expression, f)
-            const rhs = m[1].trim()
-            return 't.deepEqual(' + lhs + ', ' + rhs + ', ' + JSON.stringify(rhs) + ')'
-          }
-        }
-        return pwoc.printNode(ts.EmitHint.Unspecified, now, f)
-      })
-  return out
-  */
-}
-
-/*
-const filename = 'unk.ts'
-
-r.comments.map(d => {
-  d.value.split(/\n\n+/m).map(s => {
-    let tests = 0
-    if (is_doctest(s)) {
-      // todo: typecheck s now
-      const name = 'unk'
-      console.log(
-        'test(' + JSON.stringify(name + ' ' + ++tests) + ', t => {',
-        ...script(filename, s).map(l => '  ' + l),
-        '})',
-        ''
-      )
-    }
-  })
-})
-
-pp(r.program)
-pp(r.comments)
-*/
-
-
-/*
-
-
-function script(filename: string, s: string): string[] {
-  const pwoc = ts.createPrinter({removeComments: true})
-  const f = ts.createSourceFile('_doctest_' + filename, s, ts.ScriptTarget.ES5, true, ts.ScriptKind.TS)
-  const out =
-    f.statements.map(
-      (now, i) => {
-        if (ts.isExpressionStatement(now)) {
-          const next = f.statements[i+1] // zip with next
-          const [a, z] = next ? [next.pos, next.end] : [now.end, f.end]
-          const after = f.text.slice(a, z)
-          const m = doctest_rhs(after)
-          if (m && m[1]) {
-            const lhs = pwoc.printNode(ts.EmitHint.Expression, now.expression, f)
-            const rhs = m[1].trim()
-            return 't.deepEqual(' + lhs + ', ' + rhs + ', ' + JSON.stringify(rhs) + ')'
-          }
-        }
-        return pwoc.printNode(ts.EmitHint.Unspecified, now, f)
-      })
-  return out
-}
-
-function test_script_one(filename: string, d: Def): string[] {
-  const out = [] as string[]
-  let tests = 0
-  d.doc.split(/\n\n+/m).map(s => {
-    if (is_doctest(s)) {
-      // todo: typecheck s now
-      out.push(
-        'test(' + JSON.stringify(d.name + ' ' + ++tests) + ', t => {',
-        ...script(filename, s).map(l => '  ' + l),
-        '})',
-        ''
-      )
-    }
-  })
-  return out
-}
-
-function test_script(top: Top) {
-  return ["import {test} from 'ava'"].concat(...top.map(
-    ({filename, defs}) => walk(defs, (d) => test_script_one(filename, d)))
-  )
-}
-
-
-function prettyKind(kind: string) {
-  return kind.replace('Declaration', '').toLowerCase()
-}
-
-function toc_one(def: Def, i: number): string[] {
-  if (def.exported || i > 0) {
-    return [
-      replicate(i, '  ').join('') +
-      '* ' +
-      (def.children.length == 0 ? '' : (prettyKind(def.kind) + ' ')) +
-      def.name
-    ]
-  } else {
-    return []
-  }
-}
-
-function toc(top: Top): string[] {
-  return flatten(top.map(({defs}) => walk(defs, toc_one)))
-}
-
-function doc_one(def: Def, i: number): string[] {
-  const out = [] as string[]
-  if (def.exported || i > 0) {
-    let indent = ''
-    if (def.children.length == 0) {
-      //const method = (def.kind == 'MethodDeclaration') ? 'method ' : ''
-      out.push('* ' + '**' + def.name + '**: `' + def.type + '`')
-      indent = '  '
-    } else {
-      out.push('### ' + prettyKind(def.kind) + ' ' + def.name)
-    }
-    def.doc.split(/\n\n+/).forEach(s => {
-      out.push('')
-      if (is_doctest(s)) {
-        out.push(indent + '```typescript')
-      }
-      const lines = s.split('\n')
-      lines.forEach(line => out.push(indent + line))
-      if (is_doctest(s)) {
-        out.push(indent + '```')
-      }
-    })
-  }
-  return out
-}
-
-function doc(top: Top) {
-  return flatten(top.map(({defs}) => walk(defs, doc_one)))
-}
-
-const filenames = [] as string[]
-const argv = process.argv.slice(2)
-const outputs = [] as ((top: Top) => string[])[]
-
-{
-  let program: ts.Program
-  let verbose = false
-  for (let i = 0; i < argv.length; i++) {
-    const arg = argv[i]
-    if (arg == '-t' || arg == '--test-script') {
-      outputs.push(test_script)
-    } else if (arg == '-d' || arg == '--doc') {
-      outputs.push(doc)
-    } else if (arg == '--toc' || arg == '--toc') {
-      outputs.push(toc)
-    } else if (arg == '-i' || arg == '--include') {
-      outputs.push(_top => [fs.readFileSync(argv[++i]).toString()])
-    } else if (arg == '-s' || arg == '--string') {
-      outputs.push(_top => [argv[++i]])
-    } else {
-      filenames.push(arg)
-    }
-  }
-
-  if (outputs.length == 0) {
-    console.log(`typescript-doctests <args>
-      Each entry in <args> may be:
-        [-t|--test-script]        // write tape test script on stdout
-        [-d|--doc]                // write markdown api documentation on stdout
-        [--toc]                   // write markdown table of contents on stdout
-        [-i|--include] FILENAME   // write the contents of a file on stdout
-        [-s|--string] STRING      // write a string literally on stdout
-        FILENAME                  // typescript files to look for docstrings in
-
-      Example usages:
-
-        typescript-doctests src/*.ts -s 'import * as App from "../src/App"' -t > test/App.doctest.ts
-
-        typescript-doctests src/*.ts -i Header.md --toc --doc -i Footer.md > README.md
-    `)
-    process.exit(1)
-  } else {
-    program = ts.createProgram(filenames, {
-      target: ts.ScriptTarget.ES5,
-      module: ts.ModuleKind.CommonJS
-    })
-    const top = generateDocumentation(program, filenames)
-
-    outputs.forEach(m => m(top).forEach(line => console.log(line)))
-  }
-}
-
-
-*/
diff --git a/unused-test-files/visitor_test.ts b/unused-test-files/visitor_test.ts
deleted file mode 100644
index c73155b..0000000
--- a/unused-test-files/visitor_test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import * as ts from 'typescript'
-
-const pwoc = ts.createPrinter({removeComments: true})
-
-function script(s: string): string {
-  const f = ts.createSourceFile('test.ts', s, ts.ScriptTarget.ES5, true, ts.ScriptKind.TS)
-  const out =
-    f.statements.map(
-      (now, i) => {
-        if (ts.isExpressionStatement(now)) {
-          const next = f.statements[i+1] // zip with next
-          const [a, z] = next ? [next.pos, next.end] : [now.end, f.end]
-          const after = f.text.slice(a, z)
-          const m = after.match(/^\s*\/\/[ \t]*=>([^\n]*)/m)
-          if (m && m[1]) {
-            const lhs = pwoc.printNode(ts.EmitHint.Expression, now.expression, f)
-            const rhs = m[1].trim()
-            return 'assert.deepEqual(' + lhs + ', ' + rhs + ', ' + JSON.stringify(rhs) + ')'
-          }
-        }
-        return pwoc.printNode(ts.EmitHint.Unspecified, now, f)
-      })
-  return out.join('\n')
-}
-
-const s = `
-  const a = 1
-  a
-  // one more
-  // => 1
-  let b = 2
-  a + 1 // => 2
-  // that's all
-  a + b
-  // that's all
-  // => 3
-  function apa(bepa) {
-    return 1
-  }
-  a++
-  b++
-  // hehe // => 5
-  a // => 4
-`
-
-console.log(script(s))
diff --git a/yarn.lock b/yarn.lock
index fcddfdf..a4151b3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,11 @@
 # yarn lockfile v1
 
 
+"@types/chai@^4.3.0":
+  "integrity" "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw=="
+  "resolved" "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz"
+  "version" "4.3.0"
+
 "@types/chokidar@^1.7.5":
   "integrity" "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ=="
   "resolved" "https://registry.npmjs.org/@types/chokidar/-/chokidar-1.7.5.tgz"
@@ -20,6 +25,11 @@
   "resolved" "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz"
   "version" "1.2.0"
 
+"@types/mocha@^9.1.0":
+  "integrity" "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg=="
+  "resolved" "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz"
+  "version" "9.1.0"
+
 "@types/node@*", "@types/node@^9.4.6":
   "integrity" "sha512-5lhC7QM2J3b/+epdwaNfRuG2peN4c9EX+mkd27+SqLKhJSdswHTZvc4aZLBZChi+Wo32+E1DeMZs0fSpu/uBXQ=="
   "resolved" "https://registry.npmjs.org/@types/node/-/node-9.6.51.tgz"
@@ -32,11 +42,26 @@
   dependencies:
     "@types/node" "*"
 
+"@ungap/promise-all-settled@1.1.2":
+  "integrity" "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
+  "resolved" "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz"
+  "version" "1.1.2"
+
+"ansi-colors@4.1.1":
+  "integrity" "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
+  "resolved" "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz"
+  "version" "4.1.1"
+
 "ansi-regex@^2.0.0":
   "integrity" "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
   "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
   "version" "2.1.1"
 
+"ansi-regex@^5.0.1":
+  "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+  "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
+  "version" "5.0.1"
+
 "ansi-styles@^2.2.1":
   "integrity" "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
   "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
@@ -49,13 +74,27 @@
   dependencies:
     "color-convert" "^1.9.0"
 
-"anymatch@^2.0.0":
-  "integrity" "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw=="
-  "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz"
-  "version" "2.0.0"
+"ansi-styles@^4.0.0":
+  "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
+  "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+  "version" "4.3.0"
   dependencies:
-    "micromatch" "^3.1.4"
-    "normalize-path" "^2.1.1"
+    "color-convert" "^2.0.1"
+
+"ansi-styles@^4.1.0":
+  "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
+  "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+  "version" "4.3.0"
+  dependencies:
+    "color-convert" "^2.0.1"
+
+"anymatch@~3.1.2":
+  "integrity" "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg=="
+  "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz"
+  "version" "3.1.2"
+  dependencies:
+    "normalize-path" "^3.0.0"
+    "picomatch" "^2.0.4"
 
 "argparse@^1.0.7":
   "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="
@@ -64,68 +103,30 @@
   dependencies:
     "sprintf-js" "~1.0.2"
 
-"arr-diff@^4.0.0":
-  "integrity" "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
-  "resolved" "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz"
-  "version" "4.0.0"
-
-"arr-flatten@^1.1.0":
-  "integrity" "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
-  "resolved" "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz"
-  "version" "1.1.0"
-
-"arr-union@^3.1.0":
-  "integrity" "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
-  "resolved" "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz"
-  "version" "3.1.0"
-
-"array-unique@^0.3.2":
-  "integrity" "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
-  "resolved" "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz"
-  "version" "0.3.2"
+"argparse@^2.0.1":
+  "integrity" "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+  "resolved" "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
+  "version" "2.0.1"
 
 "arrify@^1.0.0":
   "integrity" "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
   "resolved" "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
   "version" "1.0.1"
 
-"assign-symbols@^1.0.0":
-  "integrity" "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
-  "resolved" "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz"
-  "version" "1.0.0"
-
-"async-each@^1.0.1":
-  "integrity" "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
-  "resolved" "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz"
-  "version" "1.0.3"
-
-"atob@^2.1.1":
-  "integrity" "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
-  "resolved" "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz"
-  "version" "2.1.2"
+"assertion-error@^1.1.0":
+  "integrity" "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
+  "resolved" "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz"
+  "version" "1.1.0"
 
 "balanced-match@^1.0.0":
   "integrity" "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
   "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
   "version" "1.0.0"
 
-"base@^0.11.1":
-  "integrity" "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg=="
-  "resolved" "https://registry.npmjs.org/base/-/base-0.11.2.tgz"
-  "version" "0.11.2"
-  dependencies:
-    "cache-base" "^1.0.1"
-    "class-utils" "^0.3.5"
-    "component-emitter" "^1.2.1"
-    "define-property" "^1.0.0"
-    "isobject" "^3.0.1"
-    "mixin-deep" "^1.2.0"
-    "pascalcase" "^0.1.1"
-
-"binary-extensions@^1.0.0":
-  "integrity" "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
-  "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz"
-  "version" "1.13.1"
+"binary-extensions@^2.0.0":
+  "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+  "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
+  "version" "2.2.0"
 
 "brace-expansion@^1.1.7":
   "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="
@@ -135,41 +136,40 @@
     "balanced-match" "^1.0.0"
     "concat-map" "0.0.1"
 
-"braces@^2.3.1", "braces@^2.3.2":
-  "integrity" "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w=="
-  "resolved" "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz"
-  "version" "2.3.2"
+"braces@~3.0.2":
+  "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="
+  "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
+  "version" "3.0.2"
   dependencies:
-    "arr-flatten" "^1.1.0"
-    "array-unique" "^0.3.2"
-    "extend-shallow" "^2.0.1"
-    "fill-range" "^4.0.0"
-    "isobject" "^3.0.1"
-    "repeat-element" "^1.1.2"
-    "snapdragon" "^0.8.1"
-    "snapdragon-node" "^2.0.1"
-    "split-string" "^3.0.2"
-    "to-regex" "^3.0.1"
+    "fill-range" "^7.0.1"
+
+"browser-stdout@1.3.1":
+  "integrity" "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
+  "resolved" "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz"
+  "version" "1.3.1"
 
 "buffer-from@^1.0.0":
   "integrity" "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
   "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz"
   "version" "1.1.1"
 
-"cache-base@^1.0.1":
-  "integrity" "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ=="
-  "resolved" "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz"
-  "version" "1.0.1"
+"camelcase@^6.0.0":
+  "integrity" "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
+  "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
+  "version" "6.3.0"
+
+"chai@^4.3.6":
+  "integrity" "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q=="
+  "resolved" "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz"
+  "version" "4.3.6"
   dependencies:
-    "collection-visit" "^1.0.0"
-    "component-emitter" "^1.2.1"
-    "get-value" "^2.0.6"
-    "has-value" "^1.0.0"
-    "isobject" "^3.0.1"
-    "set-value" "^2.0.0"
-    "to-object-path" "^0.3.0"
-    "union-value" "^1.0.0"
-    "unset-value" "^1.0.0"
+    "assertion-error" "^1.1.0"
+    "check-error" "^1.0.2"
+    "deep-eql" "^3.0.1"
+    "get-func-name" "^2.0.0"
+    "loupe" "^2.3.1"
+    "pathval" "^1.1.1"
+    "type-detect" "^4.0.5"
 
 "chalk@^1.1.1":
   "integrity" "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg="
@@ -191,42 +191,42 @@
     "escape-string-regexp" "^1.0.5"
     "supports-color" "^5.3.0"
 
-"chokidar@^2.0.1":
-  "integrity" "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg=="
-  "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz"
-  "version" "2.1.8"
+"chalk@^4.1.0":
+  "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="
+  "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
+  "version" "4.1.2"
   dependencies:
-    "anymatch" "^2.0.0"
-    "async-each" "^1.0.1"
-    "braces" "^2.3.2"
-    "glob-parent" "^3.1.0"
-    "inherits" "^2.0.3"
-    "is-binary-path" "^1.0.0"
-    "is-glob" "^4.0.0"
-    "normalize-path" "^3.0.0"
-    "path-is-absolute" "^1.0.0"
-    "readdirp" "^2.2.1"
-    "upath" "^1.1.1"
+    "ansi-styles" "^4.1.0"
+    "supports-color" "^7.1.0"
+
+"check-error@^1.0.2":
+  "integrity" "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
+  "resolved" "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz"
+  "version" "1.0.2"
+
+"chokidar@3.5.3":
+  "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="
+  "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
+  "version" "3.5.3"
+  dependencies:
+    "anymatch" "~3.1.2"
+    "braces" "~3.0.2"
+    "glob-parent" "~5.1.2"
+    "is-binary-path" "~2.1.0"
+    "is-glob" "~4.0.1"
+    "normalize-path" "~3.0.0"
+    "readdirp" "~3.6.0"
   optionalDependencies:
-    "fsevents" "^1.2.7"
+    "fsevents" "~2.3.2"
 
-"class-utils@^0.3.5":
-  "integrity" "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg=="
-  "resolved" "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz"
-  "version" "0.3.6"
+"cliui@^7.0.2":
+  "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="
+  "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz"
+  "version" "7.0.4"
   dependencies:
-    "arr-union" "^3.1.0"
-    "define-property" "^0.2.5"
-    "isobject" "^3.0.0"
-    "static-extend" "^0.1.1"
-
-"collection-visit@^1.0.0":
-  "integrity" "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA="
-  "resolved" "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "map-visit" "^1.0.0"
-    "object-visit" "^1.0.0"
+    "string-width" "^4.2.0"
+    "strip-ansi" "^6.0.0"
+    "wrap-ansi" "^7.0.0"
 
 "color-convert@^1.9.0":
   "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="
@@ -235,42 +235,51 @@
   dependencies:
     "color-name" "1.1.3"
 
+"color-convert@^2.0.1":
+  "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="
+  "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
+  "version" "2.0.1"
+  dependencies:
+    "color-name" "~1.1.4"
+
+"color-name@~1.1.4":
+  "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+  "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+  "version" "1.1.4"
+
 "color-name@1.1.3":
   "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
   "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
   "version" "1.1.3"
 
-"component-emitter@^1.2.1":
-  "integrity" "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
-  "resolved" "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
-  "version" "1.3.0"
-
 "concat-map@0.0.1":
   "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
   "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
   "version" "0.0.1"
 
-"copy-descriptor@^0.1.0":
-  "integrity" "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
-  "resolved" "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz"
-  "version" "0.1.1"
-
 "core-util-is@~1.0.0":
   "integrity" "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
   "resolved" "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
   "version" "1.0.2"
 
-"debug@^2.2.0", "debug@^2.3.3":
-  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
-  "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
-  "version" "2.6.9"
+"debug@4.3.3":
+  "integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="
+  "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
+  "version" "4.3.3"
   dependencies:
-    "ms" "2.0.0"
+    "ms" "2.1.2"
 
-"decode-uri-component@^0.2.0":
-  "integrity" "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
-  "resolved" "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz"
-  "version" "0.2.0"
+"decamelize@^4.0.0":
+  "integrity" "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="
+  "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz"
+  "version" "4.0.0"
+
+"deep-eql@^3.0.1":
+  "integrity" "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw=="
+  "resolved" "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz"
+  "version" "3.0.1"
+  dependencies:
+    "type-detect" "^4.0.0"
 
 "deep-equal@~0.1.0":
   "integrity" "sha1-skbCuApXCkfBG+HZvRBw7IeLh84="
@@ -289,28 +298,6 @@
   dependencies:
     "object-keys" "^1.0.12"
 
-"define-property@^0.2.5":
-  "integrity" "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY="
-  "resolved" "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz"
-  "version" "0.2.5"
-  dependencies:
-    "is-descriptor" "^0.1.0"
-
-"define-property@^1.0.0":
-  "integrity" "sha1-dp66rz9KY6rTr56NMEybvnm/sOY="
-  "resolved" "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "is-descriptor" "^1.0.0"
-
-"define-property@^2.0.2":
-  "integrity" "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ=="
-  "resolved" "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "is-descriptor" "^1.0.2"
-    "isobject" "^3.0.1"
-
 "defined@~0.0.0", "defined@0.0.0":
   "integrity" "sha1-817qfXBekzuvE7LwOz+D2SFAOz4="
   "resolved" "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz"
@@ -331,6 +318,11 @@
   "resolved" "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz"
   "version" "3.5.0"
 
+"diff@5.0.0":
+  "integrity" "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
+  "resolved" "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz"
+  "version" "5.0.0"
+
 "dom-walk@^0.1.0":
   "integrity" "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
   "resolved" "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz"
@@ -341,6 +333,11 @@
   "resolved" "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz"
   "version" "0.1.1"
 
+"emoji-regex@^8.0.0":
+  "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+  "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
+  "version" "8.0.0"
+
 "es-abstract@^1.5.0":
   "integrity" "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg=="
   "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz"
@@ -362,11 +359,21 @@
     "is-date-object" "^1.0.1"
     "is-symbol" "^1.0.2"
 
+"escalade@^3.1.1":
+  "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
+  "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"
+  "version" "3.1.1"
+
 "escape-string-regexp@^1.0.2", "escape-string-regexp@^1.0.5":
   "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
   "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
   "version" "1.0.5"
 
+"escape-string-regexp@4.0.0":
+  "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
+  "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
+  "version" "4.0.0"
+
 "esprima@^4.0.0":
   "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
   "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
@@ -377,56 +384,6 @@
   "resolved" "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz"
   "version" "1.1.2"
 
-"expand-brackets@^2.1.4":
-  "integrity" "sha1-t3c14xXOMPa27/D4OwQVGiJEliI="
-  "resolved" "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz"
-  "version" "2.1.4"
-  dependencies:
-    "debug" "^2.3.3"
-    "define-property" "^0.2.5"
-    "extend-shallow" "^2.0.1"
-    "posix-character-classes" "^0.1.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
-"extend-shallow@^2.0.1":
-  "integrity" "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8="
-  "resolved" "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "is-extendable" "^0.1.0"
-
-"extend-shallow@^3.0.0":
-  "integrity" "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg="
-  "resolved" "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "assign-symbols" "^1.0.0"
-    "is-extendable" "^1.0.1"
-
-"extend-shallow@^3.0.2":
-  "integrity" "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg="
-  "resolved" "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "assign-symbols" "^1.0.0"
-    "is-extendable" "^1.0.1"
-
-"extglob@^2.0.4":
-  "integrity" "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw=="
-  "resolved" "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "array-unique" "^0.3.2"
-    "define-property" "^1.0.0"
-    "expand-brackets" "^2.1.4"
-    "extend-shallow" "^2.0.1"
-    "fragment-cache" "^0.2.1"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
 "faucet@^0.0.1":
   "integrity" "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw="
   "resolved" "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz"
@@ -448,15 +405,25 @@
     "escape-string-regexp" "^1.0.5"
     "object-assign" "^4.1.0"
 
-"fill-range@^4.0.0":
-  "integrity" "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc="
-  "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz"
-  "version" "4.0.0"
+"fill-range@^7.0.1":
+  "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="
+  "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
+  "version" "7.0.1"
   dependencies:
-    "extend-shallow" "^2.0.1"
-    "is-number" "^3.0.0"
-    "repeat-string" "^1.6.1"
-    "to-regex-range" "^2.1.0"
+    "to-regex-range" "^5.0.1"
+
+"find-up@5.0.0":
+  "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="
+  "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
+  "version" "5.0.0"
+  dependencies:
+    "locate-path" "^6.0.0"
+    "path-exists" "^4.0.0"
+
+"flat@^5.0.2":
+  "integrity" "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="
+  "resolved" "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz"
+  "version" "5.0.2"
 
 "for-each@~0.3.3":
   "integrity" "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw=="
@@ -465,18 +432,6 @@
   dependencies:
     "is-callable" "^1.1.3"
 
-"for-in@^1.0.2":
-  "integrity" "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
-  "resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz"
-  "version" "1.0.2"
-
-"fragment-cache@^0.2.1":
-  "integrity" "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk="
-  "resolved" "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz"
-  "version" "0.2.1"
-  dependencies:
-    "map-cache" "^0.2.2"
-
 "fs.realpath@^1.0.0":
   "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
   "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
@@ -487,18 +442,22 @@
   "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
   "version" "1.1.1"
 
-"get-value@^2.0.3", "get-value@^2.0.6":
-  "integrity" "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
-  "resolved" "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz"
-  "version" "2.0.6"
+"get-caller-file@^2.0.5":
+  "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+  "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
+  "version" "2.0.5"
 
-"glob-parent@^3.1.0":
-  "integrity" "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4="
-  "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz"
-  "version" "3.1.0"
+"get-func-name@^2.0.0":
+  "integrity" "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
+  "resolved" "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz"
+  "version" "2.0.0"
+
+"glob-parent@~5.1.2":
+  "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="
+  "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+  "version" "5.1.2"
   dependencies:
-    "is-glob" "^3.1.0"
-    "path-dirname" "^1.0.0"
+    "is-glob" "^4.0.1"
 
 "glob@~7.1.4":
   "integrity" "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A=="
@@ -512,6 +471,18 @@
     "once" "^1.3.0"
     "path-is-absolute" "^1.0.0"
 
+"glob@7.2.0":
+  "integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="
+  "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz"
+  "version" "7.2.0"
+  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"
+
 "global@^4.3.2":
   "integrity" "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w=="
   "resolved" "https://registry.npmjs.org/global/-/global-4.4.0.tgz"
@@ -520,10 +491,10 @@
     "min-document" "^2.19.0"
     "process" "^0.11.10"
 
-"graceful-fs@^4.1.11":
-  "integrity" "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q=="
-  "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz"
-  "version" "4.2.2"
+"growl@1.10.5":
+  "integrity" "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
+  "resolved" "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz"
+  "version" "1.10.5"
 
 "has-ansi@^2.0.0":
   "integrity" "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE="
@@ -537,42 +508,16 @@
   "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
   "version" "3.0.0"
 
+"has-flag@^4.0.0":
+  "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+  "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
+  "version" "4.0.0"
+
 "has-symbols@^1.0.0":
   "integrity" "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
   "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz"
   "version" "1.0.0"
 
-"has-value@^0.3.1":
-  "integrity" "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8="
-  "resolved" "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz"
-  "version" "0.3.1"
-  dependencies:
-    "get-value" "^2.0.3"
-    "has-values" "^0.1.4"
-    "isobject" "^2.0.0"
-
-"has-value@^1.0.0":
-  "integrity" "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc="
-  "resolved" "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "get-value" "^2.0.6"
-    "has-values" "^1.0.0"
-    "isobject" "^3.0.0"
-
-"has-values@^0.1.4":
-  "integrity" "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
-  "resolved" "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz"
-  "version" "0.1.4"
-
-"has-values@^1.0.0":
-  "integrity" "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8="
-  "resolved" "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "is-number" "^3.0.0"
-    "kind-of" "^4.0.0"
-
 "has@^1.0.1", "has@^1.0.3", "has@~1.0.3":
   "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="
   "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
@@ -580,6 +525,11 @@
   dependencies:
     "function-bind" "^1.1.1"
 
+"he@1.2.0":
+  "integrity" "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+  "resolved" "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
+  "version" "1.2.0"
+
 "inflight@^1.0.4":
   "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk="
   "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
@@ -588,92 +538,29 @@
     "once" "^1.3.0"
     "wrappy" "1"
 
-"inherits@^2.0.3", "inherits@~2.0.1", "inherits@~2.0.3", "inherits@~2.0.4", "inherits@2":
+"inherits@~2.0.1", "inherits@~2.0.3", "inherits@~2.0.4", "inherits@2":
   "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
   "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   "version" "2.0.4"
 
-"is-accessor-descriptor@^0.1.6":
-  "integrity" "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY="
-  "resolved" "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz"
-  "version" "0.1.6"
+"is-binary-path@~2.1.0":
+  "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="
+  "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
+  "version" "2.1.0"
   dependencies:
-    "kind-of" "^3.0.2"
-
-"is-accessor-descriptor@^1.0.0":
-  "integrity" "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ=="
-  "resolved" "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "kind-of" "^6.0.0"
-
-"is-binary-path@^1.0.0":
-  "integrity" "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg="
-  "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "binary-extensions" "^1.0.0"
-
-"is-buffer@^1.1.5":
-  "integrity" "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
-  "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz"
-  "version" "1.1.6"
+    "binary-extensions" "^2.0.0"
 
 "is-callable@^1.1.3", "is-callable@^1.1.4":
   "integrity" "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
   "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz"
   "version" "1.1.4"
 
-"is-data-descriptor@^0.1.4":
-  "integrity" "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y="
-  "resolved" "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz"
-  "version" "0.1.4"
-  dependencies:
-    "kind-of" "^3.0.2"
-
-"is-data-descriptor@^1.0.0":
-  "integrity" "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ=="
-  "resolved" "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "kind-of" "^6.0.0"
-
 "is-date-object@^1.0.1":
   "integrity" "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
   "resolved" "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz"
   "version" "1.0.1"
 
-"is-descriptor@^0.1.0":
-  "integrity" "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="
-  "resolved" "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz"
-  "version" "0.1.6"
-  dependencies:
-    "is-accessor-descriptor" "^0.1.6"
-    "is-data-descriptor" "^0.1.4"
-    "kind-of" "^5.0.0"
-
-"is-descriptor@^1.0.0", "is-descriptor@^1.0.2":
-  "integrity" "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg=="
-  "resolved" "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "is-accessor-descriptor" "^1.0.0"
-    "is-data-descriptor" "^1.0.0"
-    "kind-of" "^6.0.2"
-
-"is-extendable@^0.1.0", "is-extendable@^0.1.1":
-  "integrity" "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
-  "resolved" "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
-  "version" "0.1.1"
-
-"is-extendable@^1.0.1":
-  "integrity" "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA=="
-  "resolved" "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "is-plain-object" "^2.0.4"
-
-"is-extglob@^2.1.0", "is-extglob@^2.1.1":
+"is-extglob@^2.1.1":
   "integrity" "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
   "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
   "version" "2.1.1"
@@ -685,33 +572,27 @@
   dependencies:
     "number-is-nan" "^1.0.0"
 
-"is-glob@^3.1.0":
-  "integrity" "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo="
-  "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz"
-  "version" "3.1.0"
-  dependencies:
-    "is-extglob" "^2.1.0"
+"is-fullwidth-code-point@^3.0.0":
+  "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+  "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
+  "version" "3.0.0"
 
-"is-glob@^4.0.0":
-  "integrity" "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg=="
-  "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz"
-  "version" "4.0.1"
+"is-glob@^4.0.1", "is-glob@~4.0.1":
+  "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="
+  "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
+  "version" "4.0.3"
   dependencies:
     "is-extglob" "^2.1.1"
 
-"is-number@^3.0.0":
-  "integrity" "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU="
-  "resolved" "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "kind-of" "^3.0.2"
+"is-number@^7.0.0":
+  "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+  "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+  "version" "7.0.0"
 
-"is-plain-object@^2.0.3", "is-plain-object@^2.0.4":
-  "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="
-  "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "isobject" "^3.0.1"
+"is-plain-obj@^2.1.0":
+  "integrity" "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
+  "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz"
+  "version" "2.1.0"
 
 "is-regex@^1.0.4":
   "integrity" "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE="
@@ -727,12 +608,12 @@
   dependencies:
     "has-symbols" "^1.0.0"
 
-"is-windows@^1.0.2":
-  "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
-  "resolved" "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz"
-  "version" "1.0.2"
+"is-unicode-supported@^0.1.0":
+  "integrity" "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="
+  "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz"
+  "version" "0.1.0"
 
-"isarray@~1.0.0", "isarray@1.0.0":
+"isarray@~1.0.0":
   "integrity" "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
   "resolved" "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
   "version" "1.0.0"
@@ -742,17 +623,10 @@
   "resolved" "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
   "version" "0.0.1"
 
-"isobject@^2.0.0":
-  "integrity" "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk="
-  "resolved" "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "isarray" "1.0.0"
-
-"isobject@^3.0.0", "isobject@^3.0.1":
-  "integrity" "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
-  "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz"
-  "version" "3.0.1"
+"isexe@^2.0.0":
+  "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+  "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+  "version" "2.0.0"
 
 "js-yaml@^3.2.7":
   "integrity" "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw=="
@@ -762,76 +636,45 @@
     "argparse" "^1.0.7"
     "esprima" "^4.0.0"
 
+"js-yaml@4.1.0":
+  "integrity" "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="
+  "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
+  "version" "4.1.0"
+  dependencies:
+    "argparse" "^2.0.1"
+
 "jsonify@~0.0.0":
   "integrity" "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
   "resolved" "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
   "version" "0.0.0"
 
-"kind-of@^3.0.2", "kind-of@^3.0.3", "kind-of@^3.2.0":
-  "integrity" "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ="
-  "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"
-  "version" "3.2.2"
+"locate-path@^6.0.0":
+  "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="
+  "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
+  "version" "6.0.0"
   dependencies:
-    "is-buffer" "^1.1.5"
+    "p-locate" "^5.0.0"
 
-"kind-of@^4.0.0":
-  "integrity" "sha1-IIE989cSkosgc3hpGkUGb65y3Vc="
-  "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz"
-  "version" "4.0.0"
+"log-symbols@4.1.0":
+  "integrity" "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="
+  "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz"
+  "version" "4.1.0"
   dependencies:
-    "is-buffer" "^1.1.5"
+    "chalk" "^4.1.0"
+    "is-unicode-supported" "^0.1.0"
 
-"kind-of@^5.0.0":
-  "integrity" "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
-  "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz"
-  "version" "5.1.0"
-
-"kind-of@^6.0.0":
-  "integrity" "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
-  "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz"
-  "version" "6.0.2"
-
-"kind-of@^6.0.2":
-  "integrity" "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
-  "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz"
-  "version" "6.0.2"
+"loupe@^2.3.1":
+  "integrity" "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ=="
+  "resolved" "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz"
+  "version" "2.3.4"
+  dependencies:
+    "get-func-name" "^2.0.0"
 
 "make-error@^1.1.1":
   "integrity" "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g=="
   "resolved" "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz"
   "version" "1.3.5"
 
-"map-cache@^0.2.2":
-  "integrity" "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
-  "resolved" "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz"
-  "version" "0.2.2"
-
-"map-visit@^1.0.0":
-  "integrity" "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48="
-  "resolved" "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "object-visit" "^1.0.0"
-
-"micromatch@^3.1.10", "micromatch@^3.1.4":
-  "integrity" "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg=="
-  "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz"
-  "version" "3.1.10"
-  dependencies:
-    "arr-diff" "^4.0.0"
-    "array-unique" "^0.3.2"
-    "braces" "^2.3.1"
-    "define-property" "^2.0.2"
-    "extend-shallow" "^3.0.2"
-    "extglob" "^2.0.4"
-    "fragment-cache" "^0.2.1"
-    "kind-of" "^6.0.2"
-    "nanomatch" "^1.2.9"
-    "object.pick" "^1.3.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.2"
-
 "min-document@^2.19.0":
   "integrity" "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU="
   "resolved" "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz"
@@ -846,6 +689,13 @@
   dependencies:
     "brace-expansion" "^1.1.7"
 
+"minimatch@4.2.1":
+  "integrity" "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g=="
+  "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz"
+  "version" "4.2.1"
+  dependencies:
+    "brace-expansion" "^1.1.7"
+
 "minimist@^1.2.0", "minimist@~1.2.0":
   "integrity" "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
   "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
@@ -861,14 +711,6 @@
   "resolved" "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
   "version" "0.0.8"
 
-"mixin-deep@^1.2.0":
-  "integrity" "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA=="
-  "resolved" "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz"
-  "version" "1.3.2"
-  dependencies:
-    "for-in" "^1.0.2"
-    "is-extendable" "^1.0.1"
-
 "mkdirp@^0.5.1":
   "integrity" "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM="
   "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
@@ -876,36 +718,52 @@
   dependencies:
     "minimist" "0.0.8"
 
-"ms@2.0.0":
-  "integrity" "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-  "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
-  "version" "2.0.0"
-
-"nanomatch@^1.2.9":
-  "integrity" "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA=="
-  "resolved" "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz"
-  "version" "1.2.13"
+"mocha@^9.2.2":
+  "integrity" "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g=="
+  "resolved" "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz"
+  "version" "9.2.2"
   dependencies:
-    "arr-diff" "^4.0.0"
-    "array-unique" "^0.3.2"
-    "define-property" "^2.0.2"
-    "extend-shallow" "^3.0.2"
-    "fragment-cache" "^0.2.1"
-    "is-windows" "^1.0.2"
-    "kind-of" "^6.0.2"
-    "object.pick" "^1.3.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
+    "@ungap/promise-all-settled" "1.1.2"
+    "ansi-colors" "4.1.1"
+    "browser-stdout" "1.3.1"
+    "chokidar" "3.5.3"
+    "debug" "4.3.3"
+    "diff" "5.0.0"
+    "escape-string-regexp" "4.0.0"
+    "find-up" "5.0.0"
+    "glob" "7.2.0"
+    "growl" "1.10.5"
+    "he" "1.2.0"
+    "js-yaml" "4.1.0"
+    "log-symbols" "4.1.0"
+    "minimatch" "4.2.1"
+    "ms" "2.1.3"
+    "nanoid" "3.3.1"
+    "serialize-javascript" "6.0.0"
+    "strip-json-comments" "3.1.1"
+    "supports-color" "8.1.1"
+    "which" "2.0.2"
+    "workerpool" "6.2.0"
+    "yargs" "16.2.0"
+    "yargs-parser" "20.2.4"
+    "yargs-unparser" "2.0.0"
 
-"normalize-path@^2.1.1":
-  "integrity" "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk="
-  "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz"
-  "version" "2.1.1"
-  dependencies:
-    "remove-trailing-separator" "^1.0.1"
+"ms@2.1.2":
+  "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+  "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
+  "version" "2.1.2"
 
-"normalize-path@^3.0.0":
+"ms@2.1.3":
+  "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+  "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+  "version" "2.1.3"
+
+"nanoid@3.3.1":
+  "integrity" "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
+  "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz"
+  "version" "3.3.1"
+
+"normalize-path@^3.0.0", "normalize-path@~3.0.0":
   "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
   "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
   "version" "3.0.0"
@@ -920,15 +778,6 @@
   "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
   "version" "4.1.1"
 
-"object-copy@^0.1.0":
-  "integrity" "sha1-fn2Fi3gb18mRpBupde04EnVOmYw="
-  "resolved" "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz"
-  "version" "0.1.0"
-  dependencies:
-    "copy-descriptor" "^0.1.0"
-    "define-property" "^0.2.5"
-    "kind-of" "^3.0.3"
-
 "object-inspect@~1.6.0":
   "integrity" "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ=="
   "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz"
@@ -944,20 +793,6 @@
   "resolved" "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz"
   "version" "0.4.0"
 
-"object-visit@^1.0.0":
-  "integrity" "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs="
-  "resolved" "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "isobject" "^3.0.0"
-
-"object.pick@^1.3.0":
-  "integrity" "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c="
-  "resolved" "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz"
-  "version" "1.3.0"
-  dependencies:
-    "isobject" "^3.0.1"
-
 "once@^1.3.0":
   "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="
   "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
@@ -965,20 +800,29 @@
   dependencies:
     "wrappy" "1"
 
+"p-limit@^3.0.2":
+  "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="
+  "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
+  "version" "3.1.0"
+  dependencies:
+    "yocto-queue" "^0.1.0"
+
+"p-locate@^5.0.0":
+  "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="
+  "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz"
+  "version" "5.0.0"
+  dependencies:
+    "p-limit" "^3.0.2"
+
 "parse-ms@^1.0.0":
   "integrity" "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0="
   "resolved" "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz"
   "version" "1.0.1"
 
-"pascalcase@^0.1.1":
-  "integrity" "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
-  "resolved" "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz"
-  "version" "0.1.1"
-
-"path-dirname@^1.0.0":
-  "integrity" "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
-  "resolved" "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz"
-  "version" "1.0.2"
+"path-exists@^4.0.0":
+  "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+  "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
+  "version" "4.0.0"
 
 "path-is-absolute@^1.0.0":
   "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
@@ -990,16 +834,21 @@
   "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz"
   "version" "1.0.6"
 
+"pathval@^1.1.1":
+  "integrity" "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="
+  "resolved" "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz"
+  "version" "1.1.1"
+
+"picomatch@^2.0.4", "picomatch@^2.2.1":
+  "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+  "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+  "version" "2.3.1"
+
 "plur@^1.0.0":
   "integrity" "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY="
   "resolved" "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz"
   "version" "1.0.0"
 
-"posix-character-classes@^0.1.0":
-  "integrity" "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
-  "resolved" "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz"
-  "version" "0.1.1"
-
 "prettier@^1.11.0":
   "integrity" "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw=="
   "resolved" "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz"
@@ -1024,7 +873,14 @@
   "resolved" "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
   "version" "0.11.10"
 
-"readable-stream@^2", "readable-stream@^2.0.2", "readable-stream@~2.3.6":
+"randombytes@^2.1.0":
+  "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="
+  "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
+  "version" "2.1.0"
+  dependencies:
+    "safe-buffer" "^5.1.0"
+
+"readable-stream@^2", "readable-stream@~2.3.6":
   "integrity" "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw=="
   "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz"
   "version" "2.3.6"
@@ -1057,42 +913,17 @@
     "isarray" "0.0.1"
     "string_decoder" "~0.10.x"
 
-"readdirp@^2.2.1":
-  "integrity" "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ=="
-  "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz"
-  "version" "2.2.1"
+"readdirp@~3.6.0":
+  "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="
+  "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
+  "version" "3.6.0"
   dependencies:
-    "graceful-fs" "^4.1.11"
-    "micromatch" "^3.1.10"
-    "readable-stream" "^2.0.2"
+    "picomatch" "^2.2.1"
 
-"regex-not@^1.0.0", "regex-not@^1.0.2":
-  "integrity" "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A=="
-  "resolved" "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "extend-shallow" "^3.0.2"
-    "safe-regex" "^1.1.0"
-
-"remove-trailing-separator@^1.0.1":
-  "integrity" "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
-  "resolved" "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
-  "version" "1.1.0"
-
-"repeat-element@^1.1.2":
-  "integrity" "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
-  "resolved" "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz"
-  "version" "1.1.3"
-
-"repeat-string@^1.6.1":
-  "integrity" "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
-  "resolved" "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
-  "version" "1.6.1"
-
-"resolve-url@^0.2.1":
-  "integrity" "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
-  "resolved" "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz"
-  "version" "0.2.1"
+"require-directory@^2.1.1":
+  "integrity" "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+  "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+  "version" "2.1.1"
 
 "resolve@~1.11.1":
   "integrity" "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw=="
@@ -1108,73 +939,17 @@
   dependencies:
     "through" "~2.3.4"
 
-"ret@~0.1.10":
-  "integrity" "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
-  "resolved" "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz"
-  "version" "0.1.15"
-
-"safe-buffer@~5.1.0", "safe-buffer@~5.1.1":
+"safe-buffer@^5.1.0", "safe-buffer@~5.1.0", "safe-buffer@~5.1.1":
   "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
   "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
   "version" "5.1.2"
 
-"safe-regex@^1.1.0":
-  "integrity" "sha1-QKNmnzsHfR6UPURinhV91IAjvy4="
-  "resolved" "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz"
-  "version" "1.1.0"
+"serialize-javascript@6.0.0":
+  "integrity" "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag=="
+  "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz"
+  "version" "6.0.0"
   dependencies:
-    "ret" "~0.1.10"
-
-"set-value@^2.0.0", "set-value@^2.0.1":
-  "integrity" "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw=="
-  "resolved" "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "extend-shallow" "^2.0.1"
-    "is-extendable" "^0.1.1"
-    "is-plain-object" "^2.0.3"
-    "split-string" "^3.0.1"
-
-"snapdragon-node@^2.0.1":
-  "integrity" "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw=="
-  "resolved" "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz"
-  "version" "2.1.1"
-  dependencies:
-    "define-property" "^1.0.0"
-    "isobject" "^3.0.0"
-    "snapdragon-util" "^3.0.1"
-
-"snapdragon-util@^3.0.1":
-  "integrity" "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ=="
-  "resolved" "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz"
-  "version" "3.0.1"
-  dependencies:
-    "kind-of" "^3.2.0"
-
-"snapdragon@^0.8.1":
-  "integrity" "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg=="
-  "resolved" "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz"
-  "version" "0.8.2"
-  dependencies:
-    "base" "^0.11.1"
-    "debug" "^2.2.0"
-    "define-property" "^0.2.5"
-    "extend-shallow" "^2.0.1"
-    "map-cache" "^0.2.2"
-    "source-map" "^0.5.6"
-    "source-map-resolve" "^0.5.0"
-    "use" "^3.1.0"
-
-"source-map-resolve@^0.5.0":
-  "integrity" "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA=="
-  "resolved" "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz"
-  "version" "0.5.2"
-  dependencies:
-    "atob" "^2.1.1"
-    "decode-uri-component" "^0.2.0"
-    "resolve-url" "^0.2.1"
-    "source-map-url" "^0.4.0"
-    "urix" "^0.1.0"
+    "randombytes" "^2.1.0"
 
 "source-map-support@^0.5.3":
   "integrity" "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="
@@ -1184,28 +959,11 @@
     "buffer-from" "^1.0.0"
     "source-map" "^0.6.0"
 
-"source-map-url@^0.4.0":
-  "integrity" "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
-  "resolved" "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz"
-  "version" "0.4.0"
-
-"source-map@^0.5.6":
-  "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
-  "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
-  "version" "0.5.7"
-
 "source-map@^0.6.0":
   "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
   "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
   "version" "0.6.1"
 
-"split-string@^3.0.1", "split-string@^3.0.2":
-  "integrity" "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw=="
-  "resolved" "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz"
-  "version" "3.1.0"
-  dependencies:
-    "extend-shallow" "^3.0.0"
-
 "sprintf-js@~1.0.2":
   "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
   "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
@@ -1216,14 +974,6 @@
   "resolved" "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz"
   "version" "0.1.5"
 
-"static-extend@^0.1.1":
-  "integrity" "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY="
-  "resolved" "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz"
-  "version" "0.1.2"
-  dependencies:
-    "define-property" "^0.2.5"
-    "object-copy" "^0.1.0"
-
 "string_decoder@~0.10.x":
   "integrity" "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
   "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
@@ -1236,6 +986,15 @@
   dependencies:
     "safe-buffer" "~5.1.0"
 
+"string-width@^4.1.0", "string-width@^4.2.0":
+  "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="
+  "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+  "version" "4.2.3"
+  dependencies:
+    "emoji-regex" "^8.0.0"
+    "is-fullwidth-code-point" "^3.0.0"
+    "strip-ansi" "^6.0.1"
+
 "string.prototype.trim@~1.1.2":
   "integrity" "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo="
   "resolved" "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz"
@@ -1252,6 +1011,25 @@
   dependencies:
     "ansi-regex" "^2.0.0"
 
+"strip-ansi@^6.0.0":
+  "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="
+  "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+  "version" "6.0.1"
+  dependencies:
+    "ansi-regex" "^5.0.1"
+
+"strip-ansi@^6.0.1":
+  "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="
+  "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+  "version" "6.0.1"
+  dependencies:
+    "ansi-regex" "^5.0.1"
+
+"strip-json-comments@3.1.1":
+  "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
+  "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
+  "version" "3.1.1"
+
 "supports-color@^2.0.0":
   "integrity" "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
   "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
@@ -1264,6 +1042,20 @@
   dependencies:
     "has-flag" "^3.0.0"
 
+"supports-color@^7.1.0":
+  "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="
+  "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+  "version" "7.2.0"
+  dependencies:
+    "has-flag" "^4.0.0"
+
+"supports-color@8.1.1":
+  "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="
+  "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+  "version" "8.1.1"
+  dependencies:
+    "has-flag" "^4.0.0"
+
 "tap-diff@^0.1.1":
   "integrity" "sha1-j78zM9hWQ/7qG/F1m5CCCwSjfd8="
   "resolved" "https://registry.npmjs.org/tap-diff/-/tap-diff-0.1.1.tgz"
@@ -1348,30 +1140,12 @@
     "readable-stream" "~1.1.9"
     "xtend" "~2.1.1"
 
-"to-object-path@^0.3.0":
-  "integrity" "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68="
-  "resolved" "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz"
-  "version" "0.3.0"
+"to-regex-range@^5.0.1":
+  "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="
+  "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+  "version" "5.0.1"
   dependencies:
-    "kind-of" "^3.0.2"
-
-"to-regex-range@^2.1.0":
-  "integrity" "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg="
-  "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz"
-  "version" "2.1.1"
-  dependencies:
-    "is-number" "^3.0.0"
-    "repeat-string" "^1.6.1"
-
-"to-regex@^3.0.1", "to-regex@^3.0.2":
-  "integrity" "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw=="
-  "resolved" "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "define-property" "^2.0.2"
-    "extend-shallow" "^3.0.2"
-    "regex-not" "^1.0.2"
-    "safe-regex" "^1.1.0"
+    "is-number" "^7.0.0"
 
 "ts-node@^5.0.0":
   "integrity" "sha512-XK7QmDcNHVmZkVtkiwNDWiERRHPyU8nBqZB1+iv2UhOG0q3RQ9HsZ2CMqISlFbxjrYFGfG2mX7bW4dAyxBVzUw=="
@@ -1387,49 +1161,42 @@
     "source-map-support" "^0.5.3"
     "yn" "^2.0.0"
 
+"type-detect@^4.0.0", "type-detect@^4.0.5":
+  "integrity" "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
+  "resolved" "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
+  "version" "4.0.8"
+
 "typescript@^4.6.2":
   "integrity" "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg=="
   "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz"
   "version" "4.6.2"
 
-"union-value@^1.0.0":
-  "integrity" "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg=="
-  "resolved" "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "arr-union" "^3.1.0"
-    "get-value" "^2.0.6"
-    "is-extendable" "^0.1.1"
-    "set-value" "^2.0.1"
-
-"unset-value@^1.0.0":
-  "integrity" "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk="
-  "resolved" "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "has-value" "^0.3.1"
-    "isobject" "^3.0.0"
-
-"upath@^1.1.1":
-  "integrity" "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q=="
-  "resolved" "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz"
-  "version" "1.1.2"
-
-"urix@^0.1.0":
-  "integrity" "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
-  "resolved" "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz"
-  "version" "0.1.0"
-
-"use@^3.1.0":
-  "integrity" "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
-  "resolved" "https://registry.npmjs.org/use/-/use-3.1.1.tgz"
-  "version" "3.1.1"
-
 "util-deprecate@~1.0.1":
   "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
   "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
   "version" "1.0.2"
 
+"which@2.0.2":
+  "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="
+  "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
+  "version" "2.0.2"
+  dependencies:
+    "isexe" "^2.0.0"
+
+"workerpool@6.2.0":
+  "integrity" "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A=="
+  "resolved" "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz"
+  "version" "6.2.0"
+
+"wrap-ansi@^7.0.0":
+  "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="
+  "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+  "version" "7.0.0"
+  dependencies:
+    "ansi-styles" "^4.0.0"
+    "string-width" "^4.1.0"
+    "strip-ansi" "^6.0.0"
+
 "wrappy@1":
   "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
   "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
@@ -1447,7 +1214,45 @@
   "resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
   "version" "4.0.2"
 
+"y18n@^5.0.5":
+  "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+  "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
+  "version" "5.0.8"
+
+"yargs-parser@^20.2.2", "yargs-parser@20.2.4":
+  "integrity" "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="
+  "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz"
+  "version" "20.2.4"
+
+"yargs-unparser@2.0.0":
+  "integrity" "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA=="
+  "resolved" "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz"
+  "version" "2.0.0"
+  dependencies:
+    "camelcase" "^6.0.0"
+    "decamelize" "^4.0.0"
+    "flat" "^5.0.2"
+    "is-plain-obj" "^2.1.0"
+
+"yargs@16.2.0":
+  "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="
+  "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
+  "version" "16.2.0"
+  dependencies:
+    "cliui" "^7.0.2"
+    "escalade" "^3.1.1"
+    "get-caller-file" "^2.0.5"
+    "require-directory" "^2.1.1"
+    "string-width" "^4.2.0"
+    "y18n" "^5.0.5"
+    "yargs-parser" "^20.2.2"
+
 "yn@^2.0.0":
   "integrity" "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo="
   "resolved" "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz"
   "version" "2.0.0"
+
+"yocto-queue@^0.1.0":
+  "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
+  "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
+  "version" "0.1.0"