diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 311827173..45207b077 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,14 +1,12 @@ { "name": "TypeScriptToLua", - "image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:14", - "settings": { - "terminal.integrated.shell.linux": "/bin/bash" - }, + "image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:18", "extensions": [ - "ark120202.vscode-typescript-to-lua", + "typescript-to-lua.vscode-typescript-to-lua", "dbaeumer.vscode-eslint", "editorconfig.editorconfig", "esbenp.prettier-vscode" ], - "postCreateCommand": "npm ci" + "postCreateCommand": "npm ci", + "remoteUser": "node" } diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 492195f96..000000000 --- a/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -/dist -/test/translation/transformation -/test/cli/errors -/test/cli/watch -/test/transpile/directories -/test/transpile/module-resolution/*/node_modules -/test/transpile/outFile diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 52df969ff..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,227 +0,0 @@ -module.exports = { - extends: ["plugin:jest/recommended", "plugin:jest/style"], - parserOptions: { - sourceType: "module", - project: ["test/tsconfig.json", "src/lualib/tsconfig.json", "benchmark/tsconfig.json"], - }, - env: { es6: true, node: true }, - plugins: ["import"], - rules: { - "arrow-body-style": "error", - curly: ["error", "multi-line"], - eqeqeq: ["error", "always", { null: "ignore" }], - "no-caller": "error", - "no-cond-assign": "error", - "no-debugger": "error", - "no-duplicate-case": "error", - "no-new-wrappers": "error", - "no-restricted-globals": ["error", "parseInt", "parseFloat"], - "no-unused-labels": "error", - "no-var": "error", - "object-shorthand": "error", - "prefer-const": ["error", { destructuring: "all" }], - radix: "error", - "use-isnan": "error", - "object-shorthand": [ - "error", - "always", - { avoidQuotes: true, ignoreConstructors: false, avoidExplicitReturnArrows: true }, - ], - "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "SequenceExpression"], - "spaced-comment": [ - "error", - "always", - { - line: { exceptions: ["-", "+"], markers: ["=", "!", "/"] }, - block: { exceptions: ["-", "+"], markers: ["=", "!", ":", "::"], balanced: true }, - }, - ], - "no-delete-var": ["error"], - "no-label-var": ["error"], - yoda: ["error"], - "prefer-numeric-literals": ["error"], - "prefer-rest-params": ["error"], - "prefer-spread": ["error"], - "no-useless-computed-key": ["error"], - "for-direction": ["error"], - "no-compare-neg-zero": ["error"], - "no-dupe-else-if": ["error"], - "no-empty": ["error", { allowEmptyCatch: true }], - "no-implicit-coercion": ["error", { boolean: true, number: true, string: true }], - "operator-assignment": ["error"], - "no-path-concat": ["error"], - "no-compare-neg-zero": ["error"], - "no-control-regex": ["error"], - "no-unneeded-ternary": ["error", { defaultAssignment: false }], - "one-var": ["error", "never"], - "prefer-exponentiation-operator": ["error"], - "prefer-object-spread": ["error"], - "no-useless-call": ["off"], - "no-useless-catch": ["error"], - "no-useless-concat": ["error"], - "no-useless-escape": ["error"], - "no-useless-return": ["error"], - - "import/no-default-export": "error", - // TODO currently only works for direct imports (useless for now) https://github.com/benmosher/eslint-plugin-import/issues/1729 - // "import/no-deprecated": "error", - - "jest/expect-expect": "off", - "jest/consistent-test-it": ["error", { fn: "test", withinDescribe: "test" }], - "jest/no-expect-resolves": "error", - "jest/no-test-return-statement": "error", - "jest/no-truthy-falsy": "error", - "jest/prefer-spy-on": "error", - "jest/prefer-todo": "error", - "jest/valid-title": "error", - // TODO: - // "jest/lowercase-name": "error", - }, - overrides: [ - { - files: "**/*.ts", - extends: ["plugin:@typescript-eslint/base"], - rules: { - // https://github.com/ark120202/eslint-config/blob/2c24f13fd99af7ccf29e56d5d936b3ab0f237db6/bases/typescript.js - "@typescript-eslint/adjacent-overload-signatures": "error", - "@typescript-eslint/array-type": "error", - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/ban-types": [ - "error", - { - types: { - Function: null, - CallableFunction: { fixWith: "(...args: any[]) => any" }, - NewableFunction: { fixWith: "new (...args: any[]) => any" }, - }, - }, - ], - camelcase: "off", - "@typescript-eslint/camelcase": ["error", { properties: "never", ignoreDestructuring: true }], - "@typescript-eslint/consistent-type-assertions": [ - "error", - { assertionStyle: "as", objectLiteralTypeAssertions: "never" }, - ], - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/explicit-member-accessibility": [ - "error", - { overrides: { constructors: "no-public" } }, - ], - "no-array-constructor": "off", - "@typescript-eslint/no-array-constructor": "error", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-extra-non-null-assertion": "error", - "@typescript-eslint/no-extraneous-class": "error", - "@typescript-eslint/no-floating-promises": "error", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-inferrable-types": "error", - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-misused-promises": "error", - "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-require-imports": "error", - "@typescript-eslint/no-this-alias": "error", - "no-throw-literal": "off", - "@typescript-eslint/no-throw-literal": "error", - "no-constant-condition": "off", - "@typescript-eslint/no-unnecessary-condition": [ - "error", - { ignoreRhs: true, allowConstantLoopConditions: true }, - ], - "@typescript-eslint/no-unnecessary-qualifier": "error", - "@typescript-eslint/no-unnecessary-type-arguments": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "no-unused-expressions": "off", - "@typescript-eslint/no-unused-expressions": "error", - "no-useless-constructor": "off", - "@typescript-eslint/no-useless-constructor": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/prefer-includes": "error", - "@typescript-eslint/prefer-optional-chain": "error", - "@typescript-eslint/prefer-namespace-keyword": "error", - "@typescript-eslint/prefer-readonly": "error", - "@typescript-eslint/prefer-string-starts-ends-with": "error", - "@typescript-eslint/promise-function-async": ["error", { checkArrowFunctions: false }], - quotes: "off", - "@typescript-eslint/quotes": ["error", "single", { avoidEscape: true, allowTemplateLiterals: false }], - "@typescript-eslint/require-array-sort-compare": "error", - "@typescript-eslint/require-await": "error", - "@typescript-eslint/restrict-plus-operands": ["error", { checkCompoundAssignments: true }], - "@typescript-eslint/return-await": "error", - "@typescript-eslint/triple-slash-reference": "error", - "@typescript-eslint/unified-signatures": "error", - // end of https://github.com/ark120202/eslint-config/blob/2c24f13fd99af7ccf29e56d5d936b3ab0f237db6/bases/typescript.js - "@typescript-eslint/array-type": ["error", { default: "array-simple" }], - "@typescript-eslint/ban-types": ["error", { types: { null: null } }], - "@typescript-eslint/no-namespace": ["error", { allowDeclarations: true }], - "@typescript-eslint/no-require-imports": "off", - "@typescript-eslint/no-unnecessary-condition": "off", - "@typescript-eslint/prefer-for-of": "error", - "@typescript-eslint/prefer-nullish-coalescing": "error", - "@typescript-eslint/prefer-readonly": "off", - "@typescript-eslint/quotes": ["error", "double", { avoidEscape: true, allowTemplateLiterals: false }], - "@typescript-eslint/require-array-sort-compare": "off", - "@typescript-eslint/camelcase": "off", - - "@typescript-eslint/naming-convention": [ - "error", - { - selector: "default", - format: ["camelCase"], - leadingUnderscore: "allow", - }, - { - selector: "variable", - format: ["camelCase", "UPPER_CASE"], - leadingUnderscore: "allow", - }, - { - selector: "typeLike", - format: ["PascalCase"], - }, - { - selector: "enumMember", - format: ["PascalCase"], - }, - { - selector: "typeParameter", - format: ["PascalCase"], - prefix: ["T"], - filter: { - regex: "K|V", - match: false, - }, - }, - { - selector: "interface", - format: ["PascalCase"], - custom: { - regex: "^I[A-Z]", - match: false, - }, - }, - ], - }, - }, - { - files: "src/lualib/**/*.ts", - rules: { - "no-restricted-syntax": ["error", "LabeledStatement", "SequenceExpression"], - "@typescript-eslint/no-throw-literal": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/naming-convention": "off", - }, - }, - { - files: "language-extensions/index.d.ts", - rules: { - "@typescript-eslint/naming-convention": "off", - }, - }, - { - files: "benchmark/src/memory_benchmarks/**/*.ts", - rules: { - "import/no-default-export": "off", - }, - }, - ], -}; diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..cd3dd9f16 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +# Sponsoring TypeScriptToLua helps us stay motivated and shows your appreciation for our work! +github: [Perryvw] diff --git a/.github/scripts/create_benchmark_check.js b/.github/scripts/create_benchmark_check.js index e1d303e06..4d9ac86cc 100644 --- a/.github/scripts/create_benchmark_check.js +++ b/.github/scripts/create_benchmark_check.js @@ -16,7 +16,13 @@ module.exports = ({ github, context, core }) => { const summary = `[Open visualizer](https://typescripttolua.github.io/benchviz?d=${compressed.toString("base64")})\n` + - `### Lua5.3\n${benchmarkInfoLua.comparison.summary}\n### LuaJIT\n${benchmarkInfoJIT.comparison.summary}`; + `### Lua5.3 +${benchmarkInfoLua.comparison.memory.summary} +${benchmarkInfoLua.comparison.runtime.summary} +--- +### LuaJIT +${benchmarkInfoJIT.comparison.memory.summary} +${benchmarkInfoJIT.comparison.runtime.summary}`; return summary; }; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 968cd9b87..8353ca6d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,14 +5,19 @@ on: branches: master pull_request: +env: + NODE_VERSION: 20.17.0 + jobs: lint: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} - run: npm ci - run: npm run lint env: @@ -26,18 +31,18 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v2 - - name: Use Node.js 12.13.1 - uses: actions/setup-node@v1 + - uses: actions/checkout@v4 + - name: Use Node.js 16.14.0 + uses: actions/setup-node@v4 with: - node-version: 12.13.1 + node-version: ${{ env.NODE_VERSION }} - run: npm ci - run: npm run build - run: npx jest --maxWorkers 2 --coverage env: CI: true - if: matrix.os == 'ubuntu-latest' - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 benchmark: name: Benchmark @@ -45,28 +50,44 @@ jobs: steps: - name: Lua Install run: sudo apt-get install lua5.3 luajit + - name: Add Brew to Path (Required since Nov 2022) + run: echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH - name: Glow Install run: brew install glow # Checkout master & commit - name: Checkout master - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: master path: master - name: Checkout commit - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: commit - - name: Use Node.js 12.13.1 - uses: actions/setup-node@v1 + - name: Use Node.js 16.14.0 + uses: actions/setup-node@v4 with: - node-version: 12.13.1 + node-version: ${{ env.NODE_VERSION }} # NPM - - name: NPM master - run: npm ci && npm run build + # install and build master + - name: npm ci master + run: npm ci + working-directory: master + - name: Use local tstl language extensions + run: npm i lua-types@latest && npm i -D file:. working-directory: master - - name: NPM commit - run: npm ci && npm run build + - name: Build master + run: npm run build + working-directory: master + # install and build commit + - name: npm ci commit + run: npm ci + working-directory: commit + - name: Use local tstl language extensions + run: npm i -D file:. + working-directory: commit + - name: Build commit + run: npm run build working-directory: commit # Benchmark directory setup - name: Ensure benchmark data dir exists @@ -76,14 +97,14 @@ jobs: run: rm -rf ./master/benchmark && cp -rf ./commit/benchmark ./master/benchmark # Run master benchmark first and output to commit benchmark data - name: Build benchmark Lua 5.3 master - run: node ../../commit/dist/tstl.js -p tsconfig.53.json + run: node ../dist/tstl.js -p tsconfig.53.json working-directory: master/benchmark - name: Run benchmark Lua 5.3 master id: benchmark-lua-master run: lua5.3 -- run.lua ../../../commit/benchmark/data/benchmark_master_53.json working-directory: master/benchmark/dist - name: Build benchmark LuaJIT master - run: node ../../commit/dist/tstl.js -p tsconfig.jit.json + run: node ../dist/tstl.js -p tsconfig.jit.json working-directory: master/benchmark - name: Run benchmark LuaJIT master id: benchmark-jit-master @@ -91,14 +112,14 @@ jobs: working-directory: master/benchmark/dist # Run commit benchmark and compare with master - name: Build benchmark Lua 5.3 commit - run: node ../../commit/dist/tstl.js -p tsconfig.53.json + run: node ../dist/tstl.js -p tsconfig.53.json working-directory: commit/benchmark - name: Run benchmark Lua 5.3 commit id: benchmark-lua-commit run: lua5.3 -- run.lua ../data/benchmark_master_vs_commit_53.json ../data/benchmark_master_53.json working-directory: commit/benchmark/dist - name: Build benchmark LuaJIT commit - run: node ../../commit/dist/tstl.js -p tsconfig.jit.json + run: node ../dist/tstl.js -p tsconfig.jit.json working-directory: commit/benchmark - name: Run benchmark LuaJIT commit id: benchmark-jit-commit @@ -106,7 +127,7 @@ jobs: working-directory: commit/benchmark/dist - name: Combine benchmark results id: script-combine-results - uses: actions/github-script@v3 + uses: actions/github-script@v7 with: benchmark-result-path-lua: commit/benchmark/data/benchmark_master_vs_commit_53.json benchmark-result-path-jit: commit/benchmark/data/benchmark_master_vs_commit_jit.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e6e9f26fd..f8146b8cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,10 @@ on: push: tags: "*" +permissions: + id-token: write + contents: read + jobs: release: name: Release @@ -11,13 +15,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Use Node.js 12.13.1 + - name: Use Node.js 24.12.0 uses: actions/setup-node@v1 with: - node-version: 12.13.1 + node-version: 24.12.0 registry-url: "https://registry.npmjs.org" - run: npm ci - run: npm run build - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} diff --git a/.gitignore b/.gitignore index 5546914da..fc3920330 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules /dist /coverage +/test/transpile/module-resolution/**/dist +/test/transpile/module-resolution/**/tsconfig.tsbuildinfo yarn.lock .vscode @@ -9,4 +11,7 @@ yarn.lock benchmark/data/* benchmark/dist/* -!benchmark/dist/json.lua + +# v8 cpu profiles +*-.log +*.cpuprofile diff --git a/.prettierignore b/.prettierignore index cbfe6aa04..fb6d91319 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,7 @@ /dist /coverage /test/translation/transformation/characterEscapeSequence.ts +/test/translation/transformation/exportStatement.ts +/benchmark/dist +/test/transpile/module-resolution/**/node_modules +/test/transpile/module-resolution/**/dist diff --git a/CHANGELOG.md b/CHANGELOG.md index ce877a1d5..46b2daaed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,353 @@ # Changelog +## 1.37.0 + +- Fixed a bug with where tsconfig paths were not correctly handled +- Improved error message for why >> is not allowed on Lua 5.3 and higher +- Added clearer diganostic for async generators and for-await-of not being supported +- Made @noSelf be respected on interfaces with call signatures +- Fixed promise.finally not being handled according to the javascript spec + +## 1.36.0 + +- **[Breaking]** Upgraded to TypeScript 6.0 + Thanks @RealColdFry for the following fixes: +- Fixed many bugs with try/catch/finally + - Also fixed some bugs with try/catch/finally in promises +- Fixed a bug where collection iterators would not correctly update when the collection updated +- No longer generate dead code after `break` statements +- Fixed a bug where math.atan2 was incorrectly used instead of math.atan for Lua 5.4 +- Fixed some inconsistencies with number constants (Number.MAX_SAFE_INTEGER, Number.MIN_VALUE, etc) +- Fixed a bug with the `>>>` operator for Lua 5.3 +- Fixed incorrect side effects for array destructors +- Fixed broken code when generating requires for files with `.` in the file name (e.g. `foo.tests.ts`), now the periods will be translated to `_` +- Fixed some incorrect handling of synthetic nodes +- Fixed a bug where object spread could lead to incorrect code being generated +- Fixed a bug with Object.defineProperty sharing values accross object instances + +## 1.34.0 + +- Added support for the Lua 5.5 target (it mostly does the same as the 5.4 target for now) +- Fixed a bug where enums in namespaces were not merged correctly +- Fixed an issue with sourcemap traceback that caused lines from anonymous functions not to be translated correctly. +- Fixed a small bug relating to the stacktraces produced by bundled lua + +## 1.33.0 + +- Upgraded TypeScript to 5.9.3 + +## 1.32.0 + +- Fixed a broken `@customName` interation with import statements +- Use `(table.)unpack(expression, from, to)` when using array destructing syntax `const [a,b] = array;` to avoid having to unpack the entire array +- Fixed compiler annotations also considering the next line as part of any possible arguments +- Fixed a bug with unicode classnames not being properly escaped in static initializer blocks +- Fixed a bug where `@noSelf` still was not respected for index signature methods +- Fixed a case where loop variables were incorrectly missing `local` +- Removed dead code that was sometimes generated using `continue` in a loop +- Fixed a bug with tagged template literals when the tag is a function call +- Fixed a bug with class decorators leading to invalid Lua code being generated +- A `-` or `+` prefix now converts expressions to numbers with `Number()` +- Fixed a bug with root level `using` statements not properly disposing objects + +## 1.31.0 + +- Upgraded TypeScript to 5.8.2 +- Changed `currentIndent` from private to protected in the `LuaPrinter` to allow custom printers with alternate indentation +- Added `bit` and `bit32` as reserved Lua keywords to avoid accidental naming clashes. + +## 1.30.0 + +- Allow passing in-memory plugins when using the tstl API, for more flexible integration into scripts +- Changed how stacktraces are handled for `Error` in Lua 5.1 and LuaJIT + +## 1.29.0 + +- Added support for the `Luau` luaTarget. This will use Luau's `continue` statement and ternary conditional expression `if ... then ... else ...` where appropriate. +- Added support for `new Array()` syntax to construct arrays (constructing with a length argument is not allowed). +- Fixed a bug causing arrays to sometimes be indexed with a wrong index. + +## 1.28.0 + +- Upgraded TypeScript to 5.7.2 +- Support `String(x)` transforming it to `tostring(x)`. +- Fixed statements before class super call +- Fixed some bugs with `LuaMultiReturn` used in iterables + +## 1.27.0 + +- Upgraded TypeScript to 5.6.2 +- Added support for `Math.trunc` (see [Math.trunc()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc)) +- Fixed a runtime error when disposing a disposable class +- Fixed the wrong `this` value being passed when using `?.` to call a `super` method +- Fixed a bug causing exported `/** @compileMembersOnly */` enums to break +- Fixed a bug in `Array.from` when calling it with a non-array iterable +- Fixed an incorrect diagnostic being shown for `await using` code +- Fixed a bug causing not all getters/setters to be transpiled + +## 1.26.0 + +- Upgraded TypeScript to 5.5.2 +- Added support for the new proposed ECMAScript Set methods in ESNext: `intersection`, `union`, `difference`, `symmetricDifference`, `isSubsetOf`, `isSupersetOf`, `isDisjointFrom`. For more info see [the TypeScript release notes](https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/#support-for-new-ecmascript-set-methods). +- Fixed a bug causing bundled code to be executed twice in some edge cases. +- Fixed a bug causing errors when using lualib in an environment without coroutines. + +## 1.25.0 + +- Upgraded TypeScript to 5.4.2 +- Added support for new TypeScript 5.4 features `Map.groupBy` and `Object.groupBy` +- Fixed a bug causing files to not be emitted at the correct output path +- Fixed a bug causing `@customname` to not work together with `@noSelf` +- Fixed a bug causing extended tsconfigs to not be correctly read when using watch mode + +## 1.24.0 + +- Optimized promises and async/await to better handle long chains of promises, like for example using await in a loop +- Fixed a bug causing errors when accessing `super` properties + +## 1.23.0 + +- Upgraded TypeScript to 5.3.3 + +## 1.22.0 + +- Added support for `Number.isInteger(n)` +- Added support for `afterEmit` plugin hook that can be used to post-process lua files after (possibly incremental) builds +- Fixed a bug causing `@noSelfInFile` sometimes to be ignored + +## 1.21.0 + +- Added support for `continue` for Lua 5.0, 5.1 and universal targets. +- Added support for the new `/** @customName myCustomName **/` decorator, which allows renaming of variables and identifiers. + - This is useful to get around names that are reserved keywords in TypeScript, but are used in Lua API +- Fixed a bug that caused super calls in static methods to throw an error + +## 1.20.0 + +- Added support for `Number.parseInt` and `Number.parseFloat` (mapped to same implementation as global `parseInt` and `parseFloat`) +- Added implementation for multiple `Number` constants like `Number.EPSILON` +- Added support for `Array.at` +- Fixed a bug when throwing an error object in a Lua environment without `debug` module +- Fixed a bug causing files not to be found when returning an absolute path from a `moduleResolution` plugin + +## 1.19.0 + +- Added support for the new TypeScript 5.2 `using` keyword for explicit resource management. See the [TypeScript release notes](https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/#using-declarations-and-explicit-resource-management) for more information. +- Added support for the newly introduced 'copying array methods' `toReversed`, `toSorted`, `toSpliced` and `with`. These were also introduced in TypeScript 5.2, see [their release notes](https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/#copying-array-methods) for more information. + +## 1.18.0 + +- Upgraded TypeScript to 5.2.2 +- The `noResolvePaths` option now accepts glob paths (for example, 'mydir/hello\*' to not resolve any files in mydir starting with hello). + - This also allows disabling module resolution completely by providing a '\*\*' pattern in your tsconfig.json `noResolvePaths`. + +## 1.17.0 + +- Added the `moduleResolution` plugin, allowing you to provide custom module resolution logic. See [the docs](https://typescripttolua.github.io/docs/api/plugins#moduleresolution) for more info. +- Added `isEmpty` to `LuaTable`, `LuaMap` and `LuaSet` (and their read-only counterparts). This simply to `next(tbl) == nil`, allowing for a simple check to see if a table is empty or not. +- Fixed a bug with synthetic nodes (e.g. created by custom TypeScript transformers) throwing an exception. +- Fixed unnecessary extra unpacking of tables +- Fixed some bugs with new decorators + +## 1.16.0 + +- Upgraded TypeScript to 5.1.3. +- Added support for [TypeScript 5.0 decorators](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#decorators). + - Old-style decorators will still work as long as you have `experimentalDecorators` configured, otherwise the new standard is used. +- Added support for [class static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks). +- Fixed a bug causing the `tstl` object in tsconfig.json not to be properly extended when extending a tsconfig from node_modules. + +## 1.15.0 + +- Using `extends` in tsconfig.json now also correctly merges settings in the `tstl` block (shallow merge). +- Now avoiding assigning default parameter values if the default value is `nil` (`null` or `undefined`). +- Fixed a bug where indexing a `LuaMultiReturn` value with [0] would still return everything. +- Fixed a bug with nested namespaces causing unexpected nil indexing errors. + +## 1.14.0 + +- **[Breaking]** Upgraded TypeScript to 5.0. +- Added support for `Number.toFixed`. +- Added support for spread expressions with `LuaPairsIterable` and `LuaPairsKeysIterable`. +- Fixed a bug breaking module resolution when using a custom file extension. +- Fixed various exceptions that could happen when trying to translate invalid TS. + +## 1.13.0 + +- Fixed alternate file extensions (other than .lua, if configured) breaking module resolution and emitted require statements. +- Added experimental support for `"luaLibImport": "require-minimal"` configuration option. This will output a lualib bundle containing only the lualib functions used by your code. This might not work if you are including external tstl-generated Lua, for example from a npm package. +- Added support for the "exports" field in package.json. +- Fixed some exceptions resulting from invalid language-extensions use. +- Fixed an exception when using compound assignment (like `+=`) with array length. + +## 1.12.0 + +- Reworked how tstl detects and rewrites `require` statements during dependency resolution. This should reduce the amount of false-positive matches of require statements: require statements in string literals or comments should no longer be detected by tstl. This means require statements in string literals or comments can survive the transpiler without causing a 'could not resolve lua sources' error or getting rewritten into nonsense. +- Now using `math.mod` for Lua 5.0 modulo operations. + +## 1.11.0 + +- **[Breaking]** Upgraded TypeScript to 4.9. +- `--tstlVerbose` now prints more resolver output when failing to resolve Lua sources. +- Fixed a bug breaking default exported classes with unicode names +- Relaxed conditions for the always-true warning to false positives. + +## 1.10.0 + +- **[Breaking]** Upgraded TypeScript to 4.8. +- **[Breaking]** Changed how language-extensions are distributed, you should now put `"types": ["@typescript-to-lua/language-extensions"]` in your tsconfig.json (instead of "typescript-to-lua/..."). +- Added support for **Lua 5.0**, thanks for the effort @YoRyan! +- Added support for TypeScript 4.7 [instantiation expressions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#instantiation-expressions). +- Fixed a bug causing some `require` uses not being recognized my module resolution, leading to missing files in the output. + +## 1.9.0 + +- Added a warning when trying to use a type in a condition that can never be false in Lua, such as numbers or strings. (Only when `strictNullChecks` is enabled.) +- Fixed some missing and misplaced errors when trying to reference LuaTable/LuaMap/LuaSet functions without calling them. +- Fixed a bug in the `get()` type of `ReadOnlyLuaMap`. It is now typed the same as `LuaMap`, i.e. it can return `undefined`. +- Fixed an issue in bundling that could sometimes lead to invalid bundle entry requires. +- Added a warning when using `paths` without specifying `baseUrl`. +- Fixed exception while checking for standard library types. + +## 1.8.0 + +- Added support for the [tsconfig.json paths](https://www.typescriptlang.org/tsconfig#paths) configuration option. +- Fixed spreading lua iterables & iterators translating to incorrect lua. + - You can now write things like `[...pairs(obj)]`. +- Fixed a bug in module resolution resolving the wrong lua files when having the same file names in nested directories. +- Fixed a bug causing temporary variables for nested destructuring in loop variables to be outside the loop, instead of inside. +- Fixed import expressions not actually requiring their import. +- Fixed `super` calls not being source-mapped correctly. + +## 1.7.0 + +- Added support for `LuaMap` and `LuaSet` language extensions that translate to very low level Lua table operations. See [our docs](https://typescripttolua.github.io/docs/advanced/language-extensions/#luamap-and-luaset) for more information. +- Big performance improvements, speeding up TSTL translation by 2-3x. Thanks @GlassBricks! +- Reduced the use of temorary variables. +- Moved tsconfig-schema into main TypeScriptToLua repository. +- Added support for array options in tstl CLI. +- Fixed bug where promise `then` was not correctly forwarding the result value to chained promises. +- Fixed a bug causing false positive errors from jsdoc documentation comments. +- Fixed various calling context bugs. + +## 1.6.0 + +- **[Breaking]** Upgraded TypeScript to 4.7 +- Fixed a bug where EmitOptions plugins were ignored +- Fixed a bug where sometimes function calls (like those to a custom jsx factory) would have a context argument even though `noImplicitSelf` was specified. +- Fixed a bug where sometimes `noImplicitSelf` was ignored because of incorrect file path separators. +- Fixed lualib_bundle files not correctly being included from node_module packages. +- Fixed compound assignment operators (e.g. ??= or ||=) not correctly updating the lhs if used as expression instead of statement. + +## 1.5.0 + +- Added support for `Array.from` and `Array.of` +- Added support for `beforeEmit` hook to plugins that runs after tstl is totally done, but before emitting the result. + - For more info about plugin hooks, see: https://typescripttolua.github.io/docs/api/plugins +- Added support for import expressions (`import("./module").then(m => m.foo());`) +- Added tsconfig setting `lua51AllowTryCatchInAsyncAwait` to disable restrictions on try/catch in combination with async/await in 5.1 (default: false) +- Added tsconfig setting `noImplicitGlobalVariables` to disable tstl making variables global in non-module files. +- Various lualib optimizations +- JSDoc comments from input TS are now also part of output Lua as LDoc comments. + - Can be disabled with `removeComments` tsconfig setting. +- Rewrote how try/catch works in async functions, fixing many bugs. +- Fixed a bug where methods with non-null expressions (i.e. `obj.method!()`) would not pass the correct self parameter, causing runtime errors. +- Fixed a bug where symlinked node_modules (for example when using `npm link`) were not recognized as external dependencies by module resolution. +- Fixed a bug with sourcemap traceback leading to invalid lua +- Improved sourcemap traceback interaction with `loadstring` + +## 1.4.0 + +- Upgraded to TypeScript 4.6 +- Added two event hooks to TSTL plugins: `beforeTransform` and `afterPrint` + - These allow you to run plugin code at specific points in the transpilation process. +- Lualib polyfills are now modules required into locals, instead of global functions + - This change also removes the `"always"` option for the `"lualibImport"` tsconfig key. +- Added support for `Math.sign` +- Switched to `^` instead of `math.pow`, the latter was deprecated in 5.3 +- Added an error when using `null` or `undefined` in tuples, as that is undefined behavior in the Lua spec and causes unexpected behavior +- Added tsconfig setting `extension`, allowing to specify a different output file extension +- Fixed multiple issues with optional chaining and lualib/language extensions +- Fixed issue assigning function with properties to variable declarations +- Fixed multiple issues with preceding statements in class constructors +- Fixed external code module resolution exploding into a stack overflow in complicated module hierarchies +- Fixed a `function.apply(context)` breaking the transpiler if called with only one parameter +- Fixed preceding statements in ternary conditionals (`x ? y : z`) leading to incorrect code + +## 1.3.0 + +- Added `LuaPairsIterable` language extension to mark objects as iterable with Lua's `pairs`. +- Added support for properties on functions. +- Unicode is no longer escaped and used as-is for `"luaTarget": "JIT"`. +- Fixed some bugs related to destructuring in loops and function parameters. +- Fixed incorrect global being generated for some `try` statements. +- Fixed some incorrect behavior for `??` and `? :` when generic types were involved. +- Added missing `...` optimization in cases where casts or parentheses are used. +- Fixed a bug for `Promise` when resolving with another Promise. This also fixes some unexpected behavior with `async` which is built with Promises. +- Fixed `async` functions not aborting after returning from a `catch` block. + +## 1.2.0 + +- Upgraded to TypeScript 4.5.x. +- Improved general output formatting. +- Added support for more complicated (nested) destructuring patterns, also fixing an exception they caused before. +- Fixed incorrect interactions between standard library functionality and optional chaining, e.g. `myArray?.forEach()`. +- Fixed rejected promises sometimes not getting the correct rejection reason. +- Fixed some `delete` behavior that was different in Lua compared to JS. +- Fixed a bug causing exported classes to lose their decorators. +- Fixed plugins checking for ts-node from the wrong location (tsconfig directory), plugins will now check for ts-node relative to the tstl directory. + +Under the hood: + +- We can now transform using preceding statements, allowing all kinds of optimizations and improvements to output Lua. +- Updated various language constructs to use preceding statements instead of inline immediately-invoked functions. + +## 1.1.0 + +- **[Breaking]** We now use TypeScript's JSX transformer instead of maintaining our own. As a result, `React.createElement` now requires a self parameter, so remove `@noSelf`, `this: void` if necessary. +- **[Breaking(-ish)]** Due to limitations in 5.1, try/catch can no longer be used in async or generator functions when targetting Lua 5.1. This was already broken but now tstl will explicitly give an error if you try. +- Added support for the `switch` statement in all versions! (Before they were not supported in 5.1 and universal). +- Added support for `string.prototype.replaceAll` and improved `string.prototype.replace` implementation. +- Added `noResolvePaths` tsconfig option to disable module resolution for environment-provided modules. +- Implemented support for void expressions, i.e `void(0)` or `void(ignoreThisReturnValue())`. +- Upgraded TypeScript to 4.4.4 and made it a peer dependency to hopefully avoid plugin issues due to mismatching TypeScript versions. +- The `$vararg` language extension can be used to access CLI arguments, now also in bundles. +- Fixed a bug regarding `baseUrl` and relative imports. +- Fixed `sourceMapTraceback: true` not working correctly for bundles. +- Fixed an issue regarding hoisting in switch case clauses. +- Added missing function context validation cases for object literals. +- Fixed a problem where awaiting rejected promises in try/catch would give the wrong result. +- Fixed an issue where chained `.then` calls on already-resolved or already-rejected promises would cause some callbacks to not fire while they should. +- Fixed source file paths in source maps being absolute, they are now relative again. + +## 1.0.0 + +- **[Breaking]** `/* @tupleReturn */` has been removed and will no longer have any effect. You will get an error if you try ot use it or if you use declarations that use it. +- Added support for the `Promise` class. +- Added support for `async` and `await` using coroutines. +- Module resolution now also correctly resolves `/init.lua` files for `require("")`. +- Fixed an error not being thrown when trying to call a method in an optional chain that does not exist. (If the method itself is not optional) +- Fixed a bug where parentheses could break the context parameter being resolved for a method. +- Fixed a bug where context parameters in object literal methods were not inferred correctly. +- Fixed a bug with sourceMapTraceback. +- Fixed TS emitting empty JSON files if you use JSON source files. + +## 0.42.0 + +- **[Breaking]** The `/** @tupleReturn */` is now deprecated, and will be removed next release. If you are still using it, please upgrade to the [LuaMultiReturn language extension](https://typescripttolua.github.io/docs/advanced/language-extensions#luamultireturn-type). +- Added support for JSX, see [documentation](https://typescripttolua.github.io/docs/jsx) for more information. +- Added support for the `baseUrl` configuration key for module resolution. + +A large list of bugfixes: + +- Fixed an exception causing tstl to exit when trying to assign to an optional chain. +- Fixed resolved files appearing duplicated in lua bundles. +- Fixed a problem resolving external Lua files in nested directories. +- Fixed `@noResolution` in library packages losing their NoResolution tag, causing attempts to resolve them for package users. +- Fixed a bug in the bundling code causing modules not to be cached if they return nil (which happens if they are not a module) +- Fixed module resolution trying to incorrectly resolve and rewrite things like `myObject.require()` or `my_custom_require()`. +- Fixed lualib bundle not being included in the output if external packages use it, but the client code does not. + ## 0.41.0 - Added support for [optional chaining](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html) `a?.b`, `a?.[b]` and `a?.()`. diff --git a/benchmark/README.md b/benchmark/README.md index c7b7d39c2..321218c9c 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -2,12 +2,12 @@ These benchmarks are written in typescript and transpiled to lua by using tstl. -### Currently only memory benchmarks are supported +### Memory benchmarks To add a new benchmark add a new file to `memory_benchmarks` and **default** export a function with the following type: `() => void`. To prevent the benchmark from reporting "useful" results of your benchmark function as garbage, simply return the result. -The memory used by the returned result wont count towards the total garbage amount. +The memory used by the returned result won't count towards the total garbage amount. For example (memory_benchmarks/my_benchmark.ts): @@ -25,19 +25,23 @@ export default function myBenchmark() { **Goal** The goal of memory benchmarks is to track how much (memory) `"garbage"` is created by tstl. -For that reason garabage collection is disabled in the benchmarks. +For that reason garbage collection is disabled in the benchmarks. You can force the creation of `"garbage"` by creating a lot of anonymous functions or temporary tables (see [lua-users.org](http://lua-users.org/wiki/OptimisingGarbageCollection) for more information). To avoid crashes in the CI your benchmark should not use more than 500MB of memory. -**Running locally** +### Runtime benchmarks -1. Create a benchmark baseline called "benchmark_baseline.json": +To add a new runtime benchmark (execution time), add a new file to `runtime_benchmarks` and **default** export a function with the following type: `() => void`. + +### Running locally + +1. Create a benchmark baseline called "benchmark_baseline.json": `tstl -p tsconfig.53.json && cd dist && lua -- run.lua benchmark_baseline.json` 2. Make some changes to tstl. -3. Create an updated benchmark and compare with the baseline: +3. Create an updated benchmark and compare with the baseline: `tstl -p tsconfig.53.json && cd dist && lua -- run.lua benchmark_updated.json benchmark_baseline.json` 4. The above command will output comparison data as json to stdout. - If you provide a path as third argument the comparison data will be written to that path instead. + If you provide a path as third argument the comparison data will be written to that path instead. `tstl -p tsconfig.53.json && cd dist && lua -- run.lua benchmark_updated.json benchmark_baseline.json result.md` diff --git a/benchmark/src/benchmark_types.ts b/benchmark/src/benchmark_types.ts index 6ec80efe6..38c2c1fd6 100644 --- a/benchmark/src/benchmark_types.ts +++ b/benchmark/src/benchmark_types.ts @@ -1,10 +1,11 @@ export enum BenchmarkKind { Memory = "memory", + Runtime = "runtime", } export type BenchmarkFunction = () => void; -export type BenchmarkResult = MemoryBenchmarkResult; +export type BenchmarkResult = MemoryBenchmarkResult | RuntimeBenchmarkResult; export enum MemoryBenchmarkCategory { TotalMemory = "totalMemory", @@ -21,6 +22,16 @@ export function isMemoryBenchmarkResult(result: BenchmarkResult): result is Memo return result.kind === BenchmarkKind.Memory; } +export interface RuntimeBenchmarkResult { + kind: BenchmarkKind.Runtime; + time: number; + benchmarkName: string; +} + +export function isRuntimeBenchmarkResult(result: BenchmarkResult): result is RuntimeBenchmarkResult { + return result.kind === BenchmarkKind.Runtime; +} + export interface ComparisonInfo { summary: string; text: string; diff --git a/benchmark/src/benchmark_util.ts b/benchmark/src/benchmark_util.ts new file mode 100644 index 000000000..fedbfdb93 --- /dev/null +++ b/benchmark/src/benchmark_util.ts @@ -0,0 +1,60 @@ +import { BenchmarkResult } from "./benchmark_types"; +import { calculatePercentageChange, toFixed } from "./util"; + +export const makeMarkdownTableRow = (cells: string[]) => `| ${cells.join(" | ")} |\n`; +export const makeBold = (input: string) => `**${input}**`; + +export function compareNumericBenchmarks( + newResults: T[], + oldResults: T[], + unit: string, + extractValue: (result: T) => number, + formatValue: (value: number) => string +): string { + let comparisonTable = makeMarkdownTableRow([ + "name", + `master (${unit})`, + `commit (${unit})`, + `change (${unit})`, + "change (%)", + ]); + comparisonTable += makeMarkdownTableRow(["---", "---", "---", "---", "---"]); + + let oldValueSum = 0; + let newValueSum = 0; + + newResults.forEach(newResult => { + const oldResult = oldResults.find(r => r.benchmarkName === newResult.benchmarkName); + const newValue = extractValue(newResult); + if (oldResult) { + const oldValue = extractValue(oldResult); + const percentageChange = calculatePercentageChange(oldValue, newValue); + const change = newValue - oldValue; + const row = [ + newResult.benchmarkName, + formatValue(oldValue), + formatValue(newValue), + formatValue(change), + toFixed(percentageChange, 2), + ]; + comparisonTable += makeMarkdownTableRow(row); + oldValueSum += oldValue; + newValueSum += newValue; + } else { + // No master found => new benchmark + const row = [newResult.benchmarkName, formatValue(newValue), "/", "/", "/"]; + comparisonTable += makeMarkdownTableRow(row); + } + }); + + const sumPercentageChange = calculatePercentageChange(oldValueSum, newValueSum); + comparisonTable += makeMarkdownTableRow([ + makeBold("sum"), + makeBold(formatValue(oldValueSum)), + makeBold(formatValue(newValueSum)), + makeBold(formatValue(newValueSum - oldValueSum)), + makeBold(toFixed(sumPercentageChange, 2)), + ]); + + return comparisonTable; +} diff --git a/benchmark/src/memory_benchmark.ts b/benchmark/src/memory_benchmark.ts index 51f8031be..8434f3881 100644 --- a/benchmark/src/memory_benchmark.ts +++ b/benchmark/src/memory_benchmark.ts @@ -1,5 +1,6 @@ import { BenchmarkKind, MemoryBenchmarkResult, ComparisonInfo, MemoryBenchmarkCategory } from "./benchmark_types"; -import { toFixed, json, calculatePercentageChange } from "./util"; +import { compareNumericBenchmarks } from "./benchmark_util"; +import { toFixed, json } from "./util"; export function runMemoryBenchmark(benchmarkFunction: () => void): MemoryBenchmarkResult { const result: MemoryBenchmarkResult = { @@ -42,8 +43,6 @@ export function runMemoryBenchmark(benchmarkFunction: () => void): MemoryBenchma } const formatMemory = (memInKB: number) => toFixed(memInKB / 1024, 3); -const makeMarkdownTableRow = (cells: string[]) => `| ${cells.join(" | ")} |\n`; -const makeBold = (input: string) => `**${input}**`; export function compareMemoryBenchmarks( oldResults: MemoryBenchmarkResult[], @@ -53,10 +52,10 @@ export function compareMemoryBenchmarks( const categories = [MemoryBenchmarkCategory.TotalMemory, MemoryBenchmarkCategory.Garbage]; const summary = categories - .map(category => `${makeBold(category)}\n${compareCategory(newResults, oldResults, category)}`) + .map(category => `### ${category}\n\n${compareCategory(newResults, oldResults, category)}`) .join("\n"); - const text = `**master:**\n\`\`\`json\n${json.encode(oldResults)}\n\`\`\`\n**commit:**\n\`\`\`json\n${json.encode( + const text = `### master:\n\`\`\`json\n${json.encode(oldResults)}\n\`\`\`\n### commit:\n\`\`\`json\n${json.encode( newResults )}\n\`\`\``; @@ -68,47 +67,5 @@ function compareCategory( oldResults: MemoryBenchmarkResult[], category: MemoryBenchmarkCategory ): string { - let comparisonTable = makeMarkdownTableRow(["name", "master (mb)", "commit (mb)", "change (mb)", "change (%)"]); - comparisonTable += makeMarkdownTableRow(["-", "-", "-", "-", "-"]); - - let oldValueSum = 0; - let newValueSum = 0; - - newResults.forEach(newResult => { - const oldResult = oldResults.find(r => r.benchmarkName === newResult.benchmarkName); - if (oldResult) { - const oldValue = oldResult.categories[category]; - const newValue = newResult.categories[category]; - const percentageChange = calculatePercentageChange( - newResult.categories[category], - oldResult.categories[category] - ); - const change = newResult.categories[category] - oldResult.categories[category]; - const row = [ - newResult.benchmarkName, - formatMemory(oldValue), - formatMemory(newValue), - formatMemory(change), - toFixed(percentageChange, 2), - ]; - comparisonTable += makeMarkdownTableRow(row); - oldValueSum += oldValue; - newValueSum += newValue; - } else { - // No master found => new benchmark - const row = [newResult.benchmarkName, formatMemory(newResult.categories[category]), "/", "/", "/"]; - comparisonTable += makeMarkdownTableRow(row); - } - }); - - const sumPercentageChange = calculatePercentageChange(oldValueSum, newValueSum); - comparisonTable += makeMarkdownTableRow([ - makeBold("sum"), - makeBold(formatMemory(oldValueSum)), - makeBold(formatMemory(newValueSum)), - makeBold(formatMemory(newValueSum - oldValueSum)), - makeBold(toFixed(sumPercentageChange, 2)), - ]); - - return comparisonTable; + return compareNumericBenchmarks(newResults, oldResults, "mb", result => result.categories[category], formatMemory); } diff --git a/benchmark/src/run.ts b/benchmark/src/run.ts index b880537e5..8b02cc7da 100644 --- a/benchmark/src/run.ts +++ b/benchmark/src/run.ts @@ -1,5 +1,14 @@ import { runMemoryBenchmark, compareMemoryBenchmarks } from "./memory_benchmark"; -import { isMemoryBenchmarkResult, BenchmarkResult, MemoryBenchmarkResult, ComparisonInfo } from "./benchmark_types"; +import { + isMemoryBenchmarkResult, + BenchmarkResult, + MemoryBenchmarkResult, + ComparisonInfo, + RuntimeBenchmarkResult, + isRuntimeBenchmarkResult, + BenchmarkKind, +} from "./benchmark_types"; +import { runRuntimeBenchmark, compareRuntimeBenchmarks } from "./runtime_benchmark"; import { json, loadBenchmarksFromDirectory, readFile } from "./util"; // CLI arguments @@ -10,15 +19,16 @@ declare const arg: [string | undefined, string | undefined, string | undefined]; function benchmark(): void { // Memory tests - let memoryBenchmarkNewResults: MemoryBenchmarkResult[] = []; const memoryBenchmarks = loadBenchmarksFromDirectory("memory_benchmarks"); + const memoryBenchmarkNewResults: MemoryBenchmarkResult[] = memoryBenchmarks.map(runMemoryBenchmark); - memoryBenchmarkNewResults = memoryBenchmarks.map(runMemoryBenchmark); + // Run time tests - // run future benchmarks types here + const runtimeBenchmarks = loadBenchmarksFromDirectory("runtime_benchmarks"); + const runtimeBenchmarkNewResults: RuntimeBenchmarkResult[] = runtimeBenchmarks.map(runRuntimeBenchmark); - const newBenchmarkResults = [...memoryBenchmarkNewResults]; + const newBenchmarkResults = [...memoryBenchmarkNewResults, ...runtimeBenchmarkNewResults]; // Try to read the baseline benchmark result let oldBenchmarkResults: BenchmarkResult[] = []; @@ -28,17 +38,48 @@ function benchmark(): void { } // Output comparison info + oldBenchmarkResults.sort(sortByName); + newBenchmarkResults.sort(sortByName); outputBenchmarkData(oldBenchmarkResults, newBenchmarkResults); } benchmark(); -function compareBenchmarks(oldResults: BenchmarkResult[], newResults: BenchmarkResult[]): ComparisonInfo { +function sortByName({ benchmarkName: a }: BenchmarkResult, { benchmarkName: b }: BenchmarkResult): number { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +function compareBenchmarks( + oldResults: BenchmarkResult[], + newResults: BenchmarkResult[] +): Record { const oldResultsMemory = oldResults.filter(isMemoryBenchmarkResult); const newResultsMemory = newResults.filter(isMemoryBenchmarkResult); const memoryComparisonInfo = compareMemoryBenchmarks(oldResultsMemory, newResultsMemory); - return { summary: memoryComparisonInfo.summary, text: memoryComparisonInfo.text }; + const oldResultsRuntime = oldResults.filter(isRuntimeBenchmarkResult); + const newResultsRuntime = newResults.filter(isRuntimeBenchmarkResult); + + const runtimeComparisonInfo = compareRuntimeBenchmarks(oldResultsRuntime, newResultsRuntime); + + return { + [BenchmarkKind.Memory]: memoryComparisonInfo, + [BenchmarkKind.Runtime]: runtimeComparisonInfo, + }; +} + +function formatComparisonMarkdownFile(comparisonInfo: Record): string { + let result = ""; + const benchmarkKinds = [BenchmarkKind.Memory, BenchmarkKind.Runtime]; + for (const kind of benchmarkKinds) { + result += comparisonInfo[kind].summary + "\n"; + } + for (const kind of benchmarkKinds) { + result += comparisonInfo[kind].text + "\n"; + } + return result; } function outputBenchmarkData(oldResults: BenchmarkResult[], newResults: BenchmarkResult[]): void { @@ -59,6 +100,6 @@ function outputBenchmarkData(oldResults: BenchmarkResult[], newResults: Benchmar // Compare results const comparisonInfo = compareBenchmarks(oldResults, newResults); const markdownDataFile = io.open(arg[2], "w+")[0]!; - markdownDataFile.write(comparisonInfo.summary + comparisonInfo.text); + markdownDataFile.write(formatComparisonMarkdownFile(comparisonInfo)); } } diff --git a/benchmark/src/runtime_benchmark.ts b/benchmark/src/runtime_benchmark.ts new file mode 100644 index 000000000..c56cd1b0d --- /dev/null +++ b/benchmark/src/runtime_benchmark.ts @@ -0,0 +1,43 @@ +import { BenchmarkKind, ComparisonInfo, RuntimeBenchmarkResult } from "./benchmark_types"; +import { compareNumericBenchmarks } from "./benchmark_util"; +import { json, toFixed } from "./util"; + +export function runRuntimeBenchmark(benchmarkFunction: () => void): RuntimeBenchmarkResult { + const result: RuntimeBenchmarkResult = { + kind: BenchmarkKind.Runtime, + benchmarkName: "NO_NAME", + time: 0, + }; + + // normalize times a bit + collectgarbage("collect"); + + const startTime = os.clock(); + benchmarkFunction(); + const time = os.clock() - startTime; + + result.benchmarkName = debug.getinfo(benchmarkFunction).short_src; + result.time = time; + return result; +} + +export function compareRuntimeBenchmarks( + oldResults: RuntimeBenchmarkResult[], + newResults: RuntimeBenchmarkResult[] +): ComparisonInfo { + const summary = + "### runtime\n\n" + + compareNumericBenchmarks( + newResults, + oldResults, + "s", + result => result.time, + time => toFixed(time, 4) + ); + + const text = `### master\n\`\`\`json\n${json.encode(oldResults)}\n\`\`\`\n### commit\n\`\`\`json\n${json.encode( + newResults + )}\n\`\`\``; + + return { summary, text }; +} diff --git a/benchmark/src/runtime_benchmarks/array_concat_array.ts b/benchmark/src/runtime_benchmarks/array_concat_array.ts new file mode 100644 index 000000000..9c9a7e83d --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_concat_array.ts @@ -0,0 +1,9 @@ +export default function arrayConcat(): number[] { + const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + const arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + const n = 50000; + for (let i = 0; i < n; i++) { + arr1.concat(arr2); + } + return arr1; +} diff --git a/benchmark/src/runtime_benchmarks/array_concat_spread.ts b/benchmark/src/runtime_benchmarks/array_concat_spread.ts new file mode 100644 index 000000000..a04eff958 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_concat_spread.ts @@ -0,0 +1,9 @@ +export default function arrayConcat(): number[] { + const arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + const arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + const n = 50000; + for (let i = 0; i < n; i++) { + arr1.concat(...arr2); + } + return arr1; +} diff --git a/benchmark/src/runtime_benchmarks/array_every.ts b/benchmark/src/runtime_benchmarks/array_every.ts new file mode 100644 index 000000000..f5dbfc4e4 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_every.ts @@ -0,0 +1,7 @@ +export default function arrayEvery() { + const n = 200000; + const array = [1, 2, 3, 4, 5, 6, 7, 8, 7, 10]; + for (let i = 0; i < n; i++) { + array.every((item, index) => item > index); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_filter.ts b/benchmark/src/runtime_benchmarks/array_filter.ts new file mode 100644 index 000000000..127d2476d --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_filter.ts @@ -0,0 +1,7 @@ +export default function arrayFilter() { + const n = 100000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 7, 10]; + for (let i = 0; i < n; i++) { + array.filter((item, index) => item > index); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_find.ts b/benchmark/src/runtime_benchmarks/array_find.ts new file mode 100644 index 000000000..8a84ff4e5 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_find.ts @@ -0,0 +1,9 @@ +export default function arrayFind() { + const n = 50000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 10; j++) { + array.find(value => value === j); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_findIndex.ts b/benchmark/src/runtime_benchmarks/array_findIndex.ts new file mode 100644 index 000000000..c058a99df --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_findIndex.ts @@ -0,0 +1,9 @@ +export default function arrayFindIndex() { + const n = 50000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 10; j++) { + array.findIndex(value => value === j); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_flat.ts b/benchmark/src/runtime_benchmarks/array_flat.ts new file mode 100644 index 000000000..36ace2d95 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_flat.ts @@ -0,0 +1,7 @@ +export default function arrayFlat() { + const n = 50000; + const array = [1, 2, [3, [4, 5], 6], 7, [8, 9], 10]; + for (let i = 0; i < n; i++) { + array.flat(2); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_flatMap.ts b/benchmark/src/runtime_benchmarks/array_flatMap.ts new file mode 100644 index 000000000..26c6490e5 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_flatMap.ts @@ -0,0 +1,13 @@ +export default function arrayFlatMap() { + const n = 50000; + const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + array.flatMap((el, index) => { + if (index < 5) { + return [el, el + 1]; + } else { + return el + 2; + } + }); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_foreach.ts b/benchmark/src/runtime_benchmarks/array_foreach.ts new file mode 100644 index 000000000..8e14c8119 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_foreach.ts @@ -0,0 +1,10 @@ +export default function arrayForeach() { + const n = 200000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + array.forEach(value => { + let foo = value * 2; + foo = foo; + }); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_includes.ts b/benchmark/src/runtime_benchmarks/array_includes.ts new file mode 100644 index 000000000..828c167a3 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_includes.ts @@ -0,0 +1,9 @@ +export default function arrayIncludes() { + const n = 50000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 10; j++) { + array.includes(j); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_indexOf.ts b/benchmark/src/runtime_benchmarks/array_indexOf.ts new file mode 100644 index 000000000..333c67988 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_indexOf.ts @@ -0,0 +1,9 @@ +export default function arrayIndexOf() { + const n = 50000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 10; j++) { + array.indexOf(j); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_join.ts b/benchmark/src/runtime_benchmarks/array_join.ts new file mode 100644 index 000000000..5a9f5bae4 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_join.ts @@ -0,0 +1,8 @@ +const array = [1, 2, "3", 4, 3, "6", { foo: 3 }, 8, 9, 10]; + +export default function arrayJoin() { + const n = 3000; + for (let i = 0; i < n; i++) { + array.join("|"); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_map.ts b/benchmark/src/runtime_benchmarks/array_map.ts new file mode 100644 index 000000000..79d00d66a --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_map.ts @@ -0,0 +1,7 @@ +export default function arrayMap() { + const n = 100000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + array.map(value => value * 2); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_push_array.ts b/benchmark/src/runtime_benchmarks/array_push_array.ts new file mode 100644 index 000000000..fcc239a31 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_push_array.ts @@ -0,0 +1,9 @@ +export default function arrayPush(): number[] { + const n = 200000; + const numberList: number[] = []; + const numbers = [1, 2, 3]; + for (let i = 0; i < n; i++) { + numberList.push(...numbers); + } + return numberList; +} diff --git a/benchmark/src/runtime_benchmarks/array_push_multiple.ts b/benchmark/src/runtime_benchmarks/array_push_multiple.ts new file mode 100644 index 000000000..dbef5460c --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_push_multiple.ts @@ -0,0 +1,8 @@ +export default function arrayPush(): number[] { + const n = 200000; + const numberList: number[] = []; + for (let i = 0; i < n; i++) { + numberList.push(i * i, i + 1); + } + return numberList; +} diff --git a/benchmark/src/runtime_benchmarks/array_push_single.ts b/benchmark/src/runtime_benchmarks/array_push_single.ts new file mode 100644 index 000000000..f09bc21ec --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_push_single.ts @@ -0,0 +1,8 @@ +export default function arrayPush(): number[] { + const n = 500000; + const numberList: number[] = []; + for (let i = 0; i < n; i++) { + numberList.push(i * i); + } + return numberList; +} diff --git a/benchmark/src/runtime_benchmarks/array_push_vararg.ts b/benchmark/src/runtime_benchmarks/array_push_vararg.ts new file mode 100644 index 000000000..e780461ee --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_push_vararg.ts @@ -0,0 +1,12 @@ +export default function arrayPush(): number[] { + const n = 200000; + const numberList: number[] = []; + function pushArgs(...args: number[]): void { + numberList.push(...args); + } + + for (let i = 0; i < n; i++) { + pushArgs(3, 4); + } + return numberList; +} diff --git a/benchmark/src/runtime_benchmarks/array_reduce.ts b/benchmark/src/runtime_benchmarks/array_reduce.ts new file mode 100644 index 000000000..2d615e80f --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_reduce.ts @@ -0,0 +1,7 @@ +export default function arrayReduce() { + const n = 200000; + const array = [1, 2, 3, 4, 5, 6, 7, 8, 7, 10]; + for (let i = 0; i < n; i++) { + array.reduce((prev, cur, i) => prev + cur + i, 1); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_reduceRight.ts b/benchmark/src/runtime_benchmarks/array_reduceRight.ts new file mode 100644 index 000000000..9dd97d3d2 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_reduceRight.ts @@ -0,0 +1,7 @@ +export default function arrayReduce() { + const n = 200000; + const array = [1, 2, 3, 4, 5, 6, 7, 8, 7, 10]; + for (let i = 0; i < n; i++) { + array.reduceRight((prev, cur, i) => prev + cur + i, 1); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_reverse.ts b/benchmark/src/runtime_benchmarks/array_reverse.ts new file mode 100644 index 000000000..539d26138 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_reverse.ts @@ -0,0 +1,7 @@ +export default function arrayReverse(): void { + const n = 500000; + const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + numbers.reverse(); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_slice.ts b/benchmark/src/runtime_benchmarks/array_slice.ts new file mode 100644 index 000000000..5419cb0d9 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_slice.ts @@ -0,0 +1,9 @@ +export default function arraySlice() { + const n = 50000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 6; j++) { + array.slice(j, -j); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_some.ts b/benchmark/src/runtime_benchmarks/array_some.ts new file mode 100644 index 000000000..8add42a56 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_some.ts @@ -0,0 +1,7 @@ +export default function arraySome() { + const n = 200000; + const array = [1, 2, 3, 4, 5, 6, 7, 8, 7, 10]; + for (let i = 0; i < n; i++) { + array.some((item, index) => item < index); + } +} diff --git a/benchmark/src/runtime_benchmarks/array_splice.ts b/benchmark/src/runtime_benchmarks/array_splice.ts new file mode 100644 index 000000000..4620bad86 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_splice.ts @@ -0,0 +1,9 @@ +export default function arraySplice() { + const n = 20000; + const array = [1, 2, 3, 4, 3, 6, 7, 8, 9, 10]; + for (let i = 0; i < n; i++) { + for (let j = 0; j < 10; j++) { + array.splice(j, 2, 1, 2); + } + } +} diff --git a/benchmark/src/runtime_benchmarks/array_unshift.ts b/benchmark/src/runtime_benchmarks/array_unshift.ts new file mode 100644 index 000000000..b0f59a0b2 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/array_unshift.ts @@ -0,0 +1,9 @@ +export default function arrayUnshift(): number[] { + const n = 2000; + const numberList: number[] = []; + const numbers = [1, 2, 3]; + for (let i = 0; i < n; i++) { + numberList.unshift(...numbers); + } + return numberList; +} diff --git a/benchmark/src/runtime_benchmarks/string_concat.ts b/benchmark/src/runtime_benchmarks/string_concat.ts new file mode 100644 index 000000000..47d520e9a --- /dev/null +++ b/benchmark/src/runtime_benchmarks/string_concat.ts @@ -0,0 +1,8 @@ +export default function stringReplace() { + const str = "one"; + const n = 50000; + for (let i = 0; i < n; i++) { + str.concat("two", "three", "four", "five"); + } + return str; +} diff --git a/benchmark/src/runtime_benchmarks/string_replace.ts b/benchmark/src/runtime_benchmarks/string_replace.ts new file mode 100644 index 000000000..e7a00fc35 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/string_replace.ts @@ -0,0 +1,8 @@ +export default function stringReplace() { + const str = "Hello, World!"; + const n = 50000; + for (let i = 0; i < n; i++) { + str.replace("World", "Universe"); + } + return str; +} diff --git a/benchmark/src/runtime_benchmarks/string_replaceAll.ts b/benchmark/src/runtime_benchmarks/string_replaceAll.ts new file mode 100644 index 000000000..268bb3642 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/string_replaceAll.ts @@ -0,0 +1,8 @@ +export default function stringReplaceAll() { + const str = "hello, hello world!"; + const n = 50000; + for (let i = 0; i < n; i++) { + str.replaceAll("Hello", "Goodbye"); + } + return str; +} diff --git a/benchmark/src/runtime_benchmarks/string_split.ts b/benchmark/src/runtime_benchmarks/string_split.ts new file mode 100644 index 000000000..22f6c9bb1 --- /dev/null +++ b/benchmark/src/runtime_benchmarks/string_split.ts @@ -0,0 +1,8 @@ +export default function stringReplaceAll() { + const str = "This is a string"; + const n = 50000; + for (let i = 0; i < n; i++) { + str.split(" "); + } + return str; +} diff --git a/benchmark/src/util.ts b/benchmark/src/util.ts index bd1c0a10f..41f2159f5 100644 --- a/benchmark/src/util.ts +++ b/benchmark/src/util.ts @@ -30,16 +30,21 @@ export function readFile(path: string): string { } export function readAll(file: LuaFile): string { - const content = file.read(_VERSION === "Lua 5.3" ? "a" : ("*a" as any)) as [string | undefined]; + const content = file.read(_VERSION === "Lua 5.3" ? "a" : ("*a" as any)); - if (content[0]) { - return content[0]; + if (content) { + return content as string; } throw Error(`Can't readAll for file ${file}`); } export function readDir(dir: string): string[] { - const findHandle = io.popen(isWindows ? `dir /A-D /B ${dir}` : `find '${dir}' -maxdepth 1 -type f`); + const [findHandle] = io.popen(isWindows ? `dir /A-D /B ${dir}` : `find '${dir}' -maxdepth 1 -type f`); + + if (!findHandle) { + throw new Error(`Failed to read dir ${dir}`); + } + const findResult = readAll(findHandle); if (!findHandle.close()) { diff --git a/benchmark/tsconfig.53.json b/benchmark/tsconfig.53.json index 0a7096234..6dbbe3bca 100644 --- a/benchmark/tsconfig.53.json +++ b/benchmark/tsconfig.53.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "types": ["lua-types/5.3"] + "types": ["lua-types/5.3", "@typescript-to-lua/language-extensions"] }, "tstl": { "luaTarget": "5.3" diff --git a/benchmark/tsconfig.jit.json b/benchmark/tsconfig.jit.json index 1fe18fa2c..0c6912d31 100644 --- a/benchmark/tsconfig.jit.json +++ b/benchmark/tsconfig.jit.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "types": ["lua-types/jit"] + "types": ["lua-types/jit", "@typescript-to-lua/language-extensions"] }, "tstl": { "luaTarget": "JIT" diff --git a/benchmark/tsconfig.json b/benchmark/tsconfig.json index aefc13ae9..5422f1770 100644 --- a/benchmark/tsconfig.json +++ b/benchmark/tsconfig.json @@ -3,8 +3,9 @@ "target": "esnext", "lib": ["esnext"], // Dev types are JIT - "types": ["lua-types/jit"], - "moduleResolution": "node", + "types": ["lua-types/jit", "@typescript-to-lua/language-extensions"], + "module": "nodenext", + "moduleResolution": "nodenext", "outDir": "dist", "rootDir": "src", "strict": true, diff --git a/build-lualib.js b/build-lualib.js deleted file mode 100644 index 41ece7e32..000000000 --- a/build-lualib.js +++ /dev/null @@ -1,17 +0,0 @@ -require("ts-node/register/transpile-only"); -const fs = require("fs"); -const path = require("path"); -const ts = require("typescript"); -const tstl = require("./src"); -const { loadLuaLibFeatures } = require("./src/LuaLib"); - -const configFileName = path.resolve(__dirname, "src/lualib/tsconfig.json"); -const { diagnostics } = tstl.transpileProject(configFileName); -diagnostics.forEach(tstl.createDiagnosticReporter(true)); - -const bundlePath = path.join(__dirname, "dist/lualib/lualib_bundle.lua"); -if (fs.existsSync(bundlePath)) { - fs.unlinkSync(bundlePath); -} - -fs.writeFileSync(bundlePath, loadLuaLibFeatures(Object.values(tstl.LuaLibFeature), ts.sys)); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..0ea4d78ca --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,230 @@ +// @ts-check + +import tseslint from "typescript-eslint"; +import eslintPluginJest from "eslint-plugin-jest"; + +export default tseslint.config( + // Enable linting on TypeScript file extensions. + { + files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + }, + + // Base ESLint rules + { + rules: { + "arrow-body-style": "error", + curly: ["error", "multi-line"], + eqeqeq: ["error", "always", { null: "ignore" }], + "no-caller": "error", + "no-cond-assign": "error", + "no-debugger": "error", + "no-duplicate-case": "error", + "no-new-wrappers": "error", + "no-restricted-globals": ["error", "parseInt", "parseFloat"], + "no-unused-labels": "error", + "no-var": "error", + "prefer-const": ["error", { destructuring: "all" }], + radix: "error", + "use-isnan": "error", + "object-shorthand": [ + "error", + "always", + { avoidQuotes: true, ignoreConstructors: false, avoidExplicitReturnArrows: true }, + ], + "no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "SequenceExpression"], + "spaced-comment": [ + "error", + "always", + { + line: { exceptions: ["-", "+"], markers: ["=", "!", "/"] }, + block: { exceptions: ["-", "+"], markers: ["=", "!", ":", "::"], balanced: true }, + }, + ], + "no-delete-var": ["error"], + "no-label-var": ["error"], + yoda: ["error"], + "prefer-numeric-literals": ["error"], + "prefer-rest-params": ["error"], + "prefer-spread": ["error"], + "no-useless-computed-key": ["error"], + "for-direction": ["error"], + "no-compare-neg-zero": ["error"], + "no-dupe-else-if": ["error"], + "no-empty": ["error", { allowEmptyCatch: true }], + "no-implicit-coercion": ["error", { boolean: true, number: true, string: true }], + "operator-assignment": ["error"], + "no-path-concat": ["error"], + "no-control-regex": ["error"], + "no-unneeded-ternary": ["error", { defaultAssignment: false }], + "one-var": ["error", "never"], + "prefer-exponentiation-operator": ["error"], + "prefer-object-spread": ["error"], + "no-useless-catch": ["error"], + "no-useless-concat": ["error"], + "no-useless-escape": ["error"], + "no-useless-return": ["error"], + }, + }, + + // typescript-eslint + { + plugins: { + "@typescript-eslint": tseslint.plugin, + }, + languageOptions: { + parser: tseslint.parser, + parserOptions: { + project: [ + "test/tsconfig.json", + "src/lualib/tsconfig.json", + "src/lualib/tsconfig.lua50.json", + "benchmark/tsconfig.json", + "language-extensions/tsconfig.json", + "tsconfig.eslint.json", + ], + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + rules: { + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/array-type": ["error", { default: "array-simple" }], + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/consistent-type-assertions": [ + "error", + { assertionStyle: "as", objectLiteralTypeAssertions: "never" }, + ], + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/explicit-member-accessibility": ["error", { overrides: { constructors: "no-public" } }], + "@typescript-eslint/naming-convention": [ + "error", + { + selector: "default", + format: ["camelCase"], + leadingUnderscore: "allow", + }, + { + selector: "variable", + format: ["camelCase", "UPPER_CASE"], + leadingUnderscore: "allow", + }, + { + selector: "typeLike", + format: ["PascalCase"], + }, + { + selector: "enumMember", + format: ["PascalCase"], + }, + { + selector: "typeParameter", + format: ["PascalCase"], + prefix: ["T"], + filter: { + regex: "K|V", + match: false, + }, + }, + { + selector: "interface", + format: ["PascalCase"], + custom: { + regex: "^I[A-Z]", + match: false, + }, + }, + { + // Ignore properties that require quotes + selector: "objectLiteralProperty", + modifiers: ["requiresQuotes"], + format: null, + }, + ], + "no-array-constructor": "off", + "@typescript-eslint/no-array-constructor": "error", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-empty-object-type": "error", + "@typescript-eslint/no-extra-non-null-assertion": "error", + "@typescript-eslint/no-extraneous-class": "error", + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-for-in-array": "error", + "@typescript-eslint/no-inferrable-types": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-misused-promises": "error", + "@typescript-eslint/no-namespace": ["error", { allowDeclarations: true }], + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unnecessary-qualifier": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/no-unsafe-function-type": "error", + "no-unused-expressions": "off", + "@typescript-eslint/no-unused-expressions": "error", + "no-useless-constructor": "off", + "@typescript-eslint/no-useless-constructor": "error", + "@typescript-eslint/no-wrapper-object-types": "error", + "no-throw-literal": "off", + "@typescript-eslint/only-throw-error": "error", // "no-throw-literal" was renamed to "only-throw-error". + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-includes": "error", + "@typescript-eslint/prefer-optional-chain": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/prefer-nullish-coalescing": "error", + "@typescript-eslint/prefer-string-starts-ends-with": "error", + "@typescript-eslint/promise-function-async": ["error", { checkArrowFunctions: false }], + "@typescript-eslint/require-await": "error", + "@typescript-eslint/restrict-plus-operands": ["error", { skipCompoundAssignments: false }], + "@typescript-eslint/return-await": "error", + "@typescript-eslint/triple-slash-reference": "error", + "@typescript-eslint/unified-signatures": "error", + }, + }, + + // eslint-plugin-jest + eslintPluginJest.configs["flat/recommended"], + eslintPluginJest.configs["flat/style"], + { + rules: { + "jest/expect-expect": "off", + "jest/consistent-test-it": ["error", { fn: "test", withinDescribe: "test" }], + "jest/no-disabled-tests": "error", + "jest/no-identical-title": "off", + "jest/no-test-return-statement": "error", + "jest/prefer-spy-on": "error", + "jest/prefer-todo": "error", + "jest/valid-title": "error", + // TODO: + // "jest/lowercase-name": "error", + }, + }, + + // Exceptions for specific files/directories + { + files: ["src/lualib/**/*.ts"], + rules: { + "no-restricted-syntax": ["error", "LabeledStatement", "SequenceExpression"], + "@typescript-eslint/only-throw-error": "off", + "@typescript-eslint/prefer-optional-chain": "off", + "@typescript-eslint/naming-convention": "off", + }, + }, + + // Ignore some specific files and directories + { + ignores: [ + ".github/scripts/create_benchmark_check.js", + "dist/", + "eslint.config.mjs", + "jest.config.js", + "test/cli/errors/", + "test/cli/watch/", + "test/translation/transformation/", + "test/transpile/directories/", + "test/transpile/module-resolution/**/node_modules/", + "test/transpile/module-resolution/**/dist/", + "test/transpile/outFile/", + "test/transpile/resolve-plugin/", + ], + } +); diff --git a/jest.config.js b/jest.config.js index 2d390c93d..26b60c1cf 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,4 @@ -const isCI = require("is-ci"); +const isCI = process.env.GITHUB_ACTIONS !== undefined; /** @type {Partial} */ module.exports = { @@ -15,10 +15,13 @@ module.exports = { testEnvironment: "node", testRunner: "jest-circus/runner", preset: "ts-jest", - globals: { - "ts-jest": { - tsconfig: "/test/tsconfig.json", - diagnostics: { warnOnly: !isCI }, - }, + transform: { + "^.+\\.ts?$": [ + "ts-jest", + { + tsconfig: "/test/tsconfig.json", + diagnostics: { warnOnly: !isCI }, + }, + ], }, }; diff --git a/language-extensions/index.d.ts b/language-extensions/index.d.ts index 30eb70009..6d805f189 100644 --- a/language-extensions/index.d.ts +++ b/language-extensions/index.d.ts @@ -1,14 +1,28 @@ +/* eslint-disable @typescript-eslint/naming-convention */ + type AnyTable = Record; -// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/consistent-type-definitions +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions,@typescript-eslint/no-empty-object-type type AnyNotNil = {}; /** - * Indicates a type is a language extension provided by TypescriptToLua. + * Indicates a type is a language extension provided by TypescriptToLua when used as a value or function call. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * + * @param TBrand A string used to uniquely identify the language extension type + */ +declare interface LuaExtension { + readonly __tstlExtension: TBrand; +} + +/** + * Indicates a type is a language extension provided by TypescriptToLua when used in a for-of loop. * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions * * @param TBrand A string used to uniquely identify the language extension type */ -declare type LuaExtension = { [T in TBrand]: { readonly __luaExtensionSymbol: unique symbol } }; +declare interface LuaIterationExtension { + readonly __tstlIterable: TBrand; +} /** * Returns multiple values from a function, by wrapping them in a LuaMultiReturn tuple. @@ -17,7 +31,7 @@ declare type LuaExtension = { [T in TBrand]: { readonly _ * @param T A tuple type with each element type representing a return value's type. * @param values Return values. */ -declare const $multi: ((...values: T) => LuaMultiReturn) & LuaExtension<"__luaMultiFunctionBrand">; +declare const $multi: ((...values: T) => LuaMultiReturn) & LuaExtension<"MultiFunction">; /** * Represents multiple return values as a tuple. @@ -25,7 +39,9 @@ declare const $multi: ((...values: T) => LuaMultiReturn) & L * * @param T A tuple type with each element type representing a return value's type. */ -declare type LuaMultiReturn = T & LuaExtension<"__luaMultiReturnBrand">; +declare type LuaMultiReturn = T & { + readonly __tstlMultiReturn: any; +}; /** * Creates a Lua-style numeric for loop (for i=start,limit,step) when used in for...of. Not valid in any other context. @@ -36,13 +52,13 @@ declare type LuaMultiReturn = T & LuaExtension<"__luaMultiRetur * @param step The amount to increment each iteration. */ declare const $range: ((start: number, limit: number, step?: number) => Iterable) & - LuaExtension<"__luaRangeFunctionBrand">; + LuaExtension<"RangeFunction">; /** * Transpiles to the global vararg (`...`) * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions */ -declare const $vararg: string[] & LuaExtension<"__luaVarargConstantBrand">; +declare const $vararg: string[] & LuaExtension<"VarargConstant">; /** * Represents a Lua-style iterator which is returned from a LuaIterable. @@ -76,7 +92,24 @@ declare type LuaIterator = TState extends undefined */ declare type LuaIterable = Iterable & LuaIterator & - LuaExtension<"__luaIterableBrand">; + LuaIterationExtension<"Iterable">; + +/** + * Represents an object that can be iterated with pairs() + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * + * @param TKey The type of the key returned each iteration. + * @param TValue The type of the value returned each iteration. + */ +declare type LuaPairsIterable = Iterable<[TKey, TValue]> & + LuaIterationExtension<"Pairs">; + +/** + * Represents an object that can be iterated with pairs(), where only the key value is used. + * + * @param TKey The type of the key returned each iteration. + */ +declare type LuaPairsKeyIterable = Iterable & LuaIterationExtension<"PairsKey">; /** * Calls to functions with this type are translated to `left + right`. @@ -86,8 +119,7 @@ declare type LuaIterable = Iterable & * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaAddition = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaAdditionBrand">; +declare type LuaAddition = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"Addition">; /** * Calls to methods with this type are translated to `left + right`, where `left` is the object with the method. @@ -96,8 +128,7 @@ declare type LuaAddition = ((left: TLeft, right: TRight) * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaAdditionMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaAdditionMethodBrand">; +declare type LuaAdditionMethod = ((right: TRight) => TReturn) & LuaExtension<"AdditionMethod">; /** * Calls to functions with this type are translated to `left - right`. @@ -108,7 +139,7 @@ declare type LuaAdditionMethod = ((right: TRight) => TReturn) & * @param TReturn The resulting (return) type of the operation. */ declare type LuaSubtraction = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaSubtractionBrand">; + LuaExtension<"Subtraction">; /** * Calls to methods with this type are translated to `left - right`, where `left` is the object with the method. @@ -117,8 +148,7 @@ declare type LuaSubtraction = ((left: TLeft, right: TRig * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaSubtractionMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaSubtractionMethodBrand">; +declare type LuaSubtractionMethod = ((right: TRight) => TReturn) & LuaExtension<"SubtractionMethod">; /** * Calls to functions with this type are translated to `left * right`. @@ -129,7 +159,7 @@ declare type LuaSubtractionMethod = ((right: TRight) => TReturn * @param TReturn The resulting (return) type of the operation. */ declare type LuaMultiplication = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaMultiplicationBrand">; + LuaExtension<"Multiplication">; /** * Calls to methods with this type are translated to `left * right`, where `left` is the object with the method. @@ -139,7 +169,7 @@ declare type LuaMultiplication = ((left: TLeft, right: T * @param TReturn The resulting (return) type of the operation. */ declare type LuaMultiplicationMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaMultiplicationMethodBrand">; + LuaExtension<"MultiplicationMethod">; /** * Calls to functions with this type are translated to `left / right`. @@ -149,8 +179,7 @@ declare type LuaMultiplicationMethod = ((right: TRight) => TRet * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaDivision = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaDivisionBrand">; +declare type LuaDivision = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"Division">; /** * Calls to methods with this type are translated to `left / right`, where `left` is the object with the method. @@ -159,8 +188,7 @@ declare type LuaDivision = ((left: TLeft, right: TRight) * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaDivisionMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaDivisionMethodBrand">; +declare type LuaDivisionMethod = ((right: TRight) => TReturn) & LuaExtension<"DivisionMethod">; /** * Calls to functions with this type are translated to `left % right`. @@ -170,8 +198,7 @@ declare type LuaDivisionMethod = ((right: TRight) => TReturn) & * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaModulo = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaModuloBrand">; +declare type LuaModulo = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"Modulo">; /** * Calls to methods with this type are translated to `left % right`, where `left` is the object with the method. @@ -180,7 +207,7 @@ declare type LuaModulo = ((left: TLeft, right: TRight) = * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaModuloMethod = ((right: TRight) => TReturn) & LuaExtension<"__luaModuloMethodBrand">; +declare type LuaModuloMethod = ((right: TRight) => TReturn) & LuaExtension<"ModuloMethod">; /** * Calls to functions with this type are translated to `left ^ right`. @@ -190,8 +217,7 @@ declare type LuaModuloMethod = ((right: TRight) => TReturn) & L * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaPower = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaPowerBrand">; +declare type LuaPower = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"Power">; /** * Calls to methods with this type are translated to `left ^ right`, where `left` is the object with the method. @@ -200,7 +226,7 @@ declare type LuaPower = ((left: TLeft, right: TRight) => * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaPowerMethod = ((right: TRight) => TReturn) & LuaExtension<"__luaPowerMethodBrand">; +declare type LuaPowerMethod = ((right: TRight) => TReturn) & LuaExtension<"PowerMethod">; /** * Calls to functions with this type are translated to `left // right`. @@ -211,7 +237,7 @@ declare type LuaPowerMethod = ((right: TRight) => TReturn) & Lu * @param TReturn The resulting (return) type of the operation. */ declare type LuaFloorDivision = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaFloorDivisionBrand">; + LuaExtension<"FloorDivision">; /** * Calls to methods with this type are translated to `left // right`, where `left` is the object with the method. @@ -221,7 +247,7 @@ declare type LuaFloorDivision = ((left: TLeft, right: TR * @param TReturn The resulting (return) type of the operation. */ declare type LuaFloorDivisionMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaFloorDivisionMethodBrand">; + LuaExtension<"FloorDivisionMethod">; /** * Calls to functions with this type are translated to `left & right`. @@ -232,7 +258,7 @@ declare type LuaFloorDivisionMethod = ((right: TRight) => TRetu * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseAnd = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseAndBrand">; + LuaExtension<"BitwiseAnd">; /** * Calls to methods with this type are translated to `left & right`, where `left` is the object with the method. @@ -241,8 +267,7 @@ declare type LuaBitwiseAnd = ((left: TLeft, right: TRigh * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaBitwiseAndMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseAndMethodBrand">; +declare type LuaBitwiseAndMethod = ((right: TRight) => TReturn) & LuaExtension<"BitwiseAndMethod">; /** * Calls to functions with this type are translated to `left | right`. @@ -253,7 +278,7 @@ declare type LuaBitwiseAndMethod = ((right: TRight) => TReturn) * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseOr = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseOrBrand">; + LuaExtension<"BitwiseOr">; /** * Calls to methods with this type are translated to `left | right`, where `left` is the object with the method. @@ -262,8 +287,7 @@ declare type LuaBitwiseOr = ((left: TLeft, right: TRight * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaBitwiseOrMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseOrMethodBrand">; +declare type LuaBitwiseOrMethod = ((right: TRight) => TReturn) & LuaExtension<"BitwiseOrMethod">; /** * Calls to functions with this type are translated to `left ~ right`. @@ -274,7 +298,7 @@ declare type LuaBitwiseOrMethod = ((right: TRight) => TReturn) * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseExclusiveOr = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseExclusiveOrBrand">; + LuaExtension<"BitwiseExclusiveOr">; /** * Calls to methods with this type are translated to `left ~ right`, where `left` is the object with the method. @@ -284,7 +308,7 @@ declare type LuaBitwiseExclusiveOr = ((left: TLeft, righ * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseExclusiveOrMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseExclusiveOrMethodBrand">; + LuaExtension<"BitwiseExclusiveOrMethod">; /** * Calls to functions with this type are translated to `left << right`. @@ -295,7 +319,7 @@ declare type LuaBitwiseExclusiveOrMethod = ((right: TRight) => * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseLeftShift = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseLeftShiftBrand">; + LuaExtension<"BitwiseLeftShift">; /** * Calls to methods with this type are translated to `left << right`, where `left` is the object with the method. @@ -305,7 +329,7 @@ declare type LuaBitwiseLeftShift = ((left: TLeft, right: * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseLeftShiftMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseLeftShiftMethodBrand">; + LuaExtension<"BitwiseLeftShiftMethod">; /** * Calls to functions with this type are translated to `left >> right`. @@ -316,7 +340,7 @@ declare type LuaBitwiseLeftShiftMethod = ((right: TRight) => TR * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseRightShift = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseRightShiftBrand">; + LuaExtension<"BitwiseRightShift">; /** * Calls to methods with this type are translated to `left >> right`, where `left` is the object with the method. @@ -326,7 +350,7 @@ declare type LuaBitwiseRightShift = ((left: TLeft, right * @param TReturn The resulting (return) type of the operation. */ declare type LuaBitwiseRightShiftMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaBitwiseRightShiftMethodBrand">; + LuaExtension<"BitwiseRightShiftMethod">; /** * Calls to functions with this type are translated to `left .. right`. @@ -336,8 +360,7 @@ declare type LuaBitwiseRightShiftMethod = ((right: TRight) => T * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaConcat = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaConcatBrand">; +declare type LuaConcat = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"Concat">; /** * Calls to methods with this type are translated to `left .. right`, where `left` is the object with the method. @@ -346,7 +369,7 @@ declare type LuaConcat = ((left: TLeft, right: TRight) = * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaConcatMethod = ((right: TRight) => TReturn) & LuaExtension<"__luaConcatMethodBrand">; +declare type LuaConcatMethod = ((right: TRight) => TReturn) & LuaExtension<"ConcatMethod">; /** * Calls to functions with this type are translated to `left < right`. @@ -356,8 +379,7 @@ declare type LuaConcatMethod = ((right: TRight) => TReturn) & L * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaLessThan = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaLessThanBrand">; +declare type LuaLessThan = ((left: TLeft, right: TRight) => TReturn) & LuaExtension<"LessThan">; /** * Calls to methods with this type are translated to `left < right`, where `left` is the object with the method. @@ -366,8 +388,7 @@ declare type LuaLessThan = ((left: TLeft, right: TRight) * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaLessThanMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaLessThanMethodBrand">; +declare type LuaLessThanMethod = ((right: TRight) => TReturn) & LuaExtension<"LessThanMethod">; /** * Calls to functions with this type are translated to `left > right`. @@ -378,7 +399,7 @@ declare type LuaLessThanMethod = ((right: TRight) => TReturn) & * @param TReturn The resulting (return) type of the operation. */ declare type LuaGreaterThan = ((left: TLeft, right: TRight) => TReturn) & - LuaExtension<"__luaGreaterThanBrand">; + LuaExtension<"GreaterThan">; /** * Calls to methods with this type are translated to `left > right`, where `left` is the object with the method. @@ -387,8 +408,7 @@ declare type LuaGreaterThan = ((left: TLeft, right: TRig * @param TRight The type of the right-hand-side of the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaGreaterThanMethod = ((right: TRight) => TReturn) & - LuaExtension<"__luaGreaterThanMethodBrand">; +declare type LuaGreaterThanMethod = ((right: TRight) => TReturn) & LuaExtension<"GreaterThanMethod">; /** * Calls to functions with this type are translated to `-operand`. @@ -397,7 +417,7 @@ declare type LuaGreaterThanMethod = ((right: TRight) => TReturn * @param TOperand The type of the value in the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaNegation = ((operand: TOperand) => TReturn) & LuaExtension<"__luaNegationBrand">; +declare type LuaNegation = ((operand: TOperand) => TReturn) & LuaExtension<"Negation">; /** * Calls to method with this type are translated to `-operand`, where `operand` is the object with the method. @@ -405,7 +425,7 @@ declare type LuaNegation = ((operand: TOperand) => TReturn) & * * @param TReturn The resulting (return) type of the operation. */ -declare type LuaNegationMethod = (() => TReturn) & LuaExtension<"__luaNegationMethodBrand">; +declare type LuaNegationMethod = (() => TReturn) & LuaExtension<"NegationMethod">; /** * Calls to functions with this type are translated to `~operand`. @@ -414,7 +434,7 @@ declare type LuaNegationMethod = (() => TReturn) & LuaExtension<"__luaN * @param TOperand The type of the value in the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaBitwiseNot = ((operand: TOperand) => TReturn) & LuaExtension<"__luaBitwiseNotBrand">; +declare type LuaBitwiseNot = ((operand: TOperand) => TReturn) & LuaExtension<"BitwiseNot">; /** * Calls to method with this type are translated to `~operand`, where `operand` is the object with the method. @@ -422,7 +442,7 @@ declare type LuaBitwiseNot = ((operand: TOperand) => TReturn) * * @param TReturn The resulting (return) type of the operation. */ -declare type LuaBitwiseNotMethod = (() => TReturn) & LuaExtension<"__luaBitwiseNotMethodBrand">; +declare type LuaBitwiseNotMethod = (() => TReturn) & LuaExtension<"BitwiseNotMethod">; /** * Calls to functions with this type are translated to `#operand`. @@ -431,7 +451,7 @@ declare type LuaBitwiseNotMethod = (() => TReturn) & LuaExtension<"__lu * @param TOperand The type of the value in the operation. * @param TReturn The resulting (return) type of the operation. */ -declare type LuaLength = ((operand: TOperand) => TReturn) & LuaExtension<"__luaLengthBrand">; +declare type LuaLength = ((operand: TOperand) => TReturn) & LuaExtension<"Length">; /** * Calls to method with this type are translated to `#operand`, where `operand` is the object with the method. @@ -439,7 +459,7 @@ declare type LuaLength = ((operand: TOperand) => TReturn) & L * * @param TReturn The resulting (return) type of the operation. */ -declare type LuaLengthMethod = (() => TReturn) & LuaExtension<"__luaLengthMethodBrand">; +declare type LuaLengthMethod = (() => TReturn) & LuaExtension<"LengthMethod">; /** * Calls to functions with this type are translated to `table[key]`. @@ -453,7 +473,7 @@ declare type LuaTableGet TValue) & - LuaExtension<"__luaTableGetBrand">; + LuaExtension<"TableGet">; /** * Calls to methods with this type are translated to `table[key]`, where `table` is the object with the method. @@ -463,7 +483,7 @@ declare type LuaTableGet = ((key: TKey) => TValue) & - LuaExtension<"__luaTableGetMethodBrand">; + LuaExtension<"TableGetMethod">; /** * Calls to functions with this type are translated to `table[key] = value`. @@ -478,7 +498,7 @@ declare type LuaTableSet void) & - LuaExtension<"__luaTableSetBrand">; + LuaExtension<"TableSet">; /** * Calls to methods with this type are translated to `table[key] = value`, where `table` is the object with the method. @@ -488,7 +508,24 @@ declare type LuaTableSet = ((key: TKey, value: TValue) => void) & - LuaExtension<"__luaTableSetMethodBrand">; + LuaExtension<"TableSetMethod">; + +/** + * Calls to functions with this type are translated to `table[key] = true`. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * + * @param TTable The type to access as a Lua table. + * @param TKey The type of the key to use to access the table. + */ +declare type LuaTableAddKey = ((table: TTable, key: TKey) => void) & + LuaExtension<"TableAddKey">; + +/** + * Calls to methods with this type are translated to `table[key] = true`, where `table` is the object with the method. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * @param TKey The type of the key to use to access the table. + */ +declare type LuaTableAddKeyMethod = ((key: TKey) => void) & LuaExtension<"TableAddKeyMethod">; /** * Calls to functions with this type are translated to `table[key] ~= nil`. @@ -498,7 +535,7 @@ declare type LuaTableSetMethod = ((key: TKey, va * @param TKey The type of the key to use to access the table. */ declare type LuaTableHas = ((table: TTable, key: TKey) => boolean) & - LuaExtension<"__luaTableHasBrand">; + LuaExtension<"TableHas">; /** * Calls to methods with this type are translated to `table[key] ~= nil`, where `table` is the object with the method. @@ -506,8 +543,7 @@ declare type LuaTableHas = ((ta * * @param TKey The type of the key to use to access the table. */ -declare type LuaTableHasMethod = ((key: TKey) => boolean) & - LuaExtension<"__luaTableHasMethodBrand">; +declare type LuaTableHasMethod = ((key: TKey) => boolean) & LuaExtension<"TableHasMethod">; /** * Calls to functions with this type are translated to `table[key] = nil`. @@ -517,7 +553,7 @@ declare type LuaTableHasMethod = ((key: TKey) => boolean * @param TKey The type of the key to use to access the table. */ declare type LuaTableDelete = ((table: TTable, key: TKey) => boolean) & - LuaExtension<"__luaTableDeleteBrand">; + LuaExtension<"TableDelete">; /** * Calls to methods with this type are translated to `table[key] = nil`, where `table` is the object with the method. @@ -526,7 +562,21 @@ declare type LuaTableDelete = ( * @param TKey The type of the key to use to access the table. */ declare type LuaTableDeleteMethod = ((key: TKey) => boolean) & - LuaExtension<"__luaTableDeleteMethodBrand">; + LuaExtension<"TableDeleteMethod">; + +/** + * Calls to functions with this type are translated to `next(myTable) == nil`. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * + * @param TTable The type to access as a Lua table. + */ +declare type LuaTableIsEmpty = ((table: TTable) => boolean) & LuaExtension<"TableIsEmpty">; + +/** + * Calls to methods with this type are translated to `next(myTable) == nil`, where `table` is the object with the method. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + */ +declare type LuaTableIsEmptyMethod = (() => boolean) & LuaExtension<"TableIsEmptyMethod">; /** * A convenience type for working directly with a Lua table. @@ -535,12 +585,13 @@ declare type LuaTableDeleteMethod = ((key: TKey) => bool * @param TKey The type of the keys used to access the table. * @param TValue The type of the values stored in the table. */ -declare interface LuaTable { +declare interface LuaTable extends LuaPairsIterable { length: LuaLengthMethod; get: LuaTableGetMethod; set: LuaTableSetMethod; has: LuaTableHasMethod; delete: LuaTableDeleteMethod; + isEmpty: LuaTableIsEmptyMethod; } /** @@ -554,7 +605,7 @@ declare type LuaTableConstructor = (new ) & - LuaExtension<"__luaTableNewBrand">; + LuaExtension<"TableNew">; /** * A convenience type for working directly with a Lua table. @@ -564,3 +615,83 @@ declare type LuaTableConstructor = (new extends LuaPairsIterable { + get: LuaTableGetMethod; + set: LuaTableSetMethod; + has: LuaTableHasMethod; + delete: LuaTableDeleteMethod; + isEmpty: LuaTableIsEmptyMethod; +} + +/** + * A convenience type for working directly with a Lua table, used as a map. + * + * This differs from LuaTable in that the `get` method may return `nil`. + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * @param K The type of the keys used to access the table. + * @param V The type of the values stored in the table. + */ +declare const LuaMap: (new () => LuaMap) & LuaExtension<"TableNew">; + +/** + * Readonly version of {@link LuaMap}. + * + * @param K The type of the keys used to access the table. + * @param V The type of the values stored in the table. + */ +declare interface ReadonlyLuaMap extends LuaPairsIterable { + get: LuaTableGetMethod; + has: LuaTableHasMethod; + isEmpty: LuaTableIsEmptyMethod; +} + +/** + * A convenience type for working directly with a Lua table, used as a set. + * + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * @param T The type of the keys used to access the table. + */ +declare interface LuaSet extends LuaPairsKeyIterable { + add: LuaTableAddKeyMethod; + has: LuaTableHasMethod; + delete: LuaTableDeleteMethod; + isEmpty: LuaTableIsEmptyMethod; +} + +/** + * A convenience type for working directly with a Lua table, used as a set. + * + * For more information see: https://typescripttolua.github.io/docs/advanced/language-extensions + * @param T The type of the keys used to access the table. + */ +declare const LuaSet: (new () => LuaSet) & LuaExtension<"TableNew">; + +/** + * Readonly version of {@link LuaSet}. + * + * @param T The type of the keys used to access the table. + */ +declare interface ReadonlyLuaSet extends LuaPairsKeyIterable { + has: LuaTableHasMethod; + isEmpty: LuaTableIsEmptyMethod; +} + +interface ObjectConstructor { + /** Returns an array of keys of an object, when iterated with `pairs`. */ + keys(o: LuaPairsIterable | LuaPairsKeyIterable): K[]; + + /** Returns an array of values of an object, when iterated with `pairs`. */ + values(o: LuaPairsIterable): V[]; + + /** Returns an array of key/values of an object, when iterated with `pairs`. */ + entries(o: LuaPairsIterable): Array<[K, V]>; +} diff --git a/language-extensions/package.json b/language-extensions/package.json new file mode 100644 index 000000000..194ab1212 --- /dev/null +++ b/language-extensions/package.json @@ -0,0 +1,23 @@ +{ + "name": "@typescript-to-lua/language-extensions", + "version": "1.19.0", + "description": "Language extensions used by typescript-to-lua", + "repository": "https://github.com/TypeScriptToLua/TypeScriptToLua", + "homepage": "https://typescripttolua.github.io/", + "bugs": { + "url": "https://github.com/TypeScriptToLua/TypeScriptToLua/issues" + }, + "license": "MIT", + "keywords": [ + "typescript", + "lua", + "tstl", + "transpiler", + "language extensions" + ], + "files": [ + "**.d.ts" + ], + "main": "", + "types": "index.d.ts" +} diff --git a/language-extensions/tsconfig.json b/language-extensions/tsconfig.json new file mode 100644 index 000000000..92894f9c4 --- /dev/null +++ b/language-extensions/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": ["esnext"], + "strict": true + } +} diff --git a/package-lock.json b/package-lock.json index 35fb97cf6..31aafbbcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,306 +1,285 @@ { "name": "typescript-to-lua", - "version": "0.41.0", - "lockfileVersion": 2, + "version": "1.37.1", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "typescript-to-lua", - "version": "0.41.0", + "version": "1.37.1", "license": "MIT", "dependencies": { - "enhanced-resolve": "^5.8.2", + "@typescript-to-lua/language-extensions": "1.19.0", + "enhanced-resolve": "5.8.2", + "picomatch": "^2.3.1", "resolve": "^1.15.1", - "source-map": "^0.7.3", - "typescript": "~4.3.2" + "source-map": "^0.7.3" }, "bin": { "tstl": "dist/tstl.js" }, "devDependencies": { "@types/fs-extra": "^8.1.0", - "@types/glob": "^7.1.1", - "@types/jest": "^25.1.3", - "@types/node": "^13.7.7", + "@types/glob": "^7.2.0", + "@types/jest": "^27.5.2", + "@types/node": "^22.10.0", + "@types/picomatch": "^2.3.0", "@types/resolve": "1.14.0", - "@typescript-eslint/eslint-plugin": "^4.26.1", - "@typescript-eslint/parser": "^4.26.1", - "eslint": "^7.28.0", - "eslint-plugin-import": "^2.20.1", - "eslint-plugin-jest": "^23.8.2", + "eslint": "^9.39.4", + "eslint-plugin-jest": "^28.14.0", "fs-extra": "^8.1.0", "javascript-stringify": "^2.0.1", - "jest": "^26.0.1", - "jest-circus": "^25.1.0", - "lua-types": "^2.8.0", - "lua-wasm-bindings": "^0.2.2", - "prettier": "^2.3.2", - "ts-jest": "^26.3.0", - "ts-node": "^8.6.2" + "jest": "^29.7.0", + "jest-circus": "^29.7.0", + "lua-types": "^2.14.1", + "lua-wasm-bindings": "^0.5.3", + "prettier": "^2.8.8", + "ts-jest": "^29.4.9", + "ts-node": "^10.9.2", + "typescript": "6.0.2", + "typescript-eslint": "^8.58.0" }, "engines": { - "node": ">=12.13.0" + "node": ">=16.10.0" + }, + "peerDependencies": { + "typescript": "6.0.2" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/highlight": "^7.12.13" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/core": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.6.tgz", - "integrity": "sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg==", + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.6", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.6", - "@babel/parser": "^7.9.6", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", - "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, - "dependencies": { - "@babel/types": "^7.14.2", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "license": "MIT", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", - "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", + "node_modules/@babel/generator": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.14.2" + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.12.13" + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@babel/types": "^7.8.3" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", - "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.9.0", - "lodash": "^4.17.13" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.8.3" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", - "dev": true - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz", - "integrity": "sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "node_modules/@babel/helpers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", - "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, - "dependencies": { - "color-name": "1.1.3" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz", - "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -313,8 +292,12 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-bigint": { @@ -322,17 +305,70 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz", - "integrity": "sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-json-strings": { @@ -340,17 +376,41 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz", - "integrity": "sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { @@ -358,17 +418,25 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", - "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-object-rest-spread": { @@ -376,8 +444,12 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { @@ -385,8 +457,12 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-optional-chaining": { @@ -394,3648 +470,3831 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", - "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.2", - "@babel/helper-function-name": "^7.14.2", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.2", - "@babel/types": "^7.14.2", - "debug": "^4.1.0", - "globals": "^11.1.0" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/types": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", - "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, + "license": "MIT", "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { - "node": ">=0.1.95" + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "node_modules/@babel/traverse": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", + "globals": "^11.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@jest/console": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.5.0.tgz", - "integrity": "sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "jest-message-util": "^25.5.0", - "jest-util": "^25.5.0", - "slash": "^3.0.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">= 8.3" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@jest/core": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.0.1.tgz", - "integrity": "sha512-Xq3eqYnxsG9SjDC+WLeIgf7/8KU6rddBxH+SCt18gEpOhAGYC/Mq+YbtlNcIdwjnnT+wDseXSbU0e5X84Y4jTQ==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "@jest/console": "^26.0.1", - "@jest/reporters": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.0.1", - "jest-config": "^26.0.1", - "jest-haste-map": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-resolve-dependencies": "^26.0.1", - "jest-runner": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "jest-watcher": "^26.0.1", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 10.14.2" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jest/core/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@jest/core/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@eslint/core": "^0.17.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/core/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/istanbul-lib-report": "*" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/core/node_modules/@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jest/core/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@jest/core/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/core/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@jest/core/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=18.18.0" } }, - "node_modules/@jest/core/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/core/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, "engines": { - "node": ">= 10.14.2" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/core/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/@jest/core/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "engines": { - "node": ">= 10.14.2" + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@jest/core/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/@jest/core/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "engines": { - "node": ">= 10.14.2" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@jest/core/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/@jest/core/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "p-try": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@jest/core/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@jest/core/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@jest/core/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/core/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/core/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "escape-string-regexp": "^2.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/environment": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.5.0.tgz", - "integrity": "sha512-U2VXPEqL07E/V7pSZMSQCvV5Ea4lqOlT+0ZFijl/i316cRMHvZ4qC+jBdryd+lmRetjQo0YIQr6cVPNxxK87mA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/fake-timers": "^25.5.0", - "@jest/types": "^25.5.0", - "jest-mock": "^25.5.0" + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" }, "engines": { - "node": ">= 8.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/fake-timers": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.5.0.tgz", - "integrity": "sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ==", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-mock": "^25.5.0", - "jest-util": "^25.5.0", - "lolex": "^5.0.0" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": ">= 8.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.0.1.tgz", - "integrity": "sha512-iuucxOYB7BRCvT+TYBzUqUNuxFX1hqaR6G6IcGgEqkJ5x4htNKo1r7jk1ji9Zj8ZMiMw0oB5NaA7k5Tx6MVssA==", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/environment": "^26.0.1", - "@jest/types": "^26.0.1", - "expect": "^26.0.1" + "jest-get-type": "^29.6.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-mock": "^26.6.2" + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/globals/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@jest/globals/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/@jest/globals/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/globals/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@jest/globals/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, + "license": "MIT", "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": ">=6.0.0" } }, - "node_modules/@jest/globals/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jest/globals/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" }, - "node_modules/@jest/globals/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" + "type-detect": "4.0.8" } }, - "node_modules/@jest/reporters": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.0.1.tgz", - "integrity": "sha512-NWWy9KwRtE1iyG/m7huiFVF9YsYv/e+mbflKRV84WDoJfBqUrNRyDbL/vFxQcYLl8IRqI4P3MgPn386x76Gf2g==", + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.0.1", - "jest-resolve": "^26.0.1", - "jest-util": "^26.0.1", - "jest-worker": "^26.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^4.1.3" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^7.0.0" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@jest/reporters/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@jest/reporters/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@babel/types": "^7.0.0" } }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@jest/reporters/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-report": "*" + "@babel/types": "^7.20.7" } }, - "node_modules/@jest/reporters/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/@jest/reporters/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@types/istanbul-lib-report": "*" } }, - "node_modules/@jest/reporters/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/@types/jest": { + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" } }, - "node_modules/@jest/reporters/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", "dev": true, + "peer": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" + "undici-types": "~6.20.0" } }, - "node_modules/@jest/reporters/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/@types/picomatch": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.4.tgz", + "integrity": "sha512-0so8lU8O5zatZS/2Fi4zrwks+vZv7e0dygrgEZXljODXBig97l4cPQD+9LabXfGJOWwoRkTVz6Q4edZvD12UOA==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/@jest/reporters/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@types/resolve": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.14.0.tgz", + "integrity": "sha512-bmjNBW6tok+67iOsASeYSJxSgY++BIR35nGyGLORTDirhra9reJ0shgGL3U7KPDUbOBCx8JrlCjd4d/y5uiMRQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/stack-utils": { + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/@jest/source-map": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.0.0.tgz", - "integrity": "sha512-S2Z+Aj/7KOSU2TfW0dyzBze7xr95bkm5YXNUqqCek+HE0VbNNSNzrRwfIi5lf7wvzDTSS0/ib8XQ1krFNyYgbQ==", + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" + "@types/yargs-parser": "*" } }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/@jest/test-result": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.5.0.tgz", - "integrity": "sha512-oV+hPJgXN7IQf/fHWkcS99y0smKLU2czLBJ9WA0jHITLst58HpQMtzSYxzaBvYc6U5U6jfoMthqsUlUlbRXs0A==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", "dev": true, - "dependencies": { - "@jest/console": "^25.5.0", - "@jest/types": "^25.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">= 8.3" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz", - "integrity": "sha512-ssga8XlwfP8YjbDcmVhwNlrmblddMfgUeAkWIXts1V22equp2GMIHxm7cyeD5Q/B0ZgKPK/tngt45sH99yLLGg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "dependencies": { - "@jest/test-result": "^26.0.1", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.0.1", - "jest-runner": "^26.0.1", - "jest-runtime": "^26.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": ">= 4" } }, - "node_modules/@jest/test-sequencer/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "node_modules/@typescript-eslint/parser": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", + "debug": "^4.4.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@jest/test-sequencer/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/@jest/test-sequencer/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/@typescript-eslint/types": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/test-sequencer/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">= 10.14.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@jest/test-sequencer/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/test-sequencer/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 10" + "node": "18 || 20 || >=22" } }, - "node_modules/@jest/test-sequencer/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@jest/test-sequencer/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, + "license": "MIT", "dependencies": { - "escape-string-regexp": "^2.0.0" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" } }, - "node_modules/@jest/transform": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.0.1.tgz", - "integrity": "sha512-pPRkVkAQ91drKGbzCfDOoHN838+FSbYaEAvBXvKuWeeRRUD8FjwXkqfUNUZL6Ke48aA/1cqq/Ni7kVMCoqagWA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.0.1", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.0.1", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">= 10.14.2" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@typescript-eslint/utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" }, "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/@jest/transform/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@jest/transform/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 10.14.2" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@jest/transform/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/@typescript-to-lua/language-extensions": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@typescript-to-lua/language-extensions/-/language-extensions-1.19.0.tgz", + "integrity": "sha512-Os5wOKwviTD4LeqI29N0btYOjokSJ97iCf45EOjIABlb5IwNQy7AE/AqZJobRw3ywHH8+KzJUMkEirWPzh2tUA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.4.0" } }, - "node_modules/@jest/transform/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@jest/types": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" + "acorn": "^8.11.0" }, "engines": { - "node": ">= 8.3" + "node": ">=0.4.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", - "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "node": ">=8" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", - "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@types/babel__core": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz", - "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", - "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } + "license": "MIT" }, - "node_modules/@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } + "license": "Python-2.0" }, - "node_modules/@types/babel__traverse": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.11.tgz", - "integrity": "sha512-ddHK5icION5U6q11+tV2f9Mo6CZVuT8GJKld2q9LqHSZbvLbH34Kcu2yFGckZut453+eQU6btIA3RihmnRgI+Q==", + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.3.0" + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "node_modules/@types/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@types/node": "*" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz", - "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==", + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@types/jest": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz", - "integrity": "sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==", + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "license": "MIT", "dependencies": { - "jest-diff": "^25.2.1", - "pretty-format": "^25.2.1" + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "13.7.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz", - "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.14.0.tgz", - "integrity": "sha512-bmjNBW6tok+67iOsASeYSJxSgY++BIR35nGyGLORTDirhra9reJ0shgGL3U7KPDUbOBCx8JrlCjd4d/y5uiMRQ==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true + "license": "MIT" }, - "node_modules/@types/yargs": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", - "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", + "node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.1.tgz", - "integrity": "sha512-aoIusj/8CR+xDWmZxARivZjbMBQTT9dImUtdZ8tVCVRXgBUuuZyM5Of5A9D9arQPxbi/0rlJLcuArclz/rCMJw==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "4.26.1", - "@typescript-eslint/scope-manager": "4.26.1", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.21", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "fill-range": "^7.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=8" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.1.tgz", - "integrity": "sha512-sQHBugRhrXzRCs9PaGg6rowie4i8s/iD/DpTB+EXte8OMDfdCG5TvO73XlO9Wc/zi0uyN4qOmX9hIjQEyhnbmQ==", + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.26.1", - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/typescript-estree": "4.26.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "bin": { + "browserslist": "cli.js" }, - "peerDependencies": { - "eslint": "*" + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz", - "integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "fast-json-stable-stringify": "2.x" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">= 6" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "node-int64": "^0.4.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz", - "integrity": "sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.31.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/@typescript-eslint/parser": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.26.1.tgz", - "integrity": "sha512-q7F3zSo/nU6YJpPJvQveVlIIzx9/wu75lr6oDbDzoeIRWxpoc/HQ43G4rmMoCc5my/3uSj2VEpg/D83LYZF5HQ==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "4.26.1", - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/typescript-estree": "4.26.1", - "debug": "^4.3.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz", - "integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, + "license": "MIT", "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.26.1.tgz", - "integrity": "sha512-TW1X2p62FQ8Rlne+WEShyd7ac2LA6o27S9i131W4NwDSfyeVlQWhw8ylldNNS8JG6oJB9Ha9Xyc+IUcqipvheQ==", + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=12" } }, - "node_modules/@typescript-eslint/types": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.26.1.tgz", - "integrity": "sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz", - "integrity": "sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA==", + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^6.3.0", - "tsutils": "^3.17.1" + "color-name": "~1.1.4" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=7.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "bin": { - "semver": "bin/semver.js" - } + "license": "MIT" }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz", - "integrity": "sha512-IGouNSSd+6x/fHtYRyLOM6/C+QxMDzWlDtN41ea+flWuSF9g02iqcIlX8wM53JkfljoIjP0U+yp7SiTS1onEkw==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.26.1", - "eslint-visitor-keys": "^2.0.0" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "bin": { + "create-jest": "bin/create-jest.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/abab": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", - "dev": true + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">= 8" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, + "license": "MIT", "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } } }, - "node_modules/acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" }, - "node_modules/ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">=0.3.1" } }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/electron-to-chromium": { + "version": "1.5.27", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", + "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", + "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" }, "engines": { - "node": ">= 8" + "node": ">=10.13.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "is-arrayish": "^0.2.1" } }, - "node_modules/argparse/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "node_modules/eslint-plugin-jest": { + "version": "28.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.14.0.tgz", + "integrity": "sha512-P9s/qXSMTpRTerE2FQ0qJet2gKbcGyFTPAJipoKxmWqR6uuFqIqk8FuEfg5yBieOezVrEfAMZrEwJ6yEp+1MFQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">= 0.4" - } - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, "engines": { - "node": ">=0.8" + "node": ">=4" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.10" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, "engines": { - "node": ">=8" + "node": ">=4.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "bin": { - "atob": "bin/atob.js" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 4.5.0" + "node": ">=4.0" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/aws4": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.0.1.tgz", - "integrity": "sha512-Z4GGmSNQ8pX3WS1O+6v3fo41YItJJZsVxG5gIQ+HuB/iuAQBJxMTHTwz292vuYws1LnHfwSRgoqI+nxdy/pcvw==", + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/babel-jest/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.8.0" } }, - "node_modules/babel-jest/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-report": "*" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "node_modules/expect/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz", - "integrity": "sha512-+AuoehOrjt9irZL7DOt2+4ZaTM6dlu1s5TTS46JBa0/qem4dy7VNW3tMb96qeEqcIh20LD73TVNtmVEeymTG7w==", + "node_modules/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__traverse": "^7.0.6" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-preset-current-node-syntax": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz", - "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==", + "node_modules/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz", - "integrity": "sha512-9ce+DatAa31DpR4Uir8g4Ahxs5K4W4L8refzt+qHWQANb6LhGcAEfIFgLUwk67oya2cCUd6t4eUMtO/z64ocNw==", + "node_modules/expect/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "^26.0.0", - "babel-preset-current-node-syntax": "^0.1.2" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "node_modules/expect/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "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" - }, - "engines": { - "node": ">=0.10.0" + "bser": "2.1.1" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=16.0.0" } }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { - "kind-of": "^6.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { - "kind-of": "^6.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=16" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } + "license": "ISC" }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=8" + "node": ">=6 <7 || >=8" } }, - "node_modules/browser-process-hrtime": { + "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, - "dependencies": { - "resolve": "1.1.7" - } - }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true + "license": "ISC" }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 6" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", - "dev": true + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "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" - }, + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8.0.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { - "rsvp": "^4.8.4" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=8" + "node": ">=10.13.0" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, + "license": "MIT", "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=10.17.0" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">= 0.8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.8.19" } }, - "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { - "safe-buffer": "~5.1.1" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "hasown": "^2.0.2" }, "engines": { - "node": ">=4.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">=8" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.10.0" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, - "node_modules/decimal.js": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", - "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "object-keys": "^1.0.12" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "kind-of": "^6.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, "engines": { - "node": ">=0.3.1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": ">= 8.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/dir-glob/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=6.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { - "webidl-conversions": "^5.0.0" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, + "license": "MIT", "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=10.13.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.1" + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=8.6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "engines": { - "node": ">= 0.4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/jest-diff/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/escodegen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, + "license": "MIT", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "detect-newline": "^3.0.0" }, "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, - "optional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==", + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, + "license": "MIT", "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", - "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "dependencies": { - "ms": "2.0.0" - } + "license": "MIT" }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", - "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-module-utils/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^2.0.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/eslint-module-utils/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, + "license": "MIT", "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint-module-utils/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^1.1.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-module-utils/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/eslint-module-utils/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, "engines": { - "node": ">=4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/eslint-module-utils/node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "node_modules/jest-matcher-utils/node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, + "license": "MIT", "engines": { - "node": ">=4" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" }, - "node_modules/eslint-plugin-jest": { - "version": "23.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz", - "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==", + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "^2.5.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 0.8.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, - "engines": { - "node": ">= 0.8.0" - } + "license": "MIT" }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" + "node": ">=10" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4043,16860 +4302,1596 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=4.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, "engines": { - "node": ">=4.0" + "node": ">=4" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, "engines": { "node": ">=6" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "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" - }, - "engines": { - "node": ">=0.10.0" + "json-buffer": "3.0.1" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" }, - "node_modules/expect": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-25.5.0.tgz", - "integrity": "sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/types": "^25.5.0", - "ansi-styles": "^4.0.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-regex-util": "^25.2.6" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 8.3" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "yallist": "^3.0.2" } }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/lua-types": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/lua-types/-/lua-types-2.14.1.tgz", + "integrity": "sha512-+EbnTjF+Bbfp5xmpfT0O9AZgC5J6Oq6jRnZei3HLb0pbWuCRHmdnIVRPIgEpUncWvHq21DHB2qTHhA4xGceHHg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lua-wasm-bindings": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/lua-wasm-bindings/-/lua-wasm-bindings-0.5.3.tgz", + "integrity": "sha512-GnGSkZmYA2VzkNV/xkwOSoxwNsqEk/EcX6uvRLKQw0pCAxCauTymRO2KmJUIrG/psV3cloaS4Cjsr39iCRkrpQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" + "@types/semver": "^7.3.9", + "semver": "^7.3.7" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "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" + "semver": "^7.5.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "tmpl": "1.0.5" } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.6" } }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { - "kind-of": "^6.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "engines": [ - "node >=0.6.0" - ] + "license": "MIT" }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" }, - "node_modules/fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { - "bser": "2.1.1" + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "wrappy": "1" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "callsites": "^3.0.0" }, "engines": { - "node": ">= 0.12" + "node": ">=6" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { - "map-cache": "^0.2.2" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, + "license": "MIT", "engines": { - "node": ">=6 <7 || >=8" + "node": ">=8" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=0.10.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.0.0" + "node": ">= 6" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { - "pump": "^3.0.0" + "find-up": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0" + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "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" - }, - "engines": { - "node": "*" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" + "p-limit": "^2.2.0" }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, - "dependencies": { - "kind-of": "^3.0.2" + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" + "node": ">=10.13.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, + "license": "MIT", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" + "node": ">= 6" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, - "engines": { - "node": ">= 4" - } + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { - "import-local-fixture": "fixtures/cli.js" + "resolve": "bin/resolve" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-docker": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", - "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/javascript-stringify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.0.1.tgz", - "integrity": "sha512-yV+gqbd5vaOYjqlbk16EG89xB5udgjqQF3C5FAORDg4f/IS1Yc5ERCv5e/57yBcfJYw05V5JyIXabhwb75Xxow==", - "dev": true - }, - "node_modules/jest": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.0.1.tgz", - "integrity": "sha512-29Q54kn5Bm7ZGKIuH2JRmnKl85YRigp0o0asTc6Sb6l2ch1DCXIeZTLLFy9ultJvhkTqbswF5DEx4+RlkmCxWg==", - "dev": true, - "dependencies": { - "@jest/core": "^26.0.1", - "import-local": "^3.0.2", - "jest-cli": "^26.0.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.0.1.tgz", - "integrity": "sha512-q8LP9Sint17HaE2LjxQXL+oYWW/WeeXMPE2+Op9X3mY8IEGFVc14xRxFjUuXUbcPAlDLhtWdIEt59GdQbn76Hw==", - "dev": true, - "dependencies": { - "@jest/types": "^26.0.1", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-changed-files/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-changed-files/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-changed-files/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/jest-circus": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-25.1.0.tgz", - "integrity": "sha512-Axlcr2YMxVarMW4SiZhCFCjNKhdF4xF9AIdltyutQOKyyDT795Kl/fzI95O0l8idE51Npj2wDj5GhrV7uEoEJA==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^25.1.0", - "@jest/test-result": "^25.1.0", - "@jest/types": "^25.1.0", - "chalk": "^3.0.0", - "co": "^4.6.0", - "expect": "^25.1.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^25.1.0", - "jest-matcher-utils": "^25.1.0", - "jest-message-util": "^25.1.0", - "jest-snapshot": "^25.1.0", - "jest-util": "^25.1.0", - "pretty-format": "^25.1.0", - "stack-utils": "^1.0.1", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-config": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.0.1.tgz", - "integrity": "sha512-9mWKx2L1LFgOXlDsC4YSeavnblN6A4CPfXFiobq+YYLaBMymA/SczN7xYTSmLaEYHZOcB98UdoN4m5uNt6tztg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.0.1", - "@jest/types": "^26.0.1", - "babel-jest": "^26.0.1", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.0.1", - "jest-environment-node": "^26.0.1", - "jest-get-type": "^26.0.0", - "jest-jasmine2": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "micromatch": "^4.0.2", - "pretty-format": "^26.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-config/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-config/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-config/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", - "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-each": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.5.0.tgz", - "integrity": "sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "jest-get-type": "^25.2.6", - "jest-util": "^25.5.0", - "pretty-format": "^25.5.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz", - "integrity": "sha512-u88NJa3aptz2Xix2pFhihRBAatwZHWwSiRLBDBQE1cdJvDjPvv7ZGA0NQBxWwDDn7D0g1uHqxM8aGgfA9Bx49g==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/types": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-util": "^26.0.1", - "jsdom": "^16.2.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-environment-jsdom/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-environment-jsdom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-environment-jsdom/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-environment-node": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.0.1.tgz", - "integrity": "sha512-4FRBWcSn5yVo0KtNav7+5NH5Z/tEgDLp7VRQVS5tCouWORxj+nI+1tOLutM07Zb2Qi7ja+HEDoOUkjBSWZg/IQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/types": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-util": "^26.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-environment-node/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-environment-node/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-environment-node/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-environment-node/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-environment-node/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-environment-node/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "fsevents": "^2.1.2" - } - }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-haste-map/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-haste-map/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-haste-map/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-haste-map/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz", - "integrity": "sha512-ILaRyiWxiXOJ+RWTKupzQWwnPaeXPIoLS5uW41h18varJzd9/7I0QJGqg69fhTT1ev9JpSSo9QtalriUN0oqOg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.0.1", - "@jest/source-map": "^26.0.0", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.0.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.0.1", - "jest-matcher-utils": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "pretty-format": "^26.0.1", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-jasmine2/node_modules/@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-jasmine2/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-jasmine2/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-jasmine2/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-jasmine2/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-jasmine2/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-leak-detector": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz", - "integrity": "sha512-93FR8tJhaYIWrWsbmVN1pQ9ZNlbgRpfvrnw5LmgLRX0ckOJ8ut/I35CL7awi2ecq6Ca4lL59bEK9hr7nqoHWPA==", - "dev": true, - "dependencies": { - "jest-get-type": "^26.0.0", - "pretty-format": "^26.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-leak-detector/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-leak-detector/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-leak-detector/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-matcher-utils": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz", - "integrity": "sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "jest-diff": "^25.5.0", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-message-util": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.5.0.tgz", - "integrity": "sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^25.5.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "slash": "^3.0.0", - "stack-utils": "^1.0.1" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-mock": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.5.0.tgz", - "integrity": "sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", - "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==", - "dev": true, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-resolve": { - "version": "25.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.5.1.tgz", - "integrity": "sha512-Hc09hYch5aWdtejsUZhA+vSzcotf7fajSlPA6EZPE1RmPBAD39XtJhvHWFStid58iit4IPDLI/Da4cwdDmAHiQ==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0", - "browser-resolve": "^1.11.3", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.1", - "read-pkg-up": "^7.0.1", - "realpath-native": "^2.0.0", - "resolve": "^1.17.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz", - "integrity": "sha512-9d5/RS/ft0vB/qy7jct/qAhzJsr6fRQJyGAFigK3XD4hf9kIbEH5gks4t4Z7kyMRhowU6HWm/o8ILqhaHdSqLw==", - "dev": true, - "dependencies": { - "@jest/types": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "node_modules/jest-resolve-dependencies/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-resolve-dependencies/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-resolve-dependencies/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-resolve-dependencies/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-resolve/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-resolve/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.0.1.tgz", - "integrity": "sha512-CApm0g81b49Znm4cZekYQK67zY7kkB4umOlI2Dx5CwKAzdgw75EN+ozBHRvxBzwo1ZLYZ07TFxkaPm+1t4d8jA==", - "dev": true, - "dependencies": { - "@jest/console": "^26.0.1", - "@jest/environment": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.0.1", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.0.1", - "jest-jasmine2": "^26.0.1", - "jest-leak-detector": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-resolve": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-util": "^26.0.1", - "jest-worker": "^26.0.0", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-runner/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runner/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-runner/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-runner/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-runtime": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.0.1.tgz", - "integrity": "sha512-Ci2QhYFmANg5qaXWf78T2Pfo6GtmIBn2rRaLnklRyEucmPccmCKvS9JPljcmtVamsdMmkyNkVFb9pBTD6si9Lw==", - "dev": true, - "dependencies": { - "@jest/console": "^26.0.1", - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/globals": "^26.0.1", - "@jest/source-map": "^26.0.0", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.0.1", - "jest-haste-map": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-runtime/node_modules/@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runtime/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runtime/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-runtime/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-runtime/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-snapshot": { - "version": "25.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.5.1.tgz", - "integrity": "sha512-C02JE1TUe64p2v1auUJ2ze5vcuv32tkv9PyhEb318e8XOKF7MOyXdJ7kdjbvrp3ChPLU2usI7Rjxs97Dj5P0uQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^25.5.0", - "@types/prettier": "^1.19.0", - "chalk": "^3.0.0", - "expect": "^25.5.0", - "graceful-fs": "^4.2.4", - "jest-diff": "^25.5.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-resolve": "^25.5.1", - "make-dir": "^3.0.0", - "natural-compare": "^1.4.0", - "pretty-format": "^25.5.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/jest-util": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.5.0.tgz", - "integrity": "sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "make-dir": "^3.0.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/jest-validate": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.0.1.tgz", - "integrity": "sha512-u0xRc+rbmov/VqXnX3DlkxD74rHI/CfS5xaV2VpeaVySjbb1JioNVOyly5b56q2l9ZKe7bVG5qWmjfctkQb0bA==", - "dev": true, - "dependencies": { - "@jest/types": "^26.0.1", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.0.0", - "leven": "^3.1.0", - "pretty-format": "^26.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-watcher": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.0.1.tgz", - "integrity": "sha512-pdZPydsS8475f89kGswaNsN3rhP6lnC3/QDCppP7bg1L9JQz7oU9Mb/5xPETk1RHDCWeqmVC47M4K5RR7ejxFw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.0.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest-watcher/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-watcher/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-watcher/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest/node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/jest/node_modules/@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "node_modules/jest/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest/node_modules/jest-cli": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.0.1.tgz", - "integrity": "sha512-pFLfSOBcbG9iOZWaMK4Een+tTxi/Wcm34geqZEqrst9cZDkTQ1LZ2CnBrTlHWuYAiTMFr0EQeK52ScyFU8wK+w==", - "dev": true, - "dependencies": { - "@jest/core": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "prompts": "^2.0.1", - "yargs": "^15.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/jest/node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsdom": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", - "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.0.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lua-types": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/lua-types/-/lua-types-2.8.0.tgz", - "integrity": "sha512-FJY32giHIqD/XW1XGkJnl8XotXIJsJ2M42fj9A2UudttWA6orJioToW1OpgPdayTr+S1/oTO7i+hfBY3UVG8Fg==", - "dev": true - }, - "node_modules/lua-wasm-bindings": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/lua-wasm-bindings/-/lua-wasm-bindings-0.2.2.tgz", - "integrity": "sha512-Z2v3An8jEvYbhUJ/gYxNd65ZBbaRyPMmUaleDoOhzJSIGrMgjURvy1EtHtgRGTzdtpmKtHA+YYKDrSZBE9g/ig==", - "dev": true - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "dependencies": { - "tmpl": "1.0.x" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dev": true, - "dependencies": { - "mime-db": "1.44.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/node-notifier": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-7.0.1.tgz", - "integrity": "sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg==", - "dev": true, - "optional": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.1.1", - "semver": "^7.2.1", - "shellwords": "^0.1.1", - "uuid": "^7.0.3", - "which": "^2.0.2" - } - }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-notifier/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-each-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "dependencies": { - "node-modules-regexp": "^1.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-format": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/prompts": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", - "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/realpath-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", - "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.15" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", - "dev": true, - "dependencies": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true, - "engines": { - "node": "6.* || >= 7.*" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" - }, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/sane/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "node_modules/signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "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" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", - "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-utils": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", - "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-jest": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.3.0.tgz", - "integrity": "sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q==", - "dev": true, - "dependencies": { - "@types/jest": "26.x", - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "26.x", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "mkdirp": "1.x", - "semver": "7.x", - "yargs-parser": "18.x" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/ts-jest/node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/ts-jest/node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/ts-jest/node_modules/@types/jest": { - "version": "26.0.23", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", - "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", - "dev": true, - "dependencies": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" - } - }, - "node_modules/ts-jest/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ts-jest/node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/ts-jest/node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/ts-jest/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/ts-jest/node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/ts-jest/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/ts-jest/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz", - "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-script": "dist/script.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/tslib": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", - "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", - "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", - "dev": true, - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz", - "integrity": "sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": "8.x.x || >=10.10.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "dependencies": { - "makeerror": "1.0.x" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", - "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/core": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.6.tgz", - "integrity": "sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.6", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.6", - "@babel/parser": "^7.9.6", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", - "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.2", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", - "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.14.2" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-module-transforms": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", - "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.9.0", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz", - "integrity": "sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" - } - }, - "@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "@babel/helpers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", - "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" - } - }, - "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz", - "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz", - "integrity": "sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz", - "integrity": "sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", - "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", - "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.2", - "@babel/helper-function-name": "^7.14.2", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.2", - "@babel/types": "^7.14.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", - "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, - "@jest/console": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.5.0.tgz", - "integrity": "sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "jest-message-util": "^25.5.0", - "jest-util": "^25.5.0", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.0.1.tgz", - "integrity": "sha512-Xq3eqYnxsG9SjDC+WLeIgf7/8KU6rddBxH+SCt18gEpOhAGYC/Mq+YbtlNcIdwjnnT+wDseXSbU0e5X84Y4jTQ==", - "dev": true, - "requires": { - "@jest/console": "^26.0.1", - "@jest/reporters": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.0.1", - "jest-config": "^26.0.1", - "jest-haste-map": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-resolve-dependencies": "^26.0.1", - "jest-runner": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "jest-watcher": "^26.0.1", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "@jest/environment": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.5.0.tgz", - "integrity": "sha512-U2VXPEqL07E/V7pSZMSQCvV5Ea4lqOlT+0ZFijl/i316cRMHvZ4qC+jBdryd+lmRetjQo0YIQr6cVPNxxK87mA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^25.5.0", - "@jest/types": "^25.5.0", - "jest-mock": "^25.5.0" - } - }, - "@jest/fake-timers": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.5.0.tgz", - "integrity": "sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-mock": "^25.5.0", - "jest-util": "^25.5.0", - "lolex": "^5.0.0" - } - }, - "@jest/globals": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.0.1.tgz", - "integrity": "sha512-iuucxOYB7BRCvT+TYBzUqUNuxFX1hqaR6G6IcGgEqkJ5x4htNKo1r7jk1ji9Zj8ZMiMw0oB5NaA7k5Tx6MVssA==", - "dev": true, - "requires": { - "@jest/environment": "^26.0.1", - "@jest/types": "^26.0.1", - "expect": "^26.0.1" - }, - "dependencies": { - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "@jest/reporters": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.0.1.tgz", - "integrity": "sha512-NWWy9KwRtE1iyG/m7huiFVF9YsYv/e+mbflKRV84WDoJfBqUrNRyDbL/vFxQcYLl8IRqI4P3MgPn386x76Gf2g==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.0.1", - "jest-resolve": "^26.0.1", - "jest-util": "^26.0.1", - "jest-worker": "^26.0.0", - "node-notifier": "^7.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^4.1.3" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "@jest/source-map": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.0.0.tgz", - "integrity": "sha512-S2Z+Aj/7KOSU2TfW0dyzBze7xr95bkm5YXNUqqCek+HE0VbNNSNzrRwfIi5lf7wvzDTSS0/ib8XQ1krFNyYgbQ==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.5.0.tgz", - "integrity": "sha512-oV+hPJgXN7IQf/fHWkcS99y0smKLU2czLBJ9WA0jHITLst58HpQMtzSYxzaBvYc6U5U6jfoMthqsUlUlbRXs0A==", - "dev": true, - "requires": { - "@jest/console": "^25.5.0", - "@jest/types": "^25.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz", - "integrity": "sha512-ssga8XlwfP8YjbDcmVhwNlrmblddMfgUeAkWIXts1V22equp2GMIHxm7cyeD5Q/B0ZgKPK/tngt45sH99yLLGg==", - "dev": true, - "requires": { - "@jest/test-result": "^26.0.1", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.0.1", - "jest-runner": "^26.0.1", - "jest-runtime": "^26.0.1" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "@jest/transform": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.0.1.tgz", - "integrity": "sha512-pPRkVkAQ91drKGbzCfDOoHN838+FSbYaEAvBXvKuWeeRRUD8FjwXkqfUNUZL6Ke48aA/1cqq/Ni7kVMCoqagWA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.0.1", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.0.1", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/types": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", - "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinonjs/commons": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", - "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/babel__core": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz", - "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", - "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.11.tgz", - "integrity": "sha512-ddHK5icION5U6q11+tV2f9Mo6CZVuT8GJKld2q9LqHSZbvLbH34Kcu2yFGckZut453+eQU6btIA3RihmnRgI+Q==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/graceful-fs": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz", - "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "25.2.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz", - "integrity": "sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==", - "dev": true, - "requires": { - "jest-diff": "^25.2.1", - "pretty-format": "^25.2.1" - } - }, - "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/node": { - "version": "13.7.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz", - "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==", - "dev": true - }, - "@types/resolve": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.14.0.tgz", - "integrity": "sha512-bmjNBW6tok+67iOsASeYSJxSgY++BIR35nGyGLORTDirhra9reJ0shgGL3U7KPDUbOBCx8JrlCjd4d/y5uiMRQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/yargs": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", - "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.1.tgz", - "integrity": "sha512-aoIusj/8CR+xDWmZxARivZjbMBQTT9dImUtdZ8tVCVRXgBUuuZyM5Of5A9D9arQPxbi/0rlJLcuArclz/rCMJw==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.26.1", - "@typescript-eslint/scope-manager": "4.26.1", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.21", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.1.tgz", - "integrity": "sha512-sQHBugRhrXzRCs9PaGg6rowie4i8s/iD/DpTB+EXte8OMDfdCG5TvO73XlO9Wc/zi0uyN4qOmX9hIjQEyhnbmQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.26.1", - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/typescript-estree": "4.26.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz", - "integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz", - "integrity": "sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.31.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.26.1.tgz", - "integrity": "sha512-q7F3zSo/nU6YJpPJvQveVlIIzx9/wu75lr6oDbDzoeIRWxpoc/HQ43G4rmMoCc5my/3uSj2VEpg/D83LYZF5HQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.26.1", - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/typescript-estree": "4.26.1", - "debug": "^4.3.1" - }, - "dependencies": { - "@typescript-eslint/typescript-estree": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz", - "integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.26.1.tgz", - "integrity": "sha512-TW1X2p62FQ8Rlne+WEShyd7ac2LA6o27S9i131W4NwDSfyeVlQWhw8ylldNNS8JG6oJB9Ha9Xyc+IUcqipvheQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.26.1", - "@typescript-eslint/visitor-keys": "4.26.1" - } - }, - "@typescript-eslint/types": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.26.1.tgz", - "integrity": "sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz", - "integrity": "sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^6.3.0", - "tsutils": "^3.17.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz", - "integrity": "sha512-IGouNSSd+6x/fHtYRyLOM6/C+QxMDzWlDtN41ea+flWuSF9g02iqcIlX8wM53JkfljoIjP0U+yp7SiTS1onEkw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.26.1", - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "abab": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", - "dev": true - }, - "ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", - "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - } - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", - "dev": true - }, - "babel-jest": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.0.1.tgz", - "integrity": "sha512-Z4GGmSNQ8pX3WS1O+6v3fo41YItJJZsVxG5gIQ+HuB/iuAQBJxMTHTwz292vuYws1LnHfwSRgoqI+nxdy/pcvw==", - "dev": true, - "requires": { - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz", - "integrity": "sha512-+AuoehOrjt9irZL7DOt2+4ZaTM6dlu1s5TTS46JBa0/qem4dy7VNW3tMb96qeEqcIh20LD73TVNtmVEeymTG7w==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz", - "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz", - "integrity": "sha512-9ce+DatAa31DpR4Uir8g4Ahxs5K4W4L8refzt+qHWQANb6LhGcAEfIFgLUwk67oya2cCUd6t4eUMtO/z64ocNw==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^26.0.0", - "babel-preset-current-node-syntax": "^0.1.2" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "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" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decimal.js": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", - "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", - "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", - "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-jest": { - "version": "23.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz", - "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "^2.5.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expect": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-25.5.0.tgz", - "integrity": "sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "ansi-styles": "^4.0.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-regex-util": "^25.2.6" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "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" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-docker": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", - "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==", - "dev": true, - "optional": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "javascript-stringify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.0.1.tgz", - "integrity": "sha512-yV+gqbd5vaOYjqlbk16EG89xB5udgjqQF3C5FAORDg4f/IS1Yc5ERCv5e/57yBcfJYw05V5JyIXabhwb75Xxow==", - "dev": true - }, - "jest": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.0.1.tgz", - "integrity": "sha512-29Q54kn5Bm7ZGKIuH2JRmnKl85YRigp0o0asTc6Sb6l2ch1DCXIeZTLLFy9ultJvhkTqbswF5DEx4+RlkmCxWg==", - "dev": true, - "requires": { - "@jest/core": "^26.0.1", - "import-local": "^3.0.2", - "jest-cli": "^26.0.1" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-cli": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.0.1.tgz", - "integrity": "sha512-pFLfSOBcbG9iOZWaMK4Een+tTxi/Wcm34geqZEqrst9cZDkTQ1LZ2CnBrTlHWuYAiTMFr0EQeK52ScyFU8wK+w==", - "dev": true, - "requires": { - "@jest/core": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "prompts": "^2.0.1", - "yargs": "^15.3.1" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-changed-files": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.0.1.tgz", - "integrity": "sha512-q8LP9Sint17HaE2LjxQXL+oYWW/WeeXMPE2+Op9X3mY8IEGFVc14xRxFjUuXUbcPAlDLhtWdIEt59GdQbn76Hw==", - "dev": true, - "requires": { - "@jest/types": "^26.0.1", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "jest-circus": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-25.1.0.tgz", - "integrity": "sha512-Axlcr2YMxVarMW4SiZhCFCjNKhdF4xF9AIdltyutQOKyyDT795Kl/fzI95O0l8idE51Npj2wDj5GhrV7uEoEJA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^25.1.0", - "@jest/test-result": "^25.1.0", - "@jest/types": "^25.1.0", - "chalk": "^3.0.0", - "co": "^4.6.0", - "expect": "^25.1.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^25.1.0", - "jest-matcher-utils": "^25.1.0", - "jest-message-util": "^25.1.0", - "jest-snapshot": "^25.1.0", - "jest-util": "^25.1.0", - "pretty-format": "^25.1.0", - "stack-utils": "^1.0.1", - "throat": "^5.0.0" - } - }, - "jest-config": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.0.1.tgz", - "integrity": "sha512-9mWKx2L1LFgOXlDsC4YSeavnblN6A4CPfXFiobq+YYLaBMymA/SczN7xYTSmLaEYHZOcB98UdoN4m5uNt6tztg==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.0.1", - "@jest/types": "^26.0.1", - "babel-jest": "^26.0.1", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.0.1", - "jest-environment-node": "^26.0.1", - "jest-get-type": "^26.0.0", - "jest-jasmine2": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "micromatch": "^4.0.2", - "pretty-format": "^26.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - } - } - }, - "jest-diff": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", - "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" - } - }, - "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.5.0.tgz", - "integrity": "sha512-QBogUxna3D8vtiItvn54xXde7+vuzqRrEeaw8r1s+1TG9eZLVJE5ZkKoSUlqFwRjnlaA4hyKGiu9OlkFIuKnjA==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "jest-get-type": "^25.2.6", - "jest-util": "^25.5.0", - "pretty-format": "^25.5.0" - } - }, - "jest-environment-jsdom": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz", - "integrity": "sha512-u88NJa3aptz2Xix2pFhihRBAatwZHWwSiRLBDBQE1cdJvDjPvv7ZGA0NQBxWwDDn7D0g1uHqxM8aGgfA9Bx49g==", - "dev": true, - "requires": { - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/types": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-util": "^26.0.1", - "jsdom": "^16.2.2" - }, - "dependencies": { - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-environment-node": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.0.1.tgz", - "integrity": "sha512-4FRBWcSn5yVo0KtNav7+5NH5Z/tEgDLp7VRQVS5tCouWORxj+nI+1tOLutM07Zb2Qi7ja+HEDoOUkjBSWZg/IQ==", - "dev": true, - "requires": { - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/types": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-util": "^26.0.1" - }, - "dependencies": { - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - } - } - }, - "jest-jasmine2": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz", - "integrity": "sha512-ILaRyiWxiXOJ+RWTKupzQWwnPaeXPIoLS5uW41h18varJzd9/7I0QJGqg69fhTT1ev9JpSSo9QtalriUN0oqOg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.0.1", - "@jest/source-map": "^26.0.0", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.0.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.0.1", - "jest-matcher-utils": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "pretty-format": "^26.0.1", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-leak-detector": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz", - "integrity": "sha512-93FR8tJhaYIWrWsbmVN1pQ9ZNlbgRpfvrnw5LmgLRX0ckOJ8ut/I35CL7awi2ecq6Ca4lL59bEK9hr7nqoHWPA==", - "dev": true, - "requires": { - "jest-get-type": "^26.0.0", - "pretty-format": "^26.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "jest-matcher-utils": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz", - "integrity": "sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "jest-diff": "^25.5.0", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" - } - }, - "jest-message-util": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.5.0.tgz", - "integrity": "sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^25.5.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "slash": "^3.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.5.0.tgz", - "integrity": "sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", - "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==", - "dev": true - }, - "jest-resolve": { - "version": "25.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.5.1.tgz", - "integrity": "sha512-Hc09hYch5aWdtejsUZhA+vSzcotf7fajSlPA6EZPE1RmPBAD39XtJhvHWFStid58iit4IPDLI/Da4cwdDmAHiQ==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "browser-resolve": "^1.11.3", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.1", - "read-pkg-up": "^7.0.1", - "realpath-native": "^2.0.0", - "resolve": "^1.17.0", - "slash": "^3.0.0" - }, - "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz", - "integrity": "sha512-9d5/RS/ft0vB/qy7jct/qAhzJsr6fRQJyGAFigK3XD4hf9kIbEH5gks4t4Z7kyMRhowU6HWm/o8ILqhaHdSqLw==", - "dev": true, - "requires": { - "@jest/types": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-runner": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.0.1.tgz", - "integrity": "sha512-CApm0g81b49Znm4cZekYQK67zY7kkB4umOlI2Dx5CwKAzdgw75EN+ozBHRvxBzwo1ZLYZ07TFxkaPm+1t4d8jA==", - "dev": true, - "requires": { - "@jest/console": "^26.0.1", - "@jest/environment": "^26.0.1", - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.0.1", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.0.1", - "jest-jasmine2": "^26.0.1", - "jest-leak-detector": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-resolve": "^26.0.1", - "jest-runtime": "^26.0.1", - "jest-util": "^26.0.1", - "jest-worker": "^26.0.0", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-runtime": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.0.1.tgz", - "integrity": "sha512-Ci2QhYFmANg5qaXWf78T2Pfo6GtmIBn2rRaLnklRyEucmPccmCKvS9JPljcmtVamsdMmkyNkVFb9pBTD6si9Lw==", - "dev": true, - "requires": { - "@jest/console": "^26.0.1", - "@jest/environment": "^26.0.1", - "@jest/fake-timers": "^26.0.1", - "@jest/globals": "^26.0.1", - "@jest/source-map": "^26.0.0", - "@jest/test-result": "^26.0.1", - "@jest/transform": "^26.0.1", - "@jest/types": "^26.0.1", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.0.1", - "jest-haste-map": "^26.0.1", - "jest-message-util": "^26.0.1", - "jest-mock": "^26.0.1", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.0.1", - "jest-snapshot": "^26.0.1", - "jest-util": "^26.0.1", - "jest-validate": "^26.0.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.3.1" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - } - }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" - } - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" - } - }, - "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-snapshot": { - "version": "25.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.5.1.tgz", - "integrity": "sha512-C02JE1TUe64p2v1auUJ2ze5vcuv32tkv9PyhEb318e8XOKF7MOyXdJ7kdjbvrp3ChPLU2usI7Rjxs97Dj5P0uQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^25.5.0", - "@types/prettier": "^1.19.0", - "chalk": "^3.0.0", - "expect": "^25.5.0", - "graceful-fs": "^4.2.4", - "jest-diff": "^25.5.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.5.0", - "jest-message-util": "^25.5.0", - "jest-resolve": "^25.5.1", - "make-dir": "^3.0.0", - "natural-compare": "^1.4.0", - "pretty-format": "^25.5.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "jest-util": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.5.0.tgz", - "integrity": "sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "chalk": "^3.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "make-dir": "^3.0.0" - } - }, - "jest-validate": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.0.1.tgz", - "integrity": "sha512-u0xRc+rbmov/VqXnX3DlkxD74rHI/CfS5xaV2VpeaVySjbb1JioNVOyly5b56q2l9ZKe7bVG5qWmjfctkQb0bA==", - "dev": true, - "requires": { - "@jest/types": "^26.0.1", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.0.0", - "leven": "^3.1.0", - "pretty-format": "^26.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "26.0.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.0.1.tgz", - "integrity": "sha512-pdZPydsS8475f89kGswaNsN3rhP6lnC3/QDCppP7bg1L9JQz7oU9Mb/5xPETk1RHDCWeqmVC47M4K5RR7ejxFw==", - "dev": true, - "requires": { - "@jest/test-result": "^26.0.1", - "@jest/types": "^26.0.1", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.0.1", - "string-length": "^4.0.1" - }, - "dependencies": { - "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - } - } - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", - "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.0.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "lua-types": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/lua-types/-/lua-types-2.8.0.tgz", - "integrity": "sha512-FJY32giHIqD/XW1XGkJnl8XotXIJsJ2M42fj9A2UudttWA6orJioToW1OpgPdayTr+S1/oTO7i+hfBY3UVG8Fg==", - "dev": true - }, - "lua-wasm-bindings": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/lua-wasm-bindings/-/lua-wasm-bindings-0.2.2.tgz", - "integrity": "sha512-Z2v3An8jEvYbhUJ/gYxNd65ZBbaRyPMmUaleDoOhzJSIGrMgjURvy1EtHtgRGTzdtpmKtHA+YYKDrSZBE9g/ig==", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", - "dev": true - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "dev": true, - "requires": { - "mime-db": "1.44.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "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" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-7.0.1.tgz", - "integrity": "sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.1.1", - "semver": "^7.2.1", - "shellwords": "^0.1.1", - "uuid": "^7.0.3", - "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "p-each-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", - "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", - "dev": true - }, - "pretty-format": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prompts": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", - "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.4" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "realpath-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", - "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==", - "dev": true - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", - "dev": true, - "requires": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "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" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=10" } }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "engines": { + "node": ">=10" } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "source-map-support": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", - "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "license": "ISC" }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true + "license": "MIT" }, - "spdx-expression-parse": { + "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "requires": { - "extend-shallow": "^3.0.0" + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "stack-utils": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "requires": { + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { "escape-string-regexp": "^2.0.0" }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } + "engines": { + "node": ">=10" } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">=8" } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "requires": { - "ansi-regex": "^5.0.0" + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-bom": { + "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "strip-final-newline": { + "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "ajv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", - "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==" - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "test-exclude": { + "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">=12.0.0" }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true } } }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "to-regex-range": { + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "ts-jest": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.3.0.tgz", - "integrity": "sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q==", - "dev": true, - "requires": { - "@types/jest": "26.x", - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "26.x", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "mkdirp": "1.x", - "semver": "7.x", - "yargs-parser": "18.x" + "node_modules/ts-jest": { + "version": "29.4.9", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.9.tgz", + "integrity": "sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.4", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "26.0.23", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", - "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", - "dev": true, - "requires": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" - } + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "@jest/transform": { + "optional": true }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true + "@jest/types": { + "optional": true }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" - } + "babel-jest": { + "optional": true }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true + "esbuild": { + "optional": true }, "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "optional": true } } }, - "ts-node": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz", - "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==", + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, - "requires": { + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", + "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "tslib": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", - "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { + "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, - "requires": { - "is-typedarray": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "typescript": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", - "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==" - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } + "engines": { + "node": ">=14.17" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "node_modules/typescript-eslint": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz", + "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", "dev": true, - "requires": { - "punycode": "^2.1.0" + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.0", + "@typescript-eslint/parser": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, - "optional": true + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } }, - "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true }, - "v8-to-istanbul": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz", - "integrity": "sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">= 4.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } + "license": "MIT" }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "requires": { - "makeerror": "1.0.x" + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "requires": { - "iconv-lite": "0.4.24" + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" } }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz", - "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^5.0.0" - }, + "license": "ISC", "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "license": "ISC", + "engines": { + "node": ">=12" } }, - "yn": { + "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 548b86ef2..df63dfcf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typescript-to-lua", - "version": "0.41.0", + "version": "1.37.1", "description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!", "repository": "https://github.com/TypeScriptToLua/TypeScriptToLua", "homepage": "https://typescripttolua.github.io/", @@ -18,20 +18,20 @@ "dist/**/*.js", "dist/**/*.lua", "dist/**/*.ts", - "language-extensions/**/*.ts" + "dist/lualib/**/*.json" ], "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc && npm run build-lualib", - "build-lualib": "node build-lualib.js", + "build-lualib": "node dist/tstl.js -p src/lualib/tsconfig.json && node dist/tstl.js -p src/lualib/tsconfig.lua50.json", "pretest": "npm run lint && npm run check:language-extensions && npm run build-lualib", "test": "jest", "lint": "npm run lint:eslint && npm run lint:prettier", "lint:prettier": "prettier --check . || (echo 'Run `npm run fix:prettier` to fix it.' && exit 1)", - "lint:eslint": "eslint . --ext .js,.ts", + "lint:eslint": "eslint .", "fix:prettier": "prettier --write .", - "check:language-extensions": "tsc language-extensions/index.d.ts", + "check:language-extensions": "tsc --strict --ignoreConfig language-extensions/index.d.ts", "preversion": "npm run build && npm test", "postversion": "git push && git push --tags" }, @@ -39,33 +39,37 @@ "tstl": "dist/tstl.js" }, "engines": { - "node": ">=12.13.0" + "node": ">=16.10.0" + }, + "peerDependencies": { + "typescript": "6.0.2" }, "dependencies": { - "enhanced-resolve": "^5.8.2", + "@typescript-to-lua/language-extensions": "1.19.0", + "enhanced-resolve": "5.8.2", + "picomatch": "^2.3.1", "resolve": "^1.15.1", - "source-map": "^0.7.3", - "typescript": "~4.3.2" + "source-map": "^0.7.3" }, "devDependencies": { "@types/fs-extra": "^8.1.0", - "@types/glob": "^7.1.1", - "@types/jest": "^25.1.3", - "@types/node": "^13.7.7", + "@types/glob": "^7.2.0", + "@types/jest": "^27.5.2", + "@types/node": "^22.10.0", + "@types/picomatch": "^2.3.0", "@types/resolve": "1.14.0", - "@typescript-eslint/eslint-plugin": "^4.26.1", - "@typescript-eslint/parser": "^4.26.1", - "eslint": "^7.28.0", - "eslint-plugin-import": "^2.20.1", - "eslint-plugin-jest": "^23.8.2", + "eslint": "^9.39.4", + "eslint-plugin-jest": "^28.14.0", "fs-extra": "^8.1.0", "javascript-stringify": "^2.0.1", - "jest": "^26.0.1", - "jest-circus": "^25.1.0", - "lua-types": "^2.8.0", - "lua-wasm-bindings": "^0.2.2", - "prettier": "^2.3.2", - "ts-jest": "^26.3.0", - "ts-node": "^8.6.2" + "jest": "^29.7.0", + "jest-circus": "^29.7.0", + "lua-types": "^2.14.1", + "lua-wasm-bindings": "^0.5.3", + "prettier": "^2.8.8", + "ts-jest": "^29.4.9", + "ts-node": "^10.9.2", + "typescript": "6.0.2", + "typescript-eslint": "^8.58.0" } } diff --git a/src/CompilerOptions.ts b/src/CompilerOptions.ts index 0610d26b3..1a167e7c3 100644 --- a/src/CompilerOptions.ts +++ b/src/CompilerOptions.ts @@ -1,5 +1,7 @@ import * as ts from "typescript"; +import { JsxEmit } from "typescript"; import * as diagnosticFactories from "./transpilation/diagnostics"; +import { Plugin } from "./transpilation/plugins"; type OmitIndexSignature = { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]; @@ -11,44 +13,63 @@ export interface TransformerImport { after?: boolean; afterDeclarations?: boolean; type?: "program" | "config" | "checker" | "raw" | "compilerOptions"; + [option: string]: any; } export interface LuaPluginImport { name: string; import?: string; + + [option: string]: any; +} + +export interface InMemoryLuaPlugin { + plugin: Plugin | ((options: Record) => Plugin); [option: string]: any; } -export type CompilerOptions = OmitIndexSignature & { +export interface TypeScriptToLuaOptions { buildMode?: BuildMode; - noImplicitSelf?: boolean; - noHeader?: boolean; + extension?: string; luaBundle?: string; luaBundleEntry?: string; luaTarget?: LuaTarget; luaLibImport?: LuaLibImportKind; - sourceMapTraceback?: boolean; - luaPlugins?: LuaPluginImport[]; + luaPlugins?: Array; + noImplicitGlobalVariables?: boolean; + noImplicitSelf?: boolean; + noHeader?: boolean; + noResolvePaths?: string[]; plugins?: Array; + sourceMapTraceback?: boolean; tstlVerbose?: boolean; - [option: string]: any; -}; + lua51AllowTryCatchInAsyncAwait?: boolean; + measurePerformance?: boolean; +} + +export type CompilerOptions = OmitIndexSignature & + TypeScriptToLuaOptions & { + [option: string]: any; + }; export enum LuaLibImportKind { None = "none", - Always = "always", Inline = "inline", Require = "require", + RequireMinimal = "require-minimal", } export enum LuaTarget { Universal = "universal", + Lua50 = "5.0", Lua51 = "5.1", Lua52 = "5.2", Lua53 = "5.3", Lua54 = "5.4", + Lua55 = "5.5", LuaJIT = "JIT", + Luau = "Luau", } export enum BuildMode { @@ -74,5 +95,9 @@ export function validateOptions(options: CompilerOptions): ts.Diagnostic[] { diagnostics.push(diagnosticFactories.cannotBundleLibrary()); } + if (options.jsx && options.jsx !== JsxEmit.React) { + diagnostics.push(diagnosticFactories.unsupportedJsxEmit()); + } + return diagnostics; } diff --git a/src/LuaAST.ts b/src/LuaAST.ts index 1ac86d3f5..ad4a7e06b 100644 --- a/src/LuaAST.ts +++ b/src/LuaAST.ts @@ -5,7 +5,7 @@ // because we don't create the AST from text import * as ts from "typescript"; -import { LuaLibFeature } from "./transformation/utils/lualib"; +import { LuaLibFeature } from "./LuaLib"; import { castArray } from "./utils"; export enum SyntaxKind { @@ -25,6 +25,7 @@ export enum SyntaxKind { LabelStatement, ReturnStatement, BreakStatement, + ContinueStatement, // Luau only. ExpressionStatement, // Expression @@ -32,6 +33,7 @@ export enum SyntaxKind { NumericLiteral, NilKeyword, DotsKeyword, + ArgKeyword, TrueKeyword, FalseKeyword, FunctionExpression, @@ -43,6 +45,8 @@ export enum SyntaxKind { MethodCallExpression, Identifier, TableIndexExpression, + ParenthesizedExpression, + ConditionalExpression, // Luau only // Operators @@ -125,6 +129,13 @@ export type Operator = UnaryOperator | BinaryOperator; export type SymbolId = number & { _symbolIdBrand: any }; +export enum NodeFlags { + None = 0, + Inline = 1 << 0, // Keep function body on same line + Declaration = 1 << 1, // Prefer declaration syntax `function foo()` over assignment syntax `foo = function()` + TableUnpackCall = 1 << 2, // This is a table.unpack call +} + export interface TextRange { line?: number; column?: number; @@ -132,18 +143,19 @@ export interface TextRange { export interface Node extends TextRange { kind: SyntaxKind; + flags: NodeFlags; } export function createNode(kind: SyntaxKind, tsOriginal?: ts.Node): Node { if (tsOriginal === undefined) { - return { kind }; + return { kind, flags: NodeFlags.None }; } const sourcePosition = getSourcePosition(tsOriginal); if (sourcePosition) { - return { kind, line: sourcePosition.line, column: sourcePosition.column }; + return { kind, line: sourcePosition.line, column: sourcePosition.column, flags: NodeFlags.None }; } else { - return { kind }; + return { kind, flags: NodeFlags.None }; } } @@ -190,6 +202,11 @@ export function getOriginalPos(node: Node): TextRange { return { line: node.line, column: node.column }; } +export function setNodeFlags(node: T, flags: NodeFlags): T { + node.flags = flags; + return node; +} + export interface File extends Node { kind: SyntaxKind.File; statements: Statement[]; @@ -473,6 +490,18 @@ export function createBreakStatement(tsOriginal?: ts.Node): BreakStatement { return createNode(SyntaxKind.BreakStatement, tsOriginal) as BreakStatement; } +export interface ContinueStatement extends Statement { + kind: SyntaxKind.ContinueStatement; +} + +export function isContinueStatement(node: Node): node is ContinueStatement { + return node.kind === SyntaxKind.ContinueStatement; +} + +export function createContinueStatement(tsOriginal?: ts.Node): ContinueStatement { + return createNode(SyntaxKind.ContinueStatement, tsOriginal) as ContinueStatement; +} + export interface ExpressionStatement extends Statement { kind: SyntaxKind.ExpressionStatement; expression: Expression; @@ -531,6 +560,18 @@ export function createDotsLiteral(tsOriginal?: ts.Node): DotsLiteral { return createNode(SyntaxKind.DotsKeyword, tsOriginal) as DotsLiteral; } +export interface ArgLiteral extends Expression { + kind: SyntaxKind.ArgKeyword; +} + +export function isArgLiteral(node: Node): node is ArgLiteral { + return node.kind === SyntaxKind.ArgKeyword; +} + +export function createArgLiteral(tsOriginal?: ts.Node): ArgLiteral { + return createNode(SyntaxKind.ArgKeyword, tsOriginal) as ArgLiteral; +} + // StringLiteral / NumberLiteral // TODO TS uses the export interface "LiteralLikeNode" with a "text: string" member // but since we don't parse from text I think we can simplify by just having a value member @@ -566,10 +607,17 @@ export function createStringLiteral(value: string, tsOriginal?: ts.Node): String return expression; } -export enum FunctionExpressionFlags { - None = 1 << 0, - Inline = 1 << 1, // Keep function body on same line - Declaration = 1 << 2, // Prefer declaration syntax `function foo()` over assignment syntax `foo = function()` +export function isLiteral( + node: Node +): node is NilLiteral | DotsLiteral | ArgLiteral | BooleanLiteral | NumericLiteral | StringLiteral { + return ( + isNilLiteral(node) || + isDotsLiteral(node) || + isArgLiteral(node) || + isBooleanLiteral(node) || + isNumericLiteral(node) || + isStringLiteral(node) + ); } export interface FunctionExpression extends Expression { @@ -577,7 +625,6 @@ export interface FunctionExpression extends Expression { params?: Identifier[]; dots?: DotsLiteral; body: Block; - flags: FunctionExpressionFlags; } export function isFunctionExpression(node: Node): node is FunctionExpression { @@ -588,7 +635,7 @@ export function createFunctionExpression( body: Block, params?: Identifier[], dots?: DotsLiteral, - flags = FunctionExpressionFlags.None, + flags = NodeFlags.None, tsOriginal?: ts.Node ): FunctionExpression { const expression = createNode(SyntaxKind.FunctionExpression, tsOriginal) as FunctionExpression; @@ -784,6 +831,7 @@ export function createTableIndexExpression( } export type AssignmentLeftHandSideExpression = Identifier | TableIndexExpression; + export function isAssignmentLeftHandSideExpression(node: Node): node is AssignmentLeftHandSideExpression { return isIdentifier(node) || isTableIndexExpression(node); } @@ -807,6 +855,46 @@ export function isInlineFunctionExpression(expression: FunctionExpression): expr expression.body.statements?.length === 1 && isReturnStatement(expression.body.statements[0]) && expression.body.statements[0].expressions !== undefined && - (expression.flags & FunctionExpressionFlags.Inline) !== 0 + (expression.flags & NodeFlags.Inline) !== 0 ); } + +export type ParenthesizedExpression = Expression & { + expression: Expression; +}; + +export function isParenthesizedExpression(node: Node): node is ParenthesizedExpression { + return node.kind === SyntaxKind.ParenthesizedExpression; +} + +export function createParenthesizedExpression(expression: Expression, tsOriginal?: ts.Node): ParenthesizedExpression { + const parenthesizedExpression = createNode( + SyntaxKind.ParenthesizedExpression, + tsOriginal + ) as ParenthesizedExpression; + parenthesizedExpression.expression = expression; + return parenthesizedExpression; +} + +export type ConditionalExpression = Expression & { + condition: Expression; + whenTrue: Expression; + whenFalse: Expression; +}; + +export function isConditionalExpression(node: Node): node is ConditionalExpression { + return node.kind === SyntaxKind.ConditionalExpression; +} + +export function createConditionalExpression( + condition: Expression, + whenTrue: Expression, + whenFalse: Expression, + tsOriginal?: ts.Node +): ConditionalExpression { + const conditionalExpression = createNode(SyntaxKind.ConditionalExpression, tsOriginal) as ConditionalExpression; + conditionalExpression.condition = condition; + conditionalExpression.whenTrue = whenTrue; + conditionalExpression.whenFalse = whenFalse; + return conditionalExpression; +} diff --git a/src/LuaLib.ts b/src/LuaLib.ts index e1a8d9efd..6320bc99c 100644 --- a/src/LuaLib.ts +++ b/src/LuaLib.ts @@ -1,24 +1,30 @@ import * as path from "path"; import { EmitHost } from "./transpilation"; +import * as lua from "./LuaAST"; +import { LuaTarget } from "./CompilerOptions"; +import { getOrUpdate } from "./utils"; export enum LuaLibFeature { + ArrayAt = "ArrayAt", ArrayConcat = "ArrayConcat", ArrayEntries = "ArrayEntries", ArrayEvery = "ArrayEvery", + ArrayFill = "ArrayFill", ArrayFilter = "ArrayFilter", ArrayForEach = "ArrayForEach", ArrayFind = "ArrayFind", ArrayFindIndex = "ArrayFindIndex", + ArrayFrom = "ArrayFrom", ArrayIncludes = "ArrayIncludes", ArrayIndexOf = "ArrayIndexOf", ArrayIsArray = "ArrayIsArray", ArrayJoin = "ArrayJoin", ArrayMap = "ArrayMap", ArrayPush = "ArrayPush", + ArrayPushArray = "ArrayPushArray", ArrayReduce = "ArrayReduce", ArrayReduceRight = "ArrayReduceRight", ArrayReverse = "ArrayReverse", - ArrayShift = "ArrayShift", ArrayUnshift = "ArrayUnshift", ArraySort = "ArraySort", ArraySlice = "ArraySlice", @@ -28,42 +34,67 @@ export enum LuaLibFeature { ArrayFlat = "ArrayFlat", ArrayFlatMap = "ArrayFlatMap", ArraySetLength = "ArraySetLength", + ArrayToReversed = "ArrayToReversed", + ArrayToSorted = "ArrayToSorted", + ArrayToSpliced = "ArrayToSpliced", + ArrayWith = "ArrayWith", + Await = "Await", Class = "Class", ClassExtends = "ClassExtends", CloneDescriptor = "CloneDescriptor", + CountVarargs = "CountVarargs", Decorate = "Decorate", + DecorateLegacy = "DecorateLegacy", DecorateParam = "DecorateParam", Delete = "Delete", DelegatedYield = "DelegatedYield", + DescriptorGet = "DescriptorGet", + DescriptorSet = "DescriptorSet", Error = "Error", FunctionBind = "FunctionBind", Generator = "Generator", InstanceOf = "InstanceOf", InstanceOfObject = "InstanceOfObject", Iterator = "Iterator", + LuaIteratorSpread = "LuaIteratorSpread", Map = "Map", + MapGroupBy = "MapGroupBy", + Match = "Match", MathAtan2 = "MathAtan2", + MathModf = "MathModf", + MathSign = "MathSign", + MathTrunc = "MathTrunc", New = "New", Number = "Number", NumberIsFinite = "NumberIsFinite", + NumberIsInteger = "NumberIsInteger", NumberIsNaN = "NumberIsNaN", + NumberParseInt = "ParseInt", + NumberParseFloat = "ParseFloat", NumberToString = "NumberToString", + NumberToFixed = "NumberToFixed", ObjectAssign = "ObjectAssign", ObjectDefineProperty = "ObjectDefineProperty", ObjectEntries = "ObjectEntries", ObjectFromEntries = "ObjectFromEntries", ObjectGetOwnPropertyDescriptor = "ObjectGetOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptors = "ObjectGetOwnPropertyDescriptors", + ObjectGroupBy = "ObjectGroupBy", ObjectKeys = "ObjectKeys", ObjectRest = "ObjectRest", ObjectValues = "ObjectValues", - OptionalChainAccess = "OptionalChainAccess", - OptionalFunctionCall = "OptionalFunctionCall", - OptionalMethodCall = "OptionalMethodCall", ParseFloat = "ParseFloat", ParseInt = "ParseInt", + Promise = "Promise", + PromiseAll = "PromiseAll", + PromiseAllSettled = "PromiseAllSettled", + PromiseAny = "PromiseAny", + PromiseRace = "PromiseRace", Set = "Set", SetDescriptor = "SetDescriptor", + SparseArrayNew = "SparseArrayNew", + SparseArrayPush = "SparseArrayPush", + SparseArraySpread = "SparseArraySpread", WeakMap = "WeakMap", WeakSet = "WeakSet", SourceMapTraceBack = "SourceMapTraceBack", @@ -71,12 +102,12 @@ export enum LuaLibFeature { StringAccess = "StringAccess", StringCharAt = "StringCharAt", StringCharCodeAt = "StringCharCodeAt", - StringConcat = "StringConcat", StringEndsWith = "StringEndsWith", StringIncludes = "StringIncludes", StringPadEnd = "StringPadEnd", StringPadStart = "StringPadStart", StringReplace = "StringReplace", + StringReplaceAll = "StringReplaceAll", StringSlice = "StringSlice", StringSplit = "StringSplit", StringStartsWith = "StringStartsWith", @@ -89,53 +120,93 @@ export enum LuaLibFeature { SymbolRegistry = "SymbolRegistry", TypeOf = "TypeOf", Unpack = "Unpack", + Using = "Using", + UsingAsync = "UsingAsync", } -/* eslint-disable @typescript-eslint/naming-convention */ -const luaLibDependencies: Partial> = { - ArrayConcat: [LuaLibFeature.ArrayIsArray], - ArrayFlat: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray], - ArrayFlatMap: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray], - Decorate: [LuaLibFeature.CloneDescriptor], - Delete: [LuaLibFeature.ObjectGetOwnPropertyDescriptors], - Error: [LuaLibFeature.New, LuaLibFeature.Class], - FunctionBind: [LuaLibFeature.Unpack], - Generator: [LuaLibFeature.Symbol], - InstanceOf: [LuaLibFeature.Symbol], - Iterator: [LuaLibFeature.Symbol], - ObjectDefineProperty: [LuaLibFeature.CloneDescriptor, LuaLibFeature.SetDescriptor], - ObjectFromEntries: [LuaLibFeature.Iterator, LuaLibFeature.Symbol], - Map: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class], - Set: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class], - WeakMap: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class], - WeakSet: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class], - Spread: [LuaLibFeature.Iterator, LuaLibFeature.Unpack], - StringSplit: [LuaLibFeature.StringSubstring, LuaLibFeature.StringAccess], - SymbolRegistry: [LuaLibFeature.Symbol], -}; -/* eslint-enable @typescript-eslint/naming-convention */ - -export function loadLuaLibFeatures(features: Iterable, emitHost: EmitHost): string { - let result = ""; +export interface LuaLibFeatureInfo { + dependencies?: LuaLibFeature[]; + exports: string[]; +} + +export type LuaLibModulesInfo = Record; + +export function resolveLuaLibDir(luaTarget: LuaTarget) { + const luaLibDir = luaTarget === LuaTarget.Lua50 ? "5.0" : "universal"; + return path.resolve(__dirname, path.join("..", "dist", "lualib", luaLibDir)); +} + +export const luaLibModulesInfoFileName = "lualib_module_info.json"; +const luaLibModulesInfo = new Map(); + +export function getLuaLibModulesInfo(luaTarget: LuaTarget, emitHost: EmitHost): LuaLibModulesInfo { + if (!luaLibModulesInfo.has(luaTarget)) { + const lualibPath = path.join(resolveLuaLibDir(luaTarget), luaLibModulesInfoFileName); + const result = emitHost.readFile(lualibPath); + if (result !== undefined) { + luaLibModulesInfo.set(luaTarget, JSON.parse(result) as LuaLibModulesInfo); + } else { + throw new Error(`Could not load lualib dependencies from '${lualibPath}'`); + } + } + return luaLibModulesInfo.get(luaTarget)!; +} + +// This caches the names of lualib exports to their LuaLibFeature, avoiding a linear search for every lookup +const lualibExportToFeature = new Map>(); + +export function getLuaLibExportToFeatureMap( + luaTarget: LuaTarget, + emitHost: EmitHost +): ReadonlyMap { + if (!lualibExportToFeature.has(luaTarget)) { + const luaLibModulesInfo = getLuaLibModulesInfo(luaTarget, emitHost); + const map = new Map(); + for (const [feature, info] of Object.entries(luaLibModulesInfo)) { + for (const exportName of info.exports) { + map.set(exportName, feature as LuaLibFeature); + } + } + lualibExportToFeature.set(luaTarget, map); + } + + return lualibExportToFeature.get(luaTarget)!; +} + +const lualibFeatureCache = new Map>(); + +export function readLuaLibFeature(feature: LuaLibFeature, luaTarget: LuaTarget, emitHost: EmitHost): string { + const featureMap = getOrUpdate(lualibFeatureCache, luaTarget, () => new Map()); + if (!featureMap.has(feature)) { + const featurePath = path.join(resolveLuaLibDir(luaTarget), `${feature}.lua`); + const luaLibFeature = emitHost.readFile(featurePath); + if (luaLibFeature === undefined) { + throw new Error(`Could not load lualib feature from '${featurePath}'`); + } + featureMap.set(feature, luaLibFeature); + } + return featureMap.get(feature)!; +} +export function resolveRecursiveLualibFeatures( + features: Iterable, + luaTarget: LuaTarget, + emitHost: EmitHost, + luaLibModulesInfo: LuaLibModulesInfo = getLuaLibModulesInfo(luaTarget, emitHost) +): LuaLibFeature[] { const loadedFeatures = new Set(); + const result: LuaLibFeature[] = []; function load(feature: LuaLibFeature): void { if (loadedFeatures.has(feature)) return; loadedFeatures.add(feature); - const dependencies = luaLibDependencies[feature]; + const dependencies = luaLibModulesInfo[feature]?.dependencies; if (dependencies) { dependencies.forEach(load); } - const featurePath = path.resolve(__dirname, `../dist/lualib/${feature}.lua`); - const luaLibFeature = emitHost.readFile(featurePath); - if (luaLibFeature !== undefined) { - result += luaLibFeature + "\n"; - } else { - throw new Error(`Could not load lualib feature from '${featurePath}'`); - } + result.push(feature); } for (const feature of features) { @@ -145,17 +216,98 @@ export function loadLuaLibFeatures(features: Iterable, emitHost: return result; } -let luaLibBundleContent: string; -export function getLuaLibBundle(emitHost: EmitHost): string { - if (luaLibBundleContent === undefined) { - const lualibPath = path.resolve(__dirname, "../dist/lualib/lualib_bundle.lua"); +export function loadInlineLualibFeatures( + features: Iterable, + luaTarget: LuaTarget, + emitHost: EmitHost +): string { + return resolveRecursiveLualibFeatures(features, luaTarget, emitHost) + .map(feature => readLuaLibFeature(feature, luaTarget, emitHost)) + .join("\n"); +} + +export function loadImportedLualibFeatures( + features: Iterable, + luaTarget: LuaTarget, + emitHost: EmitHost +): lua.Statement[] { + const luaLibModuleInfo = getLuaLibModulesInfo(luaTarget, emitHost); + + const imports = Array.from(features).flatMap(feature => luaLibModuleInfo[feature].exports); + if (imports.length === 0) { + return []; + } + + const requireCall = lua.createCallExpression(lua.createIdentifier("require"), [ + lua.createStringLiteral("lualib_bundle"), + ]); + + const luaLibId = lua.createIdentifier("____lualib"); + const importStatement = lua.createVariableDeclarationStatement(luaLibId, requireCall); + const statements: lua.Statement[] = [importStatement]; + // local = ____luaLib. + for (const item of imports) { + statements.push( + lua.createVariableDeclarationStatement( + lua.createIdentifier(item), + lua.createTableIndexExpression(luaLibId, lua.createStringLiteral(item)) + ) + ); + } + return statements; +} + +const luaLibBundleContent = new Map(); + +export function getLuaLibBundle(luaTarget: LuaTarget, emitHost: EmitHost): string { + const lualibPath = path.join(resolveLuaLibDir(luaTarget), "lualib_bundle.lua"); + if (!luaLibBundleContent.has(lualibPath)) { const result = emitHost.readFile(lualibPath); if (result !== undefined) { - luaLibBundleContent = result; + luaLibBundleContent.set(lualibPath, result); } else { throw new Error(`Could not load lualib bundle from '${lualibPath}'`); } } - return luaLibBundleContent; + return luaLibBundleContent.get(lualibPath) as string; +} + +export function getLualibBundleReturn(exportedValues: string[]): string { + return `\nreturn {\n${exportedValues.map(exportName => ` ${exportName} = ${exportName}`).join(",\n")}\n}\n`; +} + +export function buildMinimalLualibBundle( + features: Iterable, + luaTarget: LuaTarget, + emitHost: EmitHost +): string { + const code = loadInlineLualibFeatures(features, luaTarget, emitHost); + const moduleInfo = getLuaLibModulesInfo(luaTarget, emitHost); + const exports = Array.from(features).flatMap(feature => moduleInfo[feature].exports); + + return code + getLualibBundleReturn(exports); +} + +export function findUsedLualibFeatures( + luaTarget: LuaTarget, + emitHost: EmitHost, + luaContents: string[] +): Set { + const features = new Set(); + const exportToFeatureMap = getLuaLibExportToFeatureMap(luaTarget, emitHost); + + for (const lua of luaContents) { + const regex = /^local (\w+) = ____lualib\.(\w+)$/gm; + while (true) { + const match = regex.exec(lua); + if (!match) break; + const [, localName, exportName] = match; + if (localName !== exportName) continue; + const feature = exportToFeatureMap.get(exportName); + if (feature) features.add(feature); + } + } + + return features; } diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index 390b62977..26b55421b 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -1,11 +1,12 @@ +import * as path from "path"; import { Mapping, SourceMapGenerator, SourceNode } from "source-map"; import * as ts from "typescript"; -import { CompilerOptions, LuaLibImportKind } from "./CompilerOptions"; +import { CompilerOptions, isBundleEnabled, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; import * as lua from "./LuaAST"; -import { loadLuaLibFeatures, LuaLibFeature } from "./LuaLib"; -import { isValidLuaIdentifier } from "./transformation/utils/safe-names"; -import { EmitHost } from "./transpilation"; -import { intersperse, trimExtension } from "./utils"; +import { loadImportedLualibFeatures, loadInlineLualibFeatures, LuaLibFeature } from "./LuaLib"; +import { isValidLuaIdentifier, shouldAllowUnicode } from "./transformation/utils/safe-names"; +import { EmitHost, getEmitPath } from "./transpilation"; +import { intersperse, normalizeSlashes } from "./utils"; // https://www.lua.org/pil/2.4.html // https://www.ecma-international.org/ecma-262/10.0/index.html#table-34 @@ -32,7 +33,8 @@ export const tstlHeader = "--[[ Generated with https://github.com/TypeScriptToLu * `foo.bar` => passes (`function foo.bar()` is valid) * `getFoo().bar` => fails (`function getFoo().bar()` would be illegal) */ -const isValidLuaFunctionDeclarationName = (str: string) => /^[a-zA-Z0-9_.]+$/.test(str); +const isValidLuaFunctionDeclarationName = (str: string, options: CompilerOptions) => + (shouldAllowUnicode(options) ? /^[a-zA-Z0-9_\u00FF-\uFFFD.]+$/ : /^[a-zA-Z0-9_.]+$/).test(str); /** * Returns true if expression contains no function calls. @@ -118,14 +120,55 @@ export class LuaPrinter { [lua.SyntaxKind.BitwiseLeftShiftOperator]: "<<", [lua.SyntaxKind.BitwiseNotOperator]: "~", }; + private static operatorPrecedence: Record = { + [lua.SyntaxKind.OrOperator]: 1, + [lua.SyntaxKind.AndOperator]: 2, - private currentIndent = ""; - private sourceFile: string; - private options: CompilerOptions; + [lua.SyntaxKind.EqualityOperator]: 3, + [lua.SyntaxKind.InequalityOperator]: 3, + [lua.SyntaxKind.LessThanOperator]: 3, + [lua.SyntaxKind.LessEqualOperator]: 3, + [lua.SyntaxKind.GreaterThanOperator]: 3, + [lua.SyntaxKind.GreaterEqualOperator]: 3, - constructor(private emitHost: EmitHost, program: ts.Program, fileName: string) { + [lua.SyntaxKind.BitwiseOrOperator]: 4, + [lua.SyntaxKind.BitwiseExclusiveOrOperator]: 5, + [lua.SyntaxKind.BitwiseAndOperator]: 6, + + [lua.SyntaxKind.BitwiseLeftShiftOperator]: 7, + [lua.SyntaxKind.BitwiseRightShiftOperator]: 7, + + [lua.SyntaxKind.ConcatOperator]: 8, + + [lua.SyntaxKind.AdditionOperator]: 9, + [lua.SyntaxKind.SubtractionOperator]: 9, + + [lua.SyntaxKind.MultiplicationOperator]: 10, + [lua.SyntaxKind.DivisionOperator]: 10, + [lua.SyntaxKind.FloorDivisionOperator]: 10, + [lua.SyntaxKind.ModuloOperator]: 10, + + [lua.SyntaxKind.NotOperator]: 11, + [lua.SyntaxKind.LengthOperator]: 11, + [lua.SyntaxKind.NegationOperator]: 11, + [lua.SyntaxKind.BitwiseNotOperator]: 11, + + [lua.SyntaxKind.PowerOperator]: 12, + }; + private static rightAssociativeOperators = new Set([lua.SyntaxKind.ConcatOperator, lua.SyntaxKind.PowerOperator]); + + protected currentIndent = ""; + protected luaFile: string; + protected relativeSourcePath: string; + protected options: CompilerOptions; + + public static readonly sourceMapTracebackPlaceholder = "{#SourceMapTraceback}"; + + constructor(private emitHost: EmitHost, private program: ts.Program, private sourceFile: string) { this.options = program.getCompilerOptions(); - this.sourceFile = fileName; + this.luaFile = normalizeSlashes(getEmitPath(this.sourceFile, this.program)); + // Source nodes contain relative path from mapped lua file to original TS source file + this.relativeSourcePath = normalizeSlashes(path.relative(path.dirname(this.luaFile), this.sourceFile)); } public print(file: lua.File): PrintResult { @@ -149,7 +192,7 @@ export class LuaPrinter { if (this.options.sourceMapTraceback) { const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); - code = code.replace("{#SourceMapTraceback}", stackTraceOverride); + code = code.replace(LuaPrinter.sourceMapTracebackPlaceholder, stackTraceOverride); } return { code, sourceMap: sourceMap.toString(), sourceMapNode: rootSourceNode }; @@ -183,31 +226,40 @@ export class LuaPrinter { return `__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapString});`; } - private printFile(file: lua.File): SourceNode { - let header = file.trivia; + protected printFile(file: lua.File): SourceNode { + let sourceChunks: SourceChunk[] = [file.trivia]; if (!this.options.noHeader) { - header += tstlHeader; + sourceChunks.push(tstlHeader); } + const luaTarget = this.options.luaTarget ?? LuaTarget.Universal; const luaLibImport = this.options.luaLibImport ?? LuaLibImportKind.Require; if ( - luaLibImport === LuaLibImportKind.Always || - (luaLibImport === LuaLibImportKind.Require && file.luaLibFeatures.size > 0) + (luaLibImport === LuaLibImportKind.Require || luaLibImport === LuaLibImportKind.RequireMinimal) && + file.luaLibFeatures.size > 0 ) { - // Require lualib bundle - header += 'require("lualib_bundle");\n'; + // Import lualib features + sourceChunks = this.printStatementArray( + loadImportedLualibFeatures(file.luaLibFeatures, luaTarget, this.emitHost) + ); } else if (luaLibImport === LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) { // Inline lualib features - header += "-- Lua Library inline imports\n"; - header += loadLuaLibFeatures(file.luaLibFeatures, this.emitHost); + sourceChunks.push("-- Lua Library inline imports\n"); + sourceChunks.push(loadInlineLualibFeatures(file.luaLibFeatures, luaTarget, this.emitHost)); + sourceChunks.push("-- End of Lua Library inline imports\n"); } - if (this.options.sourceMapTraceback) { - header += "{#SourceMapTraceback}\n"; + if (this.options.sourceMapTraceback && !isBundleEnabled(this.options)) { + // In bundle mode the traceback is being generated for the entire file in getBundleResult + // Otherwise, traceback is being generated locally + sourceChunks.push(`${LuaPrinter.sourceMapTracebackPlaceholder}\n`); } - return this.concatNodes(header, ...this.printStatementArray(file.statements)); + // Print reest of the statements in file + sourceChunks.push(...this.printStatementArray(file.statements)); + + return this.concatNodes(...sourceChunks); } protected pushIndent(): void { @@ -226,12 +278,12 @@ export class LuaPrinter { const { line, column } = lua.getOriginalPos(node); return line !== undefined && column !== undefined - ? new SourceNode(line + 1, column, this.sourceFile, chunks, name) - : new SourceNode(null, null, this.sourceFile, chunks, name); + ? new SourceNode(line + 1, column, this.relativeSourcePath, chunks, name) + : new SourceNode(null, null, this.relativeSourcePath, chunks, name); } protected concatNodes(...chunks: SourceChunk[]): SourceNode { - return new SourceNode(null, null, this.sourceFile, chunks); + return new SourceNode(null, null, this.relativeSourcePath, chunks); } protected printBlock(block: lua.Block): SourceNode { @@ -276,7 +328,7 @@ export class LuaPrinter { statementNodes.push(node); - if (lua.isReturnStatement(statement)) break; + if (lua.isReturnStatement(statement) || lua.isBreakStatement(statement)) break; } return statementNodes.length > 0 ? [...intersperse(statementNodes, "\n"), "\n"] : []; @@ -344,6 +396,8 @@ export class LuaPrinter { return this.printReturnStatement(statement as lua.ReturnStatement); case lua.SyntaxKind.BreakStatement: return this.printBreakStatement(statement as lua.BreakStatement); + case lua.SyntaxKind.ContinueStatement: + return this.printContinueStatement(statement as lua.ContinueStatement); case lua.SyntaxKind.ExpressionStatement: return this.printExpressionStatement(statement as lua.ExpressionStatement); default: @@ -388,13 +442,10 @@ export class LuaPrinter { chunks.push(this.indent()); - if ( - lua.isFunctionDefinition(statement) && - (statement.right[0].flags & lua.FunctionExpressionFlags.Declaration) !== 0 - ) { + if (lua.isFunctionDefinition(statement) && (statement.right[0].flags & lua.NodeFlags.Declaration) !== 0) { // Use `function foo()` instead of `foo = function()` const name = this.printExpression(statement.left[0]); - if (isValidLuaFunctionDeclarationName(name.toString())) { + if (isValidLuaFunctionDeclarationName(name.toString(), this.options)) { chunks.push(this.printFunctionDefinition(statement)); return this.createSourceNode(statement, chunks); } @@ -525,6 +576,10 @@ export class LuaPrinter { return this.createSourceNode(statement, this.indent("break")); } + public printContinueStatement(statement: lua.ContinueStatement): SourceNode { + return this.createSourceNode(statement, this.indent("continue")); + } + public printExpressionStatement(statement: lua.ExpressionStatement): SourceNode { return this.createSourceNode(statement, [this.indent(), this.printExpression(statement.expression)]); } @@ -540,6 +595,8 @@ export class LuaPrinter { return this.printNilLiteral(expression as lua.NilLiteral); case lua.SyntaxKind.DotsKeyword: return this.printDotsLiteral(expression as lua.DotsLiteral); + case lua.SyntaxKind.ArgKeyword: + return this.printArgLiteral(expression as lua.ArgLiteral); case lua.SyntaxKind.TrueKeyword: case lua.SyntaxKind.FalseKeyword: return this.printBooleanLiteral(expression as lua.BooleanLiteral); @@ -561,6 +618,10 @@ export class LuaPrinter { return this.printIdentifier(expression as lua.Identifier); case lua.SyntaxKind.TableIndexExpression: return this.printTableIndexExpression(expression as lua.TableIndexExpression); + case lua.SyntaxKind.ParenthesizedExpression: + return this.printParenthesizedExpression(expression as lua.ParenthesizedExpression); + case lua.SyntaxKind.ConditionalExpression: + return this.printConditionalExpression(expression as lua.ConditionalExpression); default: throw new Error(`Tried to print unknown statement kind: ${lua.SyntaxKind[expression.kind]}`); } @@ -582,6 +643,10 @@ export class LuaPrinter { return this.createSourceNode(expression, "..."); } + public printArgLiteral(expression: lua.ArgLiteral): SourceNode { + return this.createSourceNode(expression, "arg"); + } + public printBooleanLiteral(expression: lua.BooleanLiteral): SourceNode { return this.createSourceNode(expression, expression.kind === lua.SyntaxKind.TrueKeyword ? "true" : "false"); } @@ -647,7 +712,7 @@ export class LuaPrinter { const value = this.printExpression(expression.value); if (expression.key) { - if (lua.isStringLiteral(expression.key) && isValidLuaIdentifier(expression.key.value)) { + if (lua.isStringLiteral(expression.key) && isValidLuaIdentifier(expression.key.value, this.options)) { chunks.push(expression.key.value, " = ", value); } else { chunks.push("[", this.printExpression(expression.key), "] = ", value); @@ -667,34 +732,49 @@ export class LuaPrinter { const chunks: SourceChunk[] = []; chunks.push(this.printOperator(expression.operator)); - chunks.push(this.printExpressionInParenthesesIfNeeded(expression.operand)); + chunks.push( + this.printExpressionInParenthesesIfNeeded( + expression.operand, + LuaPrinter.operatorPrecedence[expression.operator] + ) + ); return this.createSourceNode(expression, chunks); } public printBinaryExpression(expression: lua.BinaryExpression): SourceNode { const chunks: SourceChunk[] = []; - - chunks.push(this.printExpressionInParenthesesIfNeeded(expression.left)); + const isRightAssociative = LuaPrinter.rightAssociativeOperators.has(expression.operator); + const precedence = LuaPrinter.operatorPrecedence[expression.operator]; + chunks.push( + this.printExpressionInParenthesesIfNeeded(expression.left, isRightAssociative ? precedence + 1 : precedence) + ); chunks.push(" ", this.printOperator(expression.operator), " "); - chunks.push(this.printExpressionInParenthesesIfNeeded(expression.right)); + chunks.push( + this.printExpressionInParenthesesIfNeeded( + expression.right, + isRightAssociative ? precedence : precedence + 1 + ) + ); return this.createSourceNode(expression, chunks); } - private printExpressionInParenthesesIfNeeded(expression: lua.Expression): SourceNode { - return this.needsParenthesis(expression) + private printExpressionInParenthesesIfNeeded(expression: lua.Expression, minPrecedenceToOmit?: number): SourceNode { + return this.needsParenthesis(expression, minPrecedenceToOmit) ? this.createSourceNode(expression, ["(", this.printExpression(expression), ")"]) : this.printExpression(expression); } - private needsParenthesis(expression: lua.Expression): boolean { - return ( - lua.isBinaryExpression(expression) || - lua.isFunctionExpression(expression) || - lua.isTableExpression(expression) || - (lua.isUnaryExpression(expression) && expression.operator === lua.SyntaxKind.NotOperator) - ); + private needsParenthesis(expression: lua.Expression, minPrecedenceToOmit?: number): boolean { + if (lua.isBinaryExpression(expression) || lua.isUnaryExpression(expression)) { + return ( + minPrecedenceToOmit === undefined || + LuaPrinter.operatorPrecedence[expression.operator] < minPrecedenceToOmit + ); + } else { + return lua.isFunctionExpression(expression) || lua.isTableExpression(expression); + } } public printCallExpression(expression: lua.CallExpression): SourceNode { @@ -744,7 +824,7 @@ export class LuaPrinter { const chunks: SourceChunk[] = []; chunks.push(this.printExpressionInParenthesesIfNeeded(expression.table)); - if (lua.isStringLiteral(expression.index) && isValidLuaIdentifier(expression.index.value)) { + if (lua.isStringLiteral(expression.index) && isValidLuaIdentifier(expression.index.value, this.options)) { chunks.push(".", this.createSourceNode(expression.index, expression.index.value)); } else { chunks.push("[", this.printExpression(expression.index), "]"); @@ -752,18 +832,42 @@ export class LuaPrinter { return this.createSourceNode(expression, chunks); } + public printParenthesizedExpression(expression: lua.ParenthesizedExpression) { + return this.createSourceNode(expression, ["(", this.printExpression(expression.expression), ")"]); + } + + public printConditionalExpression(expression: lua.ConditionalExpression): SourceNode { + return this.createSourceNode(expression, [ + "if ", + this.printExpression(expression.condition), + " then ", + this.printExpression(expression.whenTrue), + " else ", + this.printExpression(expression.whenFalse), + ]); + } + public printOperator(kind: lua.Operator): SourceNode { - return new SourceNode(null, null, this.sourceFile, LuaPrinter.operatorMap[kind]); + return new SourceNode(null, null, this.relativeSourcePath, LuaPrinter.operatorMap[kind]); } protected joinChunksWithComma(chunks: SourceChunk[]): SourceChunk[] { return intersperse(chunks, ", "); } + /** + * Returns true if the expression list (table field or parameters) should be printed on one line. + */ + protected isSimpleExpressionList(expressions: lua.Expression[]): boolean { + if (expressions.length <= 1) return true; + if (expressions.length > 4) return false; + return expressions.every(isSimpleExpression); + } + protected printExpressionList(expressions: lua.Expression[]): SourceChunk[] { const chunks: SourceChunk[] = []; - if (expressions.every(isSimpleExpression)) { + if (this.isSimpleExpressionList(expressions)) { chunks.push(...this.joinChunksWithComma(expressions.map(e => this.printExpression(e)))); } else { chunks.push("\n"); @@ -783,7 +887,7 @@ export class LuaPrinter { // will not generate 'empty' mappings in the source map that point to nothing in the original TS. private buildSourceMap(sourceRoot: string, rootSourceNode: SourceNode): SourceMapGenerator { const map = new SourceMapGenerator({ - file: trimExtension(this.sourceFile) + ".lua", + file: path.basename(this.luaFile), sourceRoot, }); @@ -823,9 +927,9 @@ export class LuaPrinter { map.addMapping(currentMapping); } - for (const chunk of sourceNode.children) { + for (const chunk of sourceNode.children as SourceChunk[]) { if (typeof chunk === "string") { - const lines = (chunk as string).split("\n"); + const lines = chunk.split("\n"); if (lines.length > 1) { generatedLine += lines.length - 1; generatedColumn = 0; diff --git a/src/cli/diagnostics.ts b/src/cli/diagnostics.ts index e386fa391..963713d2b 100644 --- a/src/cli/diagnostics.ts +++ b/src/cli/diagnostics.ts @@ -33,6 +33,11 @@ export const compilerOptionRequiresAValueOfType = createCommandLineError( (name: string, type: string) => `Compiler option '${name}' requires a value of type ${type}.` ); +export const compilerOptionCouldNotParseJson = createCommandLineError( + 5025, + (name: string, error: string) => `Compiler option '${name}' failed to parse the given JSON value: '${error}'.` +); + export const optionProjectCannotBeMixedWithSourceFilesOnACommandLine = createCommandLineError( 5042, () => "Option 'project' cannot be mixed with source files on a command line." diff --git a/src/cli/parse.ts b/src/cli/parse.ts index b7ed906e3..ca4f039ad 100644 --- a/src/cli/parse.ts +++ b/src/cli/parse.ts @@ -18,7 +18,7 @@ interface CommandLineOptionOfEnum extends CommandLineOptionBase { } interface CommandLineOptionOfPrimitive extends CommandLineOptionBase { - type: "boolean" | "string" | "object"; + type: "boolean" | "string" | "json-array-of-objects" | "array"; } type CommandLineOption = CommandLineOptionOfEnum | CommandLineOptionOfPrimitive; @@ -30,6 +30,11 @@ export const optionDeclarations: CommandLineOption[] = [ type: "enum", choices: Object.values(BuildMode), }, + { + name: "extension", + description: 'File extension for the resulting Lua files. Defaults to ".lua"', + type: "string", + }, { name: "luaBundle", description: "The name of the lua file to bundle output lua to. Requires luaBundleEntry.", @@ -53,6 +58,12 @@ export const optionDeclarations: CommandLineOption[] = [ type: "enum", choices: Object.values(LuaTarget), }, + { + name: "noImplicitGlobalVariables", + description: + 'Specify to prevent implicitly turning "normal" variants into global variables in the transpiled output.', + type: "boolean", + }, { name: "noImplicitSelf", description: 'If "this" is implicitly considered an any type, do not generate a self parameter.', @@ -71,13 +82,28 @@ export const optionDeclarations: CommandLineOption[] = [ { name: "luaPlugins", description: "List of TypeScriptToLua plugins.", - type: "object", + type: "json-array-of-objects", }, { name: "tstlVerbose", description: "Provide verbose output useful for diagnosing problems.", type: "boolean", }, + { + name: "noResolvePaths", + description: "An array of paths that tstl should not resolve and keep as-is.", + type: "array", + }, + { + name: "lua51AllowTryCatchInAsyncAwait", + description: "Always allow try/catch in async/await functions for Lua 5.1.", + type: "boolean", + }, + { + name: "measurePerformance", + description: "Measure performance of the tstl compiler.", + type: "boolean", + }, ]; export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): ParsedCommandLine { @@ -103,7 +129,7 @@ export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): continue; } - const { error, value } = readValue(option, rawValue); + const { error, value } = readValue(option, rawValue, OptionSource.TsConfig); if (error) parsedConfigFile.errors.push(error); if (parsedConfigFile.options[name] === undefined) parsedConfigFile.options[name] = value; } @@ -121,7 +147,7 @@ function updateParsedCommandLine(parsedCommandLine: ts.ParsedCommandLine, args: if (!args[i].startsWith("-")) continue; const isShorthand = !args[i].startsWith("--"); - const argumentName = args[i].substr(isShorthand ? 1 : 2); + const argumentName = args[i].substring(isShorthand ? 1 : 2); const option = optionDeclarations.find(option => { if (option.name.toLowerCase() === argumentName.toLowerCase()) return true; if (isShorthand && option.aliases) { @@ -143,9 +169,9 @@ function updateParsedCommandLine(parsedCommandLine: ts.ParsedCommandLine, args: if (error) parsedCommandLine.errors.push(error); parsedCommandLine.options[option.name] = value; if (consumed) { - i += 1; // Values of custom options are parsed as a file name, exclude them - parsedCommandLine.fileNames = parsedCommandLine.fileNames.filter(f => f !== value); + parsedCommandLine.fileNames = parsedCommandLine.fileNames.filter(f => f !== args[i + 1]); + i += 1; } } } @@ -175,7 +201,12 @@ function readCommandLineArgument(option: CommandLineOption, value: any): Command }; } - return { ...readValue(option, value), consumed: true }; + return { ...readValue(option, value, OptionSource.CommandLine), consumed: true }; +} + +enum OptionSource { + CommandLine, + TsConfig, } interface ReadValueResult { @@ -183,13 +214,12 @@ interface ReadValueResult { value: any; } -function readValue(option: CommandLineOption, value: unknown): ReadValueResult { +function readValue(option: CommandLineOption, value: unknown, source: OptionSource): ReadValueResult { if (value === null) return { value }; switch (option.type) { case "boolean": - case "string": - case "object": { + case "string": { if (typeof value !== option.type) { return { value: undefined, @@ -199,7 +229,45 @@ function readValue(option: CommandLineOption, value: unknown): ReadValueResult { return { value }; } + case "array": + case "json-array-of-objects": { + const isInvalidNonCliValue = source === OptionSource.TsConfig && !Array.isArray(value); + const isInvalidCliValue = source === OptionSource.CommandLine && typeof value !== "string"; + if (isInvalidNonCliValue || isInvalidCliValue) { + return { + value: undefined, + error: cliDiagnostics.compilerOptionRequiresAValueOfType(option.name, option.type), + }; + } + + const shouldParseValue = source === OptionSource.CommandLine && typeof value === "string"; + if (!shouldParseValue) return { value }; + + if (option.type === "array") { + const array = value.split(","); + return { value: array }; + } + + try { + const objects = JSON.parse(value); + if (!Array.isArray(objects)) { + return { + value: undefined, + error: cliDiagnostics.compilerOptionRequiresAValueOfType(option.name, option.type), + }; + } + + return { value: objects }; + } catch (e) { + if (!(e instanceof SyntaxError)) throw e; + + return { + value: undefined, + error: cliDiagnostics.compilerOptionCouldNotParseJson(option.name, e.message), + }; + } + } case "enum": { if (typeof value !== "string") { return { diff --git a/src/cli/tsconfig.ts b/src/cli/tsconfig.ts index bc6fb5ae9..33e469368 100644 --- a/src/cli/tsconfig.ts +++ b/src/cli/tsconfig.ts @@ -1,6 +1,6 @@ import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions } from "../CompilerOptions"; +import { CompilerOptions, TypeScriptToLuaOptions } from "../CompilerOptions"; import { normalizeSlashes } from "../utils"; import * as cliDiagnostics from "./diagnostics"; import { ParsedCommandLine, updateParsedConfigFile } from "./parse"; @@ -41,17 +41,93 @@ export function parseConfigFileWithSystem( commandLineOptions?: CompilerOptions, system = ts.sys ): ParsedCommandLine { + const configRootDir = path.dirname(configFileName); const parsedConfigFile = ts.parseJsonSourceFileConfigFileContent( ts.readJsonConfigFile(configFileName, system.readFile), system, - path.dirname(configFileName), + configRootDir, commandLineOptions, configFileName ); + const cycleCache = new Set(); + const extendedTstlOptions = getExtendedTstlOptions(configFileName, configRootDir, cycleCache, system); + + parsedConfigFile.raw.tstl = Object.assign(extendedTstlOptions, parsedConfigFile.raw.tstl ?? {}); + return updateParsedConfigFile(parsedConfigFile); } +function resolveNpmModuleConfig( + moduleName: string, + configRootDir: string, + host: ts.ModuleResolutionHost +): string | undefined { + const resolved = ts.nodeNextJsonConfigResolver(moduleName, path.join(configRootDir, "tsconfig.json"), host); + if (resolved.resolvedModule) { + return resolved.resolvedModule.resolvedFileName; + } +} + +function getExtendedTstlOptions( + configFilePath: string, + configRootDir: string, + cycleCache: Set, + system: ts.System +): TypeScriptToLuaOptions { + const absolutePath = ts.pathIsAbsolute(configFilePath) + ? configFilePath + : ts.pathIsRelative(configFilePath) + ? path.resolve(configRootDir, configFilePath) + : resolveNpmModuleConfig(configFilePath, configRootDir, system); // if a path is neither relative nor absolute, it is probably a npm module + + if (!absolutePath) { + return {}; + } + + const newConfigRoot = path.dirname(absolutePath); + + if (cycleCache.has(absolutePath)) { + return {}; + } + + cycleCache.add(absolutePath); + const fileContent = system.readFile(absolutePath); + const options = {}; + + if (fileContent) { + const { config: parsedConfig } = ts.parseConfigFileTextToJson(configFilePath, fileContent) as { + config?: { + extends?: string | string[]; + tstl?: TypeScriptToLuaOptions; + }; + }; + + if (!parsedConfig) { + return {}; + } + + if (parsedConfig.extends) { + if (Array.isArray(parsedConfig.extends)) { + for (const extendedConfigFile of parsedConfig.extends) { + Object.assign( + options, + getExtendedTstlOptions(extendedConfigFile, newConfigRoot, cycleCache, system) + ); + } + } else { + Object.assign(options, getExtendedTstlOptions(parsedConfig.extends, newConfigRoot, cycleCache, system)); + } + } + + if (parsedConfig.tstl) { + Object.assign(options, parsedConfig.tstl); + } + } + + return options; +} + export function createConfigFileUpdater( optionsToExtend: CompilerOptions ): (options: ts.CompilerOptions) => ts.Diagnostic[] { @@ -61,16 +137,7 @@ export function createConfigFileUpdater( if (!configFile || !configFilePath) return []; if (!configFileMap.has(configFile)) { - const parsedConfigFile = updateParsedConfigFile( - ts.parseJsonSourceFileConfigFileContent( - configFile, - ts.sys, - path.dirname(configFilePath), - optionsToExtend, - configFilePath - ) - ); - + const parsedConfigFile = parseConfigFileWithSystem(configFilePath, optionsToExtend, ts.sys); configFileMap.set(configFile, parsedConfigFile); } diff --git a/src/index.ts b/src/index.ts index 3d060a994..2d2e3de54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,3 +8,4 @@ export { LuaLibFeature } from "./LuaLib"; export * from "./LuaPrinter"; export * from "./transformation/context"; export * from "./transpilation"; +export { EmitHost, EmitFile, ProcessedFile } from "./transpilation/utils"; diff --git a/src/lualib-build/plugin.ts b/src/lualib-build/plugin.ts new file mode 100644 index 000000000..79233f3df --- /dev/null +++ b/src/lualib-build/plugin.ts @@ -0,0 +1,188 @@ +import { SourceNode } from "source-map"; +import * as ts from "typescript"; +import * as tstl from ".."; +import * as path from "path"; +import { + getLualibBundleReturn, + LuaLibFeature, + LuaLibModulesInfo, + luaLibModulesInfoFileName, + resolveRecursiveLualibFeatures, +} from "../LuaLib"; +import { EmitHost, ProcessedFile } from "../transpilation/utils"; +import { + isExportAlias, + isExportAssignment, + isExportsReturn, + isExportTableDeclaration, + isImport, + isRequire, +} from "./util"; +import { createDiagnosticFactoryWithCode } from "../utils"; + +export const lualibDiagnostic = createDiagnosticFactoryWithCode(200000, (message: string, file?: ts.SourceFile) => ({ + messageText: message, + file, + start: file && 0, + length: file && 0, +})); + +class LuaLibPlugin implements tstl.Plugin { + // Plugin members + public visitors = { + [ts.SyntaxKind.SourceFile]: this.lualibFileVisitor.bind(this), + }; + + public printer: tstl.Printer = (program, emitHost, fileName, file) => + new LuaLibPrinter(emitHost, program, fileName).print(file); + + public afterPrint(program: ts.Program, options: tstl.CompilerOptions, emitHost: EmitHost, result: ProcessedFile[]) { + void options; + + // Write lualib dependency json + const { result: luaLibModuleInfo, diagnostics } = this.createLuaLibModulesInfo(); + const emitBOM = options.emitBOM ?? false; + emitHost.writeFile( + path.join(tstl.getEmitOutDir(program), luaLibModulesInfoFileName), + JSON.stringify(luaLibModuleInfo, null, 2), + emitBOM + ); + + // Flatten the output folder structure; we do not want to keep the target-specific directories + for (const file of result) { + let outPath = file.fileName; + while (outPath.includes("lualib") && path.basename(path.dirname(outPath)) !== "lualib") { + const upOne = path.join(path.dirname(outPath), "..", path.basename(outPath)); + outPath = path.normalize(upOne); + } + file.fileName = outPath; + } + + // Create map of result files keyed by their 'lualib name' + const exportedLualibFeatures = new Map(result.map(f => [path.basename(f.fileName).split(".")[0], f.code])); + + // Figure out the order required in the bundle by recursively resolving all dependency features + const allFeatures = Object.values(LuaLibFeature) as LuaLibFeature[]; + const luaTarget = options.luaTarget ?? tstl.LuaTarget.Universal; + const orderedFeatures = resolveRecursiveLualibFeatures(allFeatures, luaTarget, emitHost, luaLibModuleInfo); + + // Concatenate lualib files into bundle with exports table and add lualib_bundle.lua to results + let lualibBundle = orderedFeatures.map(f => exportedLualibFeatures.get(LuaLibFeature[f])).join("\n"); + const exports = allFeatures.flatMap(feature => luaLibModuleInfo[feature].exports); + lualibBundle += getLualibBundleReturn(exports); + result.push({ fileName: "lualib_bundle.lua", code: lualibBundle }); + + return diagnostics; + } + + // Internals + protected featureExports: Map> = new Map(); + protected featureDependencies: Map> = new Map(); + + protected lualibFileVisitor(file: ts.SourceFile, context: tstl.TransformationContext): tstl.File { + const featureName = path.basename(file.fileName, ".ts") as tstl.LuaLibFeature; + if (!(featureName in tstl.LuaLibFeature)) { + context.diagnostics.push(lualibDiagnostic(`File is not a lualib feature: ${featureName}`, file)); + } + + // Transpile file as normal with tstl + const fileResult = context.superTransformNode(file)[0] as tstl.File; + + const usedFeatures = new Set(context.usedLuaLibFeatures); + + // Get all imports in file + const importNames = new Set(); + const imports = file.statements.filter(ts.isImportDeclaration); + for (const { importClause, moduleSpecifier } of imports) { + if (importClause?.namedBindings && ts.isNamedImports(importClause.namedBindings)) { + for (const { name } of importClause.namedBindings.elements) { + importNames.add(name.text); + } + } + // track lualib imports + if (ts.isStringLiteral(moduleSpecifier)) { + const featureName = path.basename(moduleSpecifier.text, ".ts") as tstl.LuaLibFeature; + if (featureName in tstl.LuaLibFeature) { + usedFeatures.add(featureName); + } + } + } + + const filteredStatements = fileResult.statements + .filter( + s => !isExportTableDeclaration(s) && !isRequire(s) && !isImport(s, importNames) && !isExportsReturn(s) + ) + .map(statement => { + if (isExportAlias(statement)) { + const name = statement.left[0]; + const exportName = statement.right[0].index.value; + if (name.text === exportName) return undefined; // Remove "x = x" statements + return tstl.createAssignmentStatement(name, tstl.createIdentifier(exportName)); + } + return statement; + }) + .filter(statement => statement !== undefined); + + const exportNames = filteredStatements.filter(isExportAssignment).map(s => s.left[0].index.value); + if (!filteredStatements.every(isExportAssignment)) { + // If there are local statements, wrap them in a do ... end with exports outside + const exports = tstl.createVariableDeclarationStatement(exportNames.map(k => tstl.createIdentifier(k))); + // transform export assignments to local assignments + const bodyStatements = filteredStatements.map(s => + isExportAssignment(s) + ? tstl.createAssignmentStatement(tstl.createIdentifier(s.left[0].index.value), s.right[0]) + : s + ); + + fileResult.statements = [exports, tstl.createDoStatement(bodyStatements)]; + } else { + // transform export assignments to local variable declarations + fileResult.statements = filteredStatements.map(s => + tstl.createVariableDeclarationStatement(tstl.createIdentifier(s.left[0].index.value), s.right[0]) + ); + } + + // Save dependency information + this.featureExports.set(featureName, new Set(exportNames)); + if (usedFeatures.size > 0) { + this.featureDependencies.set(featureName, usedFeatures); + } + + return fileResult; + } + + protected createLuaLibModulesInfo(): { result: LuaLibModulesInfo; diagnostics: ts.Diagnostic[] } { + const result: Partial = {}; + const diagnostics: ts.Diagnostic[] = []; + for (const feature of Object.values(tstl.LuaLibFeature)) { + const exports = this.featureExports.get(feature); + if (!exports) { + diagnostics.push(lualibDiagnostic(`Missing file for lualib feature: ${feature}`)); + continue; + } + const dependencies = this.featureDependencies.get(feature); + result[feature] = { + exports: Array.from(exports), + dependencies: dependencies ? Array.from(dependencies) : undefined, + }; + } + return { result: result as LuaLibModulesInfo, diagnostics }; + } +} + +class LuaLibPrinter extends tstl.LuaPrinter { + // Strip all exports during print + public printTableIndexExpression(expression: tstl.TableIndexExpression): SourceNode { + if ( + tstl.isIdentifier(expression.table) && + expression.table.text === "____exports" && + tstl.isStringLiteral(expression.index) + ) { + return super.printExpression(tstl.createIdentifier(expression.index.value)); + } + return super.printTableIndexExpression(expression); + } +} + +const pluginInstance = new LuaLibPlugin(); +export default pluginInstance; diff --git a/src/lualib-build/util.ts b/src/lualib-build/util.ts new file mode 100644 index 000000000..c8ea1e3a8 --- /dev/null +++ b/src/lualib-build/util.ts @@ -0,0 +1,47 @@ +import * as tstl from ".."; + +export function isExportTableDeclaration(node: tstl.Node): node is tstl.VariableDeclarationStatement & { left: [] } { + return tstl.isVariableDeclarationStatement(node) && isExportTable(node.left[0]); +} + +export function isExportTable(node: tstl.Node): node is tstl.Identifier { + return tstl.isIdentifier(node) && node.text === "____exports"; +} + +export type ExportTableIndex = tstl.TableIndexExpression & { index: tstl.StringLiteral }; +export function isExportTableIndex(node: tstl.Node): node is ExportTableIndex { + return tstl.isTableIndexExpression(node) && isExportTable(node.table) && tstl.isStringLiteral(node.index); +} + +export function isExportAlias( + node: tstl.Node +): node is tstl.VariableDeclarationStatement & { right: [ExportTableIndex] } { + return tstl.isVariableDeclarationStatement(node) && node.right !== undefined && isExportTableIndex(node.right[0]); +} + +export type ExportAssignment = tstl.AssignmentStatement & { left: [ExportTableIndex] }; +export function isExportAssignment(node: tstl.Node): node is ExportAssignment { + return tstl.isAssignmentStatement(node) && isExportTableIndex(node.left[0]); +} + +export function isRequire(node: tstl.Node) { + return ( + tstl.isVariableDeclarationStatement(node) && + node.right && + tstl.isCallExpression(node.right[0]) && + tstl.isIdentifier(node.right[0].expression) && + node.right[0].expression.text === "require" + ); +} + +export function isImport(node: tstl.Node, importNames: Set) { + return tstl.isVariableDeclarationStatement(node) && importNames.has(node.left[0].text); +} + +export function isExportsReturn(node: tstl.Node) { + return ( + tstl.isReturnStatement(node) && + tstl.isIdentifier(node.expressions[0]) && + node.expressions[0].text === "____exports" + ); +} diff --git a/src/lualib/5.0/CountVarargs.ts b/src/lualib/5.0/CountVarargs.ts new file mode 100644 index 000000000..34467ebd4 --- /dev/null +++ b/src/lualib/5.0/CountVarargs.ts @@ -0,0 +1,7 @@ +/** @noSelfInFile */ + +export function __TS__CountVarargs(...args: T[]): number { + // select() is not available in Lua 5.0. In this version, the arg table + // includes trailing nils. + return args.length; +} diff --git a/src/lualib/5.0/Match.ts b/src/lualib/5.0/Match.ts new file mode 100644 index 000000000..3b1705939 --- /dev/null +++ b/src/lualib/5.0/Match.ts @@ -0,0 +1,12 @@ +/** @noSelfInFile */ + +export function __TS__Match(s: string, pattern: string, init?: number): LuaMultiReturn { + const [start, end, ...captures] = string.find(s, pattern, init); + if (start === undefined || end === undefined) { + return $multi(); + } else if (captures.length <= 0) { + return $multi(s.slice(start - 1, end)); + } else { + return $multi(...(captures as string[])); + } +} diff --git a/src/lualib/5.0/MathModf.ts b/src/lualib/5.0/MathModf.ts new file mode 100644 index 000000000..ec816ebe0 --- /dev/null +++ b/src/lualib/5.0/MathModf.ts @@ -0,0 +1,6 @@ +/** @noSelfInFile */ + +export function __TS__MathModf(x: number): LuaMultiReturn<[number, number]> { + const integral = x > 0 ? Math.floor(x) : Math.ceil(x); + return $multi(integral, x - integral); +} diff --git a/src/lualib/5.0/SparseArraySpread.ts b/src/lualib/5.0/SparseArraySpread.ts new file mode 100644 index 000000000..9a11f3cc9 --- /dev/null +++ b/src/lualib/5.0/SparseArraySpread.ts @@ -0,0 +1,6 @@ +import { __TS__SparseArray } from "./SparseArray"; +import { __TS__Unpack } from "./Unpack"; + +export function __TS__SparseArraySpread(this: void, sparseArray: __TS__SparseArray): LuaMultiReturn { + return __TS__Unpack(sparseArray, 1, sparseArray.sparseLength); +} diff --git a/src/lualib/5.0/Unpack.ts b/src/lualib/5.0/Unpack.ts new file mode 100644 index 000000000..a84416233 --- /dev/null +++ b/src/lualib/5.0/Unpack.ts @@ -0,0 +1,16 @@ +/** @noSelfInFile */ + +// We're not interested in emulating all of the behaviors of unpack() from Lua +// 5.1, just the ones needed by other parts of lualib. +export function __TS__Unpack(list: T[], i: number, j?: number): LuaMultiReturn { + if (i === 1 && j === undefined) { + return unpack(list); + } else { + j ??= list.length; + const slice: T[] = []; + for (let n = i; n <= j; n++) { + slice[n - i] = list[n - 1]; // We don't want to add 1 to the index into list. + } + return $multi(...slice); + } +} diff --git a/src/lualib/ArrayAt.ts b/src/lualib/ArrayAt.ts new file mode 100644 index 000000000..32e4ea2b4 --- /dev/null +++ b/src/lualib/ArrayAt.ts @@ -0,0 +1,13 @@ +// https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.at +// Technically the specs also allow non-numeric types to be passed as index. +// However, TypeScript types the `Array.at` index param as number so we also expect only numbers +// This behaviour also matches the implementation of other Array functions in lualib. +export function __TS__ArrayAt(this: T[], relativeIndex: number): T | undefined { + const absoluteIndex = relativeIndex < 0 ? this.length + relativeIndex : relativeIndex; + + if (absoluteIndex >= 0 && absoluteIndex < this.length) { + return this[absoluteIndex]; + } + + return undefined; +} diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts index 30da83514..caaafa369 100644 --- a/src/lualib/ArrayConcat.ts +++ b/src/lualib/ArrayConcat.ts @@ -1,18 +1,22 @@ -function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] { - const out: any[] = []; - for (const val of arr1) { - out[out.length] = val; +export function __TS__ArrayConcat(this: T[], ...items: Array): T[] { + const result: T[] = []; + let len = 0; + for (const i of $range(1, this.length)) { + len++; + result[len - 1] = this[i - 1]; } - for (const arg of args) { - if (Array.isArray(arg)) { - const argAsArray = arg; - for (const val of argAsArray) { - out[out.length] = val; + for (const i of $range(1, items.length)) { + const item = items[i - 1]; + if (Array.isArray(item)) { + for (const j of $range(1, item.length)) { + len++; + result[len - 1] = item[j - 1]; } } else { - out[out.length] = arg; + len++; + result[len - 1] = item; } } - return out; + return result; } diff --git a/src/lualib/ArrayEntries.ts b/src/lualib/ArrayEntries.ts index 7d12f1347..6cdef13a3 100644 --- a/src/lualib/ArrayEntries.ts +++ b/src/lualib/ArrayEntries.ts @@ -1,5 +1,5 @@ // https://262.ecma-international.org/10.0/#sec-array.prototype.entries -function __TS__ArrayEntries(this: void, array: T[]): IterableIterator<[number, T]> { +export function __TS__ArrayEntries(this: void, array: T[]): IterableIterator<[number, T]> { let key = 0; return { [Symbol.iterator](): IterableIterator<[number, T]> { diff --git a/src/lualib/ArrayEvery.ts b/src/lualib/ArrayEvery.ts index 011dd9abe..d94efec54 100644 --- a/src/lualib/ArrayEvery.ts +++ b/src/lualib/ArrayEvery.ts @@ -1,10 +1,10 @@ -function __TS__ArrayEvery( - this: void, - arr: T[], - callbackfn: (value: T, index?: number, array?: any[]) => boolean +export function __TS__ArrayEvery( + this: T[], + callbackfn: (value: T, index?: number, array?: any[]) => boolean, + thisArg?: any ): boolean { - for (let i = 0; i < arr.length; i++) { - if (!callbackfn(arr[i], i, arr)) { + for (const i of $range(1, this.length)) { + if (!callbackfn.call(thisArg, this[i - 1], i - 1, this)) { return false; } } diff --git a/src/lualib/ArrayFill.ts b/src/lualib/ArrayFill.ts new file mode 100644 index 000000000..a1654114a --- /dev/null +++ b/src/lualib/ArrayFill.ts @@ -0,0 +1,19 @@ +// https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.fill +export function __TS__ArrayFill(this: T[], value: T, start?: number, end?: number): T[] { + let relativeStart = start ?? 0; + let relativeEnd = end ?? this.length; + + if (relativeStart < 0) { + relativeStart += this.length; + } + + if (relativeEnd < 0) { + relativeEnd += this.length; + } + + for (let i = relativeStart; i < relativeEnd; i++) { + this[i] = value; + } + + return this; +} diff --git a/src/lualib/ArrayFilter.ts b/src/lualib/ArrayFilter.ts index 3d88ddffa..5d63a0494 100644 --- a/src/lualib/ArrayFilter.ts +++ b/src/lualib/ArrayFilter.ts @@ -1,12 +1,14 @@ -function __TS__ArrayFilter( - this: void, - arr: T[], - callbackfn: (value: T, index?: number, array?: any[]) => boolean +export function __TS__ArrayFilter( + this: T[], + callbackfn: (value: T, index?: number, array?: any[]) => boolean, + thisArg?: any ): T[] { const result: T[] = []; - for (let i = 0; i < arr.length; i++) { - if (callbackfn(arr[i], i, arr)) { - result[result.length] = arr[i]; + let len = 0; + for (const i of $range(1, this.length)) { + if (callbackfn.call(thisArg, this[i - 1], i - 1, this)) { + len++; + result[len - 1] = this[i - 1]; } } return result; diff --git a/src/lualib/ArrayFind.ts b/src/lualib/ArrayFind.ts index 608bd3ef6..3beb9c83b 100644 --- a/src/lualib/ArrayFind.ts +++ b/src/lualib/ArrayFind.ts @@ -1,17 +1,14 @@ // https://www.ecma-international.org/ecma-262/10.0/index.html#sec-array.prototype.find -function __TS__ArrayFind( - this: void, - arr: T[], - predicate: (value: T, index: number, obj: T[]) => unknown +export function __TS__ArrayFind( + this: T[], + predicate: (value: T, index: number, obj: T[]) => unknown, + thisArg?: any ): T | undefined { - const len = arr.length; - let k = 0; - while (k < len) { - const elem = arr[k]; - if (predicate(elem, k, arr)) { + for (const i of $range(1, this.length)) { + const elem = this[i - 1]; + if (predicate.call(thisArg, elem, i - 1, this)) { return elem; } - k += 1; } return undefined; diff --git a/src/lualib/ArrayFindIndex.ts b/src/lualib/ArrayFindIndex.ts index 53d83cb39..3741f3a0f 100644 --- a/src/lualib/ArrayFindIndex.ts +++ b/src/lualib/ArrayFindIndex.ts @@ -1,11 +1,11 @@ -function __TS__ArrayFindIndex( - this: void, - arr: T[], - callbackFn: (element: T, index?: number, array?: T[]) => boolean +export function __TS__ArrayFindIndex( + this: T[], + callbackFn: (element: T, index?: number, array?: T[]) => boolean, + thisArg?: any ): number { - for (let i = 0, len = arr.length; i < len; i++) { - if (callbackFn(arr[i], i, arr)) { - return i; + for (const i of $range(1, this.length)) { + if (callbackFn.call(thisArg, this[i - 1], i - 1, this)) { + return i - 1; } } return -1; diff --git a/src/lualib/ArrayFlat.ts b/src/lualib/ArrayFlat.ts index 2bed314cb..3e15b455b 100644 --- a/src/lualib/ArrayFlat.ts +++ b/src/lualib/ArrayFlat.ts @@ -1,10 +1,23 @@ -function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] { - let result: any[] = []; - for (const value of array) { +export function __TS__ArrayFlat(this: any[], depth = 1): any[] { + const result: any[] = []; + let len = 0; + for (const i of $range(1, this.length)) { + const value = this[i - 1]; if (depth > 0 && Array.isArray(value)) { - result = result.concat(__TS__ArrayFlat(value, depth - 1)); + let toAdd: any[]; + if (depth === 1) { + toAdd = value; + } else { + toAdd = value.flat(depth - 1); + } + for (const j of $range(1, toAdd.length)) { + const val = toAdd[j - 1]; + len++; + result[len - 1] = val; + } } else { - result[result.length] = value; + len++; + result[len - 1] = value; } } diff --git a/src/lualib/ArrayFlatMap.ts b/src/lualib/ArrayFlatMap.ts index c31af9046..fa68fce8f 100644 --- a/src/lualib/ArrayFlatMap.ts +++ b/src/lualib/ArrayFlatMap.ts @@ -1,15 +1,20 @@ -function __TS__ArrayFlatMap( - this: void, - array: T[], - callback: (value: T, index: number, array: T[]) => U | readonly U[] +export function __TS__ArrayFlatMap( + this: T[], + callback: (value: T, index: number, array: T[]) => U | readonly U[], + thisArg?: any ): U[] { - let result: U[] = []; - for (let i = 0; i < array.length; i++) { - const value = callback(array[i], i, array); - if (type(value) === "table" && Array.isArray(value)) { - result = result.concat(value); + const result: U[] = []; + let len = 0; + for (const i of $range(1, this.length)) { + const value = callback.call(thisArg, this[i - 1], i - 1, this); + if (Array.isArray(value)) { + for (const j of $range(1, value.length)) { + len++; + result[len - 1] = value[j - 1]; + } } else { - result[result.length] = value as U; + len++; + result[len - 1] = value as U; } } diff --git a/src/lualib/ArrayForEach.ts b/src/lualib/ArrayForEach.ts index 96ac4a806..caf4ec53e 100644 --- a/src/lualib/ArrayForEach.ts +++ b/src/lualib/ArrayForEach.ts @@ -1,9 +1,9 @@ -function __TS__ArrayForEach( - this: void, - arr: T[], - callbackFn: (value: T, index?: number, array?: any[]) => any +export function __TS__ArrayForEach( + this: T[], + callbackFn: (value: T, index?: number, array?: any[]) => any, + thisArg?: any ): void { - for (let i = 0; i < arr.length; i++) { - callbackFn(arr[i], i, arr); + for (const i of $range(1, this.length)) { + callbackFn.call(thisArg, this[i - 1], i - 1, this); } } diff --git a/src/lualib/ArrayFrom.ts b/src/lualib/ArrayFrom.ts new file mode 100644 index 000000000..3742d7949 --- /dev/null +++ b/src/lualib/ArrayFrom.ts @@ -0,0 +1,37 @@ +/** @noSelfInFile */ + +import { __TS__Iterator } from "./Iterator"; + +function arrayLikeStep(this: ArrayLike, index: number): LuaMultiReturn<[number, unknown] | []> { + index += 1; + if (index > this.length) return $multi(); + return $multi(index, this[index]); +} + +const arrayLikeIterator: ( + this: void, + arr: ArrayLike | Iterable +) => LuaIterable> = ((arr: any) => { + if (typeof arr.length === "number") return $multi(arrayLikeStep, arr, 0); + return __TS__Iterator(arr); +}) as any; + +export function __TS__ArrayFrom( + this: void, + arrayLike: ArrayLike | Iterable, + mapFn?: (this: unknown, element: unknown, index: number) => unknown, + thisArg?: unknown +): unknown[] { + const result = []; + if (mapFn === undefined) { + for (const [, v] of arrayLikeIterator(arrayLike)) { + result.push(v); + } + } else { + let i = 0; + for (const [, v] of arrayLikeIterator(arrayLike)) { + result.push(mapFn.call(thisArg, v, i++)); + } + } + return result; +} diff --git a/src/lualib/ArrayIncludes.ts b/src/lualib/ArrayIncludes.ts index b012f87bf..b3fd871f6 100644 --- a/src/lualib/ArrayIncludes.ts +++ b/src/lualib/ArrayIncludes.ts @@ -1,5 +1,5 @@ // https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.includes -function __TS__ArrayIncludes(this: T[], searchElement: T, fromIndex = 0): boolean { +export function __TS__ArrayIncludes(this: T[], searchElement: T, fromIndex = 0): boolean { const len = this.length; let k = fromIndex; @@ -11,8 +11,8 @@ function __TS__ArrayIncludes(this: T[], searchElement: T, fromIndex = 0): boo k = 0; } - for (const i of $range(k, len)) { - if (this[i] === searchElement) { + for (const i of $range(k + 1, len)) { + if (this[i - 1] === searchElement) { return true; } } diff --git a/src/lualib/ArrayIndexOf.ts b/src/lualib/ArrayIndexOf.ts index e91a1a5dc..0a3ebc1f9 100644 --- a/src/lualib/ArrayIndexOf.ts +++ b/src/lualib/ArrayIndexOf.ts @@ -1,31 +1,23 @@ -function __TS__ArrayIndexOf(this: void, arr: T[], searchElement: T, fromIndex?: number): number { - const len = arr.length; +export function __TS__ArrayIndexOf(this: T[], searchElement: T, fromIndex = 0): number { + const len = this.length; if (len === 0) { return -1; } - let n = 0; - if (fromIndex) { - n = fromIndex; - } - - if (n >= len) { + if (fromIndex >= len) { return -1; } - let k: number; - if (n >= 0) { - k = n; - } else { - k = len + n; - if (k < 0) { - k = 0; + if (fromIndex < 0) { + fromIndex = len + fromIndex; + if (fromIndex < 0) { + fromIndex = 0; } } - for (let i = k; i < len; i++) { - if (arr[i] === searchElement) { - return i; + for (const i of $range(fromIndex + 1, len)) { + if (this[i - 1] === searchElement) { + return i - 1; } } diff --git a/src/lualib/ArrayIsArray.ts b/src/lualib/ArrayIsArray.ts index 38a4525ef..61fca760b 100644 --- a/src/lualib/ArrayIsArray.ts +++ b/src/lualib/ArrayIsArray.ts @@ -1,5 +1,7 @@ -function __TS__ArrayIsArray(this: void, value: any): value is any[] { +declare type NextEmptyCheck = (this: void, table: any, index?: undefined) => unknown | undefined; + +export function __TS__ArrayIsArray(this: void, value: any): value is any[] { // Workaround to determine if value is an array or not (fails in case of objects without keys) - // See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/7 - return type(value) === "table" && (1 in value || (next as NextEmptyCheck)(value, undefined) === undefined); + // See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737 + return type(value) === "table" && (1 in value || (next as NextEmptyCheck)(value) === undefined); } diff --git a/src/lualib/ArrayJoin.ts b/src/lualib/ArrayJoin.ts index 33e220181..0f0b11c9f 100644 --- a/src/lualib/ArrayJoin.ts +++ b/src/lualib/ArrayJoin.ts @@ -1,8 +1,7 @@ -function __TS__ArrayJoin(this: unknown[], separator = ",") { - let result = ""; - for (const [index, value] of ipairs(this)) { - if (index > 1) result += separator; - result += value.toString(); +export function __TS__ArrayJoin(this: any[], separator = ",") { + const parts: string[] = []; + for (const i of $range(1, this.length)) { + parts[i - 1] = this[i - 1].toString(); } - return result; + return table.concat(parts, separator); } diff --git a/src/lualib/ArrayMap.ts b/src/lualib/ArrayMap.ts index 04ee22a48..2caf84028 100644 --- a/src/lualib/ArrayMap.ts +++ b/src/lualib/ArrayMap.ts @@ -1,7 +1,11 @@ -function __TS__ArrayMap(this: void, arr: T[], callbackfn: (value: T, index?: number, array?: T[]) => U): U[] { - const newArray: U[] = []; - for (let i = 0; i < arr.length; i++) { - newArray[i] = callbackfn(arr[i], i, arr); +export function __TS__ArrayMap( + this: T[], + callbackfn: (value: T, index?: number, array?: T[]) => U, + thisArg?: any +): U[] { + const result: U[] = []; + for (const i of $range(1, this.length)) { + result[i - 1] = callbackfn.call(thisArg, this[i - 1], i - 1, this); } - return newArray; + return result; } diff --git a/src/lualib/ArrayPush.ts b/src/lualib/ArrayPush.ts index f09005e44..9f181d1f2 100644 --- a/src/lualib/ArrayPush.ts +++ b/src/lualib/ArrayPush.ts @@ -1,6 +1,8 @@ -function __TS__ArrayPush(this: void, arr: T[], ...items: T[]): number { - for (const item of items) { - arr[arr.length] = item; +export function __TS__ArrayPush(this: T[], ...items: T[]): number { + let len = this.length; + for (const i of $range(1, items.length)) { + len++; + this[len - 1] = items[i - 1]; } - return arr.length; + return len; } diff --git a/src/lualib/ArrayPushArray.ts b/src/lualib/ArrayPushArray.ts new file mode 100644 index 000000000..8ea9b6916 --- /dev/null +++ b/src/lualib/ArrayPushArray.ts @@ -0,0 +1,8 @@ +export function __TS__ArrayPushArray(this: T[], items: T[]): number { + let len = this.length; + for (const i of $range(1, items.length)) { + len++; + this[len - 1] = items[i - 1]; + } + return len; +} diff --git a/src/lualib/ArrayReduce.ts b/src/lualib/ArrayReduce.ts index c8ea2de50..cc569409a 100644 --- a/src/lualib/ArrayReduce.ts +++ b/src/lualib/ArrayReduce.ts @@ -1,27 +1,28 @@ +import { __TS__CountVarargs } from "./CountVarargs"; + // https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.reduce -function __TS__ArrayReduce( - this: void, - arr: T[], - callbackFn: (accumulator: T, currentValue: T, index: number, array: T[]) => T, - ...initial: T[] -): T { - const len = arr.length; +export function __TS__ArrayReduce( + this: TElement[], + callbackFn: (accumulator: TAccumulator, currentValue: TElement, index: number, array: TElement[]) => TAccumulator, + ...initial: TAccumulator[] +): TAccumulator { + const len = this.length; let k = 0; - let accumulator = undefined; + let accumulator: TAccumulator = undefined!; // Check if initial value is present in function call - if (select("#", ...initial) !== 0) { - accumulator = select(1, ...initial); + if (__TS__CountVarargs(...initial) !== 0) { + [accumulator] = [...initial]; } else if (len > 0) { - accumulator = arr[0]; + accumulator = this[0] as unknown as TAccumulator; k = 1; } else { throw "Reduce of empty array with no initial value"; } - for (const i of $range(k, len - 1)) { - accumulator = callbackFn(accumulator, arr[i], i, arr); + for (const i of $range(k + 1, len)) { + accumulator = callbackFn(accumulator, this[i - 1], i - 1, this); } return accumulator; diff --git a/src/lualib/ArrayReduceRight.ts b/src/lualib/ArrayReduceRight.ts index a0d5933d2..2316fa048 100644 --- a/src/lualib/ArrayReduceRight.ts +++ b/src/lualib/ArrayReduceRight.ts @@ -1,27 +1,28 @@ +import { __TS__CountVarargs } from "./CountVarargs"; + // https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.reduce -function __TS__ArrayReduceRight( - this: void, - arr: T[], - callbackFn: (accumulator: T, currentValue: T, index: number, array: T[]) => T, - ...initial: T[] -): T { - const len = arr.length; +export function __TS__ArrayReduceRight( + this: TElement[], + callbackFn: (accumulator: TAccumulator, currentValue: TElement, index: number, array: TElement[]) => TAccumulator, + ...initial: TAccumulator[] +): TAccumulator { + const len = this.length; let k = len - 1; - let accumulator = undefined; + let accumulator: TAccumulator = undefined!; // Check if initial value is present in function call - if (select("#", ...initial) !== 0) { - accumulator = select(1, ...initial); + if (__TS__CountVarargs(...initial) !== 0) { + [accumulator] = [...initial]; } else if (len > 0) { - accumulator = arr[k]; + accumulator = this[k] as unknown as TAccumulator; k -= 1; } else { throw "Reduce of empty array with no initial value"; } - for (const i of $range(k, 0, -1)) { - accumulator = callbackFn(accumulator, arr[i], i, arr); + for (const i of $range(k + 1, 1, -1)) { + accumulator = callbackFn(accumulator, this[i - 1], i - 1, this); } return accumulator; diff --git a/src/lualib/ArrayReverse.ts b/src/lualib/ArrayReverse.ts index b4a97a2c1..96403753b 100644 --- a/src/lualib/ArrayReverse.ts +++ b/src/lualib/ArrayReverse.ts @@ -1,12 +1,12 @@ -function __TS__ArrayReverse(this: void, arr: any[]): any[] { - let i = 0; - let j = arr.length - 1; +export function __TS__ArrayReverse(this: any[]): any[] { + let i = 1; + let j = this.length; while (i < j) { - const temp = arr[j]; - arr[j] = arr[i]; - arr[i] = temp; - i += 1; - j -= 1; + const temp = this[j - 1]; + this[j - 1] = this[i - 1]; + this[i - 1] = temp; + i++; + j--; } - return arr; + return this; } diff --git a/src/lualib/ArraySetLength.ts b/src/lualib/ArraySetLength.ts index e1bd8ea03..6f4de4b18 100644 --- a/src/lualib/ArraySetLength.ts +++ b/src/lualib/ArraySetLength.ts @@ -1,4 +1,4 @@ -function __TS__ArraySetLength(this: void, arr: T[], length: number): number { +export function __TS__ArraySetLength(this: T[], length: number): number { if ( length < 0 || length !== length || // NaN @@ -8,8 +8,8 @@ function __TS__ArraySetLength(this: void, arr: T[], length: number): number { // non-integer throw `invalid array length: ${length}`; } - for (let i = arr.length - 1; i >= length; --i) { - arr[i] = undefined; + for (const i of $range(length + 1, this.length)) { + this[i - 1] = undefined!; } return length; } diff --git a/src/lualib/ArrayShift.ts b/src/lualib/ArrayShift.ts deleted file mode 100644 index e39d9616b..000000000 --- a/src/lualib/ArrayShift.ts +++ /dev/null @@ -1,3 +0,0 @@ -function __TS__ArrayShift(this: void, arr: T[]): T { - return table.remove(arr, 1); -} diff --git a/src/lualib/ArraySlice.ts b/src/lualib/ArraySlice.ts index d38d96006..e8c357e7f 100644 --- a/src/lualib/ArraySlice.ts +++ b/src/lualib/ArraySlice.ts @@ -1,34 +1,39 @@ // https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.slice -function __TS__ArraySlice(this: void, list: T[], first: number, last: number): T[] { - const len = list.length; +export function __TS__ArraySlice(this: T[], first?: number, last?: number): T[] { + const len = this.length; - const relativeStart = first || 0; - - let k: number; - if (relativeStart < 0) { - k = Math.max(len + relativeStart, 0); + first = first ?? 0; + if (first < 0) { + first = len + first; + if (first < 0) { + first = 0; + } } else { - k = Math.min(relativeStart, len); - } - - let relativeEnd = last; - if (last === undefined) { - relativeEnd = len; + if (first > len) { + first = len; + } } - let final: number; - if (relativeEnd < 0) { - final = Math.max(len + relativeEnd, 0); + last = last ?? len; + if (last < 0) { + last = len + last; + if (last < 0) { + last = 0; + } } else { - final = Math.min(relativeEnd, len); + if (last > len) { + last = len; + } } const out = []; - let n = 0; - while (k < final) { - out[n] = list[k]; - k++; + first++; + last++; + let n = 1; + while (first < last) { + out[n - 1] = this[first - 1]; + first++; n++; } return out; diff --git a/src/lualib/ArraySome.ts b/src/lualib/ArraySome.ts index 9122b1bbc..33ffe69ab 100644 --- a/src/lualib/ArraySome.ts +++ b/src/lualib/ArraySome.ts @@ -1,10 +1,10 @@ -function __TS__ArraySome( - this: void, - arr: T[], - callbackfn: (value: T, index?: number, array?: any[]) => boolean +export function __TS__ArraySome( + this: T[], + callbackfn: (value: T, index?: number, array?: any[]) => boolean, + thisArg?: any ): boolean { - for (let i = 0; i < arr.length; i++) { - if (callbackfn(arr[i], i, arr)) { + for (const i of $range(1, this.length)) { + if (callbackfn.call(thisArg, this[i - 1], i - 1, this)) { return true; } } diff --git a/src/lualib/ArraySort.ts b/src/lualib/ArraySort.ts index 1855c3bb5..2a6495511 100644 --- a/src/lualib/ArraySort.ts +++ b/src/lualib/ArraySort.ts @@ -1,8 +1,8 @@ -function __TS__ArraySort(this: void, arr: T[], compareFn?: (a: T, b: T) => number): T[] { +export function __TS__ArraySort(this: T[], compareFn?: (a: T, b: T) => number): T[] { if (compareFn !== undefined) { - table.sort(arr, (a, b) => compareFn(a, b) < 0); + table.sort(this, (a, b) => compareFn(a, b) < 0); } else { - table.sort(arr); + table.sort(this); } - return arr; + return this; } diff --git a/src/lualib/ArraySplice.ts b/src/lualib/ArraySplice.ts index 0fae685e8..24b5264b2 100644 --- a/src/lualib/ArraySplice.ts +++ b/src/lualib/ArraySplice.ts @@ -1,20 +1,26 @@ -// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.splice -function __TS__ArraySplice(this: void, list: T[], ...args: unknown[]): T[] { - const len = list.length; +import { __TS__CountVarargs } from "./CountVarargs"; - const actualArgumentCount = select("#", ...args); - const start = select(1, ...args) as number; - const deleteCount = select(2, ...args) as number; +// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.splice +export function __TS__ArraySplice(this: T[], ...args: any[]): T[] { + const len = this.length; - let actualStart: number; + const actualArgumentCount = __TS__CountVarargs(...args); + let start = args[0] as number; + const deleteCount = args[1] as number; if (start < 0) { - actualStart = Math.max(len + start, 0); - } else { - actualStart = Math.min(start, len); + start = len + start; + if (start < 0) { + start = 0; + } + } else if (start > len) { + start = len; } - const itemCount = Math.max(actualArgumentCount - 2, 0); + let itemCount = actualArgumentCount - 2; + if (itemCount < 0) { + itemCount = 0; + } let actualDeleteCount: number; @@ -23,56 +29,62 @@ function __TS__ArraySplice(this: void, list: T[], ...args: unknown[]): T[] { actualDeleteCount = 0; } else if (actualArgumentCount === 1) { // ECMA-spec line 6: if number of actual arguments is 1 - actualDeleteCount = len - actualStart; + actualDeleteCount = len - start; } else { - actualDeleteCount = Math.min(Math.max(deleteCount || 0, 0), len - actualStart); + actualDeleteCount = deleteCount ?? 0; + if (actualDeleteCount < 0) { + actualDeleteCount = 0; + } + if (actualDeleteCount > len - start) { + actualDeleteCount = len - start; + } } const out: T[] = []; - for (let k = 0; k < actualDeleteCount; k++) { - const from = actualStart + k; + for (const k of $range(1, actualDeleteCount)) { + const from = start + k; - if (list[from]) { - out[k] = list[from]; + if (this[from - 1] !== undefined) { + out[k - 1] = this[from - 1]; } } if (itemCount < actualDeleteCount) { - for (let k = actualStart; k < len - actualDeleteCount; k++) { + for (const k of $range(start + 1, len - actualDeleteCount)) { const from = k + actualDeleteCount; const to = k + itemCount; - if (list[from]) { - list[to] = list[from]; + if (this[from - 1]) { + this[to - 1] = this[from - 1]; } else { - list[to] = undefined; + this[to - 1] = undefined!; } } - for (let k = len; k > len - actualDeleteCount + itemCount; k--) { - list[k - 1] = undefined; + for (const k of $range(len - actualDeleteCount + itemCount + 1, len)) { + this[k - 1] = undefined!; } } else if (itemCount > actualDeleteCount) { - for (let k = len - actualDeleteCount; k > actualStart; k--) { - const from = k + actualDeleteCount - 1; - const to = k + itemCount - 1; + for (const k of $range(len - actualDeleteCount, start + 1, -1)) { + const from = k + actualDeleteCount; + const to = k + itemCount; - if (list[from]) { - list[to] = list[from]; + if (this[from - 1]) { + this[to - 1] = this[from - 1]; } else { - list[to] = undefined; + this[to - 1] = undefined!; } } } - let j = actualStart; + let j = start + 1; for (const i of $range(3, actualArgumentCount)) { - list[j] = select(i, ...args) as T; + this[j - 1] = args[i - 1]; j++; } - for (let k = list.length - 1; k >= len - actualDeleteCount + itemCount; k--) { - list[k] = undefined; + for (const k of $range(this.length, len - actualDeleteCount + itemCount + 1, -1)) { + this[k - 1] = undefined!; } return out; diff --git a/src/lualib/ArrayToObject.ts b/src/lualib/ArrayToObject.ts index 460a77250..1f9e9778a 100644 --- a/src/lualib/ArrayToObject.ts +++ b/src/lualib/ArrayToObject.ts @@ -1,7 +1,7 @@ -function __TS__ArrayToObject(this: void, array: T[]): Record { +export function __TS__ArrayToObject(this: T[]): Record { const object: Record = {}; - for (let i = 0; i < array.length; i += 1) { - object[i] = array[i]; + for (const i of $range(1, this.length)) { + object[i - 1] = this[i - 1]; } return object; } diff --git a/src/lualib/ArrayToReversed.ts b/src/lualib/ArrayToReversed.ts new file mode 100644 index 000000000..50b58855f --- /dev/null +++ b/src/lualib/ArrayToReversed.ts @@ -0,0 +1,5 @@ +export function __TS__ArrayToReversed(this: T[]): T[] { + const copy = [...this]; + copy.reverse(); + return copy; +} diff --git a/src/lualib/ArrayToSorted.ts b/src/lualib/ArrayToSorted.ts new file mode 100644 index 000000000..47c033d2d --- /dev/null +++ b/src/lualib/ArrayToSorted.ts @@ -0,0 +1,5 @@ +export function __TS__ArrayToSorted(this: T[], compareFn?: (a: T, b: T) => number): T[] { + const copy = [...this]; + copy.sort(compareFn); + return copy; +} diff --git a/src/lualib/ArrayToSpliced.ts b/src/lualib/ArrayToSpliced.ts new file mode 100644 index 000000000..298ed8035 --- /dev/null +++ b/src/lualib/ArrayToSpliced.ts @@ -0,0 +1,5 @@ +export function __TS__ArrayToSpliced(this: T[], start: number, deleteCount: number, ...items: T[]): T[] { + const copy = [...this]; + copy.splice(start, deleteCount, ...items); + return copy; +} diff --git a/src/lualib/ArrayUnshift.ts b/src/lualib/ArrayUnshift.ts index 95dc15b8f..6c628c625 100644 --- a/src/lualib/ArrayUnshift.ts +++ b/src/lualib/ArrayUnshift.ts @@ -1,6 +1,12 @@ -function __TS__ArrayUnshift(this: void, arr: T[], ...items: T[]): number { - for (let i = items.length - 1; i >= 0; --i) { - table.insert(arr, 1, items[i]); +export function __TS__ArrayUnshift(this: T[], ...items: T[]): number { + const numItemsToInsert = items.length; + if (numItemsToInsert === 0) return this.length; + + for (const i of $range(this.length, 1, -1)) { + this[i + numItemsToInsert - 1] = this[i - 1]; } - return arr.length; + for (const i of $range(1, numItemsToInsert)) { + this[i - 1] = items[i - 1]; + } + return this.length; } diff --git a/src/lualib/ArrayWith.ts b/src/lualib/ArrayWith.ts new file mode 100644 index 000000000..90d818a5a --- /dev/null +++ b/src/lualib/ArrayWith.ts @@ -0,0 +1,5 @@ +export function __TS__ArrayWith(this: T[], index: number, value: T): T[] { + const copy = [...this]; + copy[index] = value; + return copy; +} diff --git a/src/lualib/Await.ts b/src/lualib/Await.ts new file mode 100644 index 000000000..7f6a345ee --- /dev/null +++ b/src/lualib/Await.ts @@ -0,0 +1,69 @@ +// The following is a translation of the TypeScript async awaiter which uses generators and yields. +// For Lua we use coroutines instead. +// +// Source: +// +// var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { +// function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } +// return new (P || (P = Promise))(function (resolve, reject) { +// function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } +// function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } +// function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } +// step((generator = generator.apply(thisArg, _arguments || [])).next()); +// }); +// }; +// + +import { __TS__Promise } from "./Promise"; + +const coroutine = _G.coroutine ?? {}; +const cocreate = coroutine.create; +const coresume = coroutine.resume; +const costatus = coroutine.status; +const coyield = coroutine.yield; + +// Be extremely careful editing this function. A single non-tail function call may ruin chained awaits performance +// eslint-disable-next-line @typescript-eslint/promise-function-async +export function __TS__AsyncAwaiter(this: void, generator: (this: void) => void) { + return new Promise((resolve, reject) => { + let resolved = false; + const asyncCoroutine = cocreate(generator); + + function fulfilled(value: unknown): void { + const [success, resultOrError] = coresume(asyncCoroutine, value); + if (success) { + // `step` never throws. Tail call return is important! + return step(resultOrError); + } + // `reject` should never throw. Tail call return is important! + return reject(resultOrError); + } + + function step(this: void, result: unknown): void { + if (resolved) { + return; + } + if (costatus(asyncCoroutine) === "dead") { + // `resolve` never throws. Tail call return is important! + return resolve(result); + } + // We cannot use `then` because we need to avoid calling `coroutine.resume` from inside `pcall` + // `fulfilled` and `reject` should never throw. Tail call return is important! + return __TS__Promise.resolve(result).addCallbacks(fulfilled, reject); + } + + const [success, resultOrError] = coresume(asyncCoroutine, (v: unknown) => { + resolved = true; + return __TS__Promise.resolve(v).addCallbacks(resolve, reject); + }); + if (success) { + return step(resultOrError); + } else { + return reject(resultOrError); + } + }); +} + +export function __TS__Await(this: void, thing: unknown) { + return coyield(thing); +} diff --git a/src/lualib/Class.ts b/src/lualib/Class.ts index d5d7af93d..bdcd7ce4f 100644 --- a/src/lualib/Class.ts +++ b/src/lualib/Class.ts @@ -1,4 +1,4 @@ -function __TS__Class(): LuaClass { +export function __TS__Class(): LuaClass { const c: LuaClass = { prototype: {} }; c.prototype.__index = c.prototype; c.prototype.constructor = c; diff --git a/src/lualib/ClassExtends.ts b/src/lualib/ClassExtends.ts index 0df851629..6075868d7 100644 --- a/src/lualib/ClassExtends.ts +++ b/src/lualib/ClassExtends.ts @@ -1,4 +1,4 @@ -function __TS__ClassExtends(this: void, target: LuaClass, base: LuaClass): void { +export function __TS__ClassExtends(this: void, target: LuaClass, base: LuaClass): void { target.____super = base; // Set base class as a metatable, because descriptors use `getmetatable` to get extended prototype diff --git a/src/lualib/CloneDescriptor.ts b/src/lualib/CloneDescriptor.ts index d74292bab..2afe76914 100644 --- a/src/lualib/CloneDescriptor.ts +++ b/src/lualib/CloneDescriptor.ts @@ -1,4 +1,4 @@ -function __TS__CloneDescriptor( +export function __TS__CloneDescriptor( this: void, { enumerable, configurable, get, set, writable, value }: PropertyDescriptor ): PropertyDescriptor { diff --git a/src/lualib/Decorate.ts b/src/lualib/Decorate.ts index 816721da7..fd65f44e8 100644 --- a/src/lualib/Decorate.ts +++ b/src/lualib/Decorate.ts @@ -1,48 +1,20 @@ /** - * SEE: https://github.com/Microsoft/TypeScript/blob/master/src/compiler/transformers/ts.ts#L3598 + * TypeScript 5.0 decorators */ -type Decorator = ( - target: TTarget, - key?: TKey, - descriptor?: PropertyDescriptor -) => TTarget; -function __TS__Decorate( - this: void, - decorators: Array>, - target: TTarget, - key?: TKey, - desc?: any +import { Decorator } from "./Decorator"; + +export function __TS__Decorate( + this: TClass, + originalValue: TTarget, + decorators: Array>, + context: DecoratorContext ): TTarget { - let result = target; + let result = originalValue; for (let i = decorators.length; i >= 0; i--) { const decorator = decorators[i]; - if (decorator) { - const oldResult = result; - - if (key === undefined) { - result = decorator(result); - } else if (desc === true) { - const value = rawget(target, key); - const descriptor = __TS__ObjectGetOwnPropertyDescriptor(target, key) || { - configurable: true, - writable: true, - value, - }; - const desc = decorator(target, key, descriptor) || descriptor; - const isSimpleValue = desc.configurable === true && desc.writable === true && !desc.get && !desc.set; - if (isSimpleValue) { - rawset(target, key, desc.value); - } else { - __TS__SetDescriptor(target, key, { ...descriptor, ...desc }); - } - } else if (desc === false) { - result = decorator(target, key, desc); - } else { - result = decorator(target, key); - } - - result = result || oldResult; + if (decorator !== undefined) { + result = decorator.call(this, result, context) ?? result; } } diff --git a/src/lualib/DecorateLegacy.ts b/src/lualib/DecorateLegacy.ts new file mode 100644 index 000000000..0369623d3 --- /dev/null +++ b/src/lualib/DecorateLegacy.ts @@ -0,0 +1,54 @@ +/** + * Old-style decorators, activated by enabling the experimentalDecorators flag + */ +import { __TS__ObjectGetOwnPropertyDescriptor } from "./ObjectGetOwnPropertyDescriptor"; +import { __TS__SetDescriptor } from "./SetDescriptor"; + +export type LegacyDecorator = ( + target: TTarget, + key?: TKey, + descriptor?: PropertyDescriptor +) => TTarget; + +export function __TS__DecorateLegacy( + this: void, + decorators: Array>, + target: TTarget, + key?: TKey, + desc?: any +): TTarget { + let result = target; + + for (let i = decorators.length; i >= 0; i--) { + const decorator = decorators[i]; + if (decorator !== undefined) { + const oldResult = result; + + if (key === undefined) { + result = decorator(result); + } else if (desc === true) { + const value = rawget(target, key); + const descriptor = __TS__ObjectGetOwnPropertyDescriptor(target, key) ?? { + configurable: true, + writable: true, + value, + }; + const desc = decorator(target, key, descriptor) || descriptor; + const isSimpleValue = desc.configurable === true && desc.writable === true && !desc.get && !desc.set; + if (isSimpleValue) { + rawset(target, key, desc.value); + } else { + __TS__SetDescriptor(target, key, { ...descriptor, ...desc }); + } + } else if (desc === false) { + result = decorator(target, key, desc); + } else { + result = decorator(target, key); + } + + result = result || oldResult; + } + } + + return result; +} diff --git a/src/lualib/DecorateParam.ts b/src/lualib/DecorateParam.ts index 4e11f3e54..0165294b2 100644 --- a/src/lualib/DecorateParam.ts +++ b/src/lualib/DecorateParam.ts @@ -1,12 +1,14 @@ +import type { LegacyDecorator } from "./DecorateLegacy"; + type ParamDecorator = ( target: TTarget, - key: TKey, + key: TKey | undefined, index: number ) => TTarget; -function __TS__DecorateParam( +export function __TS__DecorateParam( this: void, paramIndex: number, decorator: ParamDecorator -): Decorator { +): LegacyDecorator { return (target: TTarget, key?: TKey) => decorator(target, key, paramIndex); } diff --git a/src/lualib/Decorator.d.ts b/src/lualib/Decorator.d.ts new file mode 100644 index 000000000..d8f84febf --- /dev/null +++ b/src/lualib/Decorator.d.ts @@ -0,0 +1 @@ +export type Decorator = (target: TTarget, context: DecoratorContext) => TTarget; diff --git a/src/lualib/DelegatedYield.ts b/src/lualib/DelegatedYield.ts index ab47d02d8..827dd6326 100644 --- a/src/lualib/DelegatedYield.ts +++ b/src/lualib/DelegatedYield.ts @@ -1,4 +1,6 @@ -function __TS__DelegatedYield(this: void, iterable: string | GeneratorIterator | Iterable | readonly T[]) { +import { GeneratorIterator } from "./GeneratorIterator"; + +export function __TS__DelegatedYield(this: void, iterable: string | GeneratorIterator | Iterable | readonly T[]) { if (typeof iterable === "string") { for (const index of $range(0, iterable.length - 1)) { coroutine.yield(iterable[index]); diff --git a/src/lualib/Delete.ts b/src/lualib/Delete.ts index 079dcb93d..07499f44f 100644 --- a/src/lualib/Delete.ts +++ b/src/lualib/Delete.ts @@ -1,19 +1,17 @@ -function __TS__Delete(this: void, target: any, key: any): boolean { +import { __TS__ObjectGetOwnPropertyDescriptors } from "./ObjectGetOwnPropertyDescriptors"; + +export function __TS__Delete(this: void, target: any, key: any): boolean { const descriptors = __TS__ObjectGetOwnPropertyDescriptors(target); const descriptor = descriptors[key]; if (descriptor) { if (!descriptor.configurable) { - throw `Cannot delete property ${key} of ${target}.`; + throw new TypeError(`Cannot delete property ${key} of ${target}.`); } descriptors[key] = undefined; return true; } - if (target[key] !== undefined) { - target[key] = undefined; - return true; - } - - return false; + target[key] = undefined; + return true; } diff --git a/src/lualib/DescriptorGet.ts b/src/lualib/DescriptorGet.ts new file mode 100644 index 000000000..034a5825a --- /dev/null +++ b/src/lualib/DescriptorGet.ts @@ -0,0 +1,25 @@ +const getmetatable = _G.getmetatable; +const rawget = _G.rawget; + +export function __TS__DescriptorGet(this: any, metatable: any, key: string): void { + while (metatable) { + const rawResult = rawget(metatable, key as any); + if (rawResult !== undefined) { + return rawResult; + } + + const descriptors = rawget(metatable, "_descriptors"); + if (descriptors) { + const descriptor: PropertyDescriptor = descriptors[key]; + if (descriptor !== undefined) { + if (descriptor.get) { + return descriptor.get.call(this); + } + + return descriptor.value; + } + } + + metatable = getmetatable(metatable); + } +} diff --git a/src/lualib/DescriptorSet.ts b/src/lualib/DescriptorSet.ts new file mode 100644 index 000000000..bb50ca4d3 --- /dev/null +++ b/src/lualib/DescriptorSet.ts @@ -0,0 +1,28 @@ +const getmetatable = _G.getmetatable; +const rawget = _G.rawget; +const rawset = _G.rawset; + +export function __TS__DescriptorSet(this: any, metatable: any, key: string, value: any): void { + while (metatable) { + const descriptors = rawget(metatable, "_descriptors"); + if (descriptors) { + const descriptor: PropertyDescriptor = descriptors[key]; + if (descriptor !== undefined) { + if (descriptor.set) { + descriptor.set.call(this, value); + } else { + if (descriptor.writable === false) { + throw `Cannot assign to read only property '${key}' of object '${this}'`; + } + + descriptor.value = value; + } + return; + } + } + + metatable = getmetatable(metatable); + } + + rawset(this, key, value); +} diff --git a/src/lualib/Error.ts b/src/lualib/Error.ts index 197ff816b..ae5deb05b 100644 --- a/src/lualib/Error.ts +++ b/src/lualib/Error.ts @@ -1,9 +1,14 @@ +import { __TS__New } from "./New"; + interface ErrorType { name: string; new (...args: any[]): Error; } -function __TS__GetErrorStack(constructor: () => any): string { +function getErrorStack(constructor: () => any): string | undefined { + // If debug module is not available in this environment, don't bother trying to get stack trace + if (debug === undefined) return undefined; + let level = 1; while (true) { const info = debug.getinfo(level, "f"); @@ -17,14 +22,26 @@ function __TS__GetErrorStack(constructor: () => any): string { } } - return debug.traceback(undefined, level); + if (_VERSION.includes("Lua 5.0")) { + return debug.traceback(`[Level ${level}]`); + // @ts-ignore Fails when compiled with Lua 5.0 types + } else if (_VERSION === "Lua 5.1") { + // Lua 5.1 and LuaJIT have a bug where it's not possible to specify the level without a message. + // @ts-ignore Fails when compiled with Lua 5.0 types + return string.sub(debug.traceback("", level), 2); + } else { + // @ts-ignore Fails when compiled with Lua 5.0 types + return debug.traceback(undefined, level); + } } -function __TS__WrapErrorToString(getDescription: (this: T) => string): (this: T) => string { +function wrapErrorToString(getDescription: (this: T) => string): (this: T) => string { return function (this: Error): string { - const description = getDescription.call(this); + const description = getDescription.call(this as T); const caller = debug.getinfo(3, "f"); - if (_VERSION === "Lua 5.1" || (caller && caller.func !== error)) { + // @ts-ignore Fails when compiled with Lua 5.0 types + const isClassicLua = _VERSION.includes("Lua 5.0"); + if (isClassicLua || (caller && caller.func !== error)) { return description; } else { return `${description}\n${this.stack}`; @@ -32,24 +49,24 @@ function __TS__WrapErrorToString(getDescription: (this: T) => s }; } -function __TS__InitErrorClass(Type: ErrorType, name: string): any { +function initErrorClass(Type: ErrorType, name: string): any { Type.name = name; return setmetatable(Type, { __call: (_self: any, message: string) => new Type(message), }); } -Error = __TS__InitErrorClass( +export const Error: ErrorConstructor = initErrorClass( class implements Error { public name = "Error"; - public stack: string; + public stack?: string; constructor(public message = "") { - this.stack = __TS__GetErrorStack((this.constructor as any).new); + this.stack = getErrorStack(__TS__New as any); const metatable = getmetatable(this); - if (!metatable.__errorToStringPatched) { + if (metatable && !metatable.__errorToStringPatched) { metatable.__errorToStringPatched = true; - metatable.__tostring = __TS__WrapErrorToString(metatable.__tostring); + metatable.__tostring = wrapErrorToString(metatable.__tostring); } } @@ -60,11 +77,17 @@ Error = __TS__InitErrorClass( "Error" ); -for (const errorName of ["RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError"]) { - globalThis[errorName] = __TS__InitErrorClass( +function createErrorClass(name: string) { + return initErrorClass( class extends Error { - public name = errorName; + public name = name; }, - errorName + name ); } + +export const RangeError = createErrorClass("RangeError"); +export const ReferenceError = createErrorClass("ReferenceError"); +export const SyntaxError = createErrorClass("SyntaxError"); +export const TypeError = createErrorClass("TypeError"); +export const URIError = createErrorClass("URIError"); diff --git a/src/lualib/FunctionBind.ts b/src/lualib/FunctionBind.ts index e12fbe37c..f36e9f6e5 100644 --- a/src/lualib/FunctionBind.ts +++ b/src/lualib/FunctionBind.ts @@ -1,13 +1,10 @@ -function __TS__FunctionBind( +export function __TS__FunctionBind( this: void, fn: (this: void, ...argArray: any[]) => any, - thisArg: any, ...boundArgs: any[] ): (...args: any[]) => any { return (...args: any[]) => { - for (let i = 0; i < boundArgs.length; ++i) { - table.insert(args, i + 1, boundArgs[i]); - } - return fn(thisArg, ...args); + args.unshift(...boundArgs); + return fn(...args); }; } diff --git a/src/lualib/Generator.ts b/src/lualib/Generator.ts index 1573f5ec3..c17aab8c7 100644 --- a/src/lualib/Generator.ts +++ b/src/lualib/Generator.ts @@ -1,14 +1,12 @@ -interface GeneratorIterator { - ____coroutine: LuaThread; - [Symbol.iterator](): GeneratorIterator; - next: typeof __TS__GeneratorNext; -} +import { __TS__CountVarargs } from "./CountVarargs"; +import { GeneratorIterator } from "./GeneratorIterator"; +import { __TS__Unpack } from "./Unpack"; -function __TS__GeneratorIterator(this: GeneratorIterator) { +function generatorIterator(this: GeneratorIterator) { return this; } -function __TS__GeneratorNext(this: GeneratorIterator, ...args: any[]) { +function generatorNext(this: GeneratorIterator, ...args: any[]) { const co = this.____coroutine; if (coroutine.status(co) === "dead") return { done: true }; @@ -18,14 +16,14 @@ function __TS__GeneratorNext(this: GeneratorIterator, ...args: any[]) { return { value, done: coroutine.status(co) === "dead" }; } -function __TS__Generator(this: void, fn: (this: void, ...args: any[]) => any) { +export function __TS__Generator(this: void, fn: (this: void, ...args: any[]) => any) { return function (this: void, ...args: any[]): GeneratorIterator { - const argsLength = select("#", ...args); + const argsLength = __TS__CountVarargs(...args); return { // Using explicit this there, since we don't pass arguments after the first nil and context is likely to be nil - ____coroutine: coroutine.create(() => fn((unpack || table.unpack)(args, 1, argsLength))), - [Symbol.iterator]: __TS__GeneratorIterator, - next: __TS__GeneratorNext, + ____coroutine: coroutine.create(() => fn(...__TS__Unpack(args, 1, argsLength))), + [Symbol.iterator]: generatorIterator, + next: generatorNext, }; }; } diff --git a/src/lualib/GeneratorIterator.d.ts b/src/lualib/GeneratorIterator.d.ts new file mode 100644 index 000000000..2509046b5 --- /dev/null +++ b/src/lualib/GeneratorIterator.d.ts @@ -0,0 +1,5 @@ +export interface GeneratorIterator { + ____coroutine: LuaThread; + [Symbol.iterator](): GeneratorIterator; + next: typeof generatorNext; +} diff --git a/src/lualib/InstanceOf.ts b/src/lualib/InstanceOf.ts index a4d80c881..317c0b794 100644 --- a/src/lualib/InstanceOf.ts +++ b/src/lualib/InstanceOf.ts @@ -1,11 +1,11 @@ -function __TS__InstanceOf(this: void, obj: LuaClassInstance, classTbl: LuaClass): boolean { +export function __TS__InstanceOf(this: void, obj: LuaClassInstance, classTbl: LuaClass): boolean { if (typeof classTbl !== "object") { throw "Right-hand side of 'instanceof' is not an object"; } if (classTbl[Symbol.hasInstance] !== undefined) { // eslint-disable-next-line no-implicit-coercion - return !!classTbl[Symbol.hasInstance](obj); + return !!classTbl[Symbol.hasInstance]!(obj); } if (typeof obj === "object") { @@ -14,7 +14,7 @@ function __TS__InstanceOf(this: void, obj: LuaClassInstance, classTbl: LuaClass) if (luaClass === classTbl) { return true; } - luaClass = luaClass.____super; + luaClass = luaClass.____super!; } } return false; diff --git a/src/lualib/InstanceOfObject.ts b/src/lualib/InstanceOfObject.ts index 681e243c5..28e32150e 100644 --- a/src/lualib/InstanceOfObject.ts +++ b/src/lualib/InstanceOfObject.ts @@ -1,4 +1,4 @@ -function __TS__InstanceOfObject(this: void, value: unknown): boolean { +export function __TS__InstanceOfObject(this: void, value: unknown): boolean { const valueType = type(value); return valueType === "table" || valueType === "function"; } diff --git a/src/lualib/Iterator.ts b/src/lualib/Iterator.ts index d6112cd88..6991ea888 100644 --- a/src/lualib/Iterator.ts +++ b/src/lualib/Iterator.ts @@ -1,40 +1,38 @@ -/** @tupleReturn */ -function __TS__IteratorGeneratorStep(this: GeneratorIterator): [true, any] | [] { +import { GeneratorIterator } from "./GeneratorIterator"; + +function iteratorGeneratorStep(this: GeneratorIterator): LuaMultiReturn<[true, any] | []> { const co = this.____coroutine; const [status, value] = coroutine.resume(co); if (!status) throw value; - if (coroutine.status(co) === "dead") return []; - return [true, value]; + if (coroutine.status(co) === "dead") return $multi(); + return $multi(true, value); } -/** @tupleReturn */ -function __TS__IteratorIteratorStep(this: Iterator): [true, T] | [] { +function iteratorIteratorStep(this: Iterator): LuaMultiReturn<[true, T] | []> { const result = this.next(); - if (result.done) return []; - return [true, result.value]; + if (result.done) return $multi(); + return $multi(true, result.value); } -/** @tupleReturn */ -function __TS__IteratorStringStep(this: string, index: number): [number, string] | [] { +function iteratorStringStep(this: string, index: number): LuaMultiReturn<[number, string] | []> { index += 1; - if (index > this.length) return []; - return [index, string.sub(this, index, index)]; + if (index > this.length) return $multi(); + return $multi(index, string.sub(this, index, index)); } -/** @tupleReturn */ -function __TS__Iterator( +export function __TS__Iterator( this: void, iterable: string | GeneratorIterator | Iterable | readonly T[] -): [(...args: any[]) => [any, any] | [], ...any[]] | LuaIterable> { +): LuaMultiReturn<[(...args: any[]) => [any, any] | [], ...any[]]> | LuaIterable> { if (typeof iterable === "string") { - return [__TS__IteratorStringStep, iterable, 0]; + return $multi(iteratorStringStep, iterable, 0); } else if ("____coroutine" in iterable) { - return [__TS__IteratorGeneratorStep, iterable]; + return $multi(iteratorGeneratorStep, iterable); } else if (iterable[Symbol.iterator]) { const iterator = iterable[Symbol.iterator](); - return [__TS__IteratorIteratorStep, iterator]; + return $multi(iteratorIteratorStep, iterator); } else { return ipairs(iterable as readonly T[]); } diff --git a/src/lualib/LuaIteratorSpread.ts b/src/lualib/LuaIteratorSpread.ts new file mode 100644 index 000000000..b846bc535 --- /dev/null +++ b/src/lualib/LuaIteratorSpread.ts @@ -0,0 +1,13 @@ +export function __TS__LuaIteratorSpread( + this: (this: void, state: TState, key: TKey) => LuaMultiReturn<[TKey, TValue]>, + state: TState, + firstKey: TKey +): LuaMultiReturn> { + const results = []; + let [key, value] = this(state, firstKey); + while (key) { + results.push([key, value]); + [key, value] = this(state, key); + } + return $multi(...results) as LuaMultiReturn>; +} diff --git a/src/lualib/Map.ts b/src/lualib/Map.ts index e442b6132..c2bcb43a4 100644 --- a/src/lualib/Map.ts +++ b/src/lualib/Map.ts @@ -1,4 +1,4 @@ -Map = class Map { +export class Map { public static [Symbol.species] = Map; public [Symbol.toStringTag] = "Map"; @@ -52,24 +52,24 @@ Map = class Map { // Do order bookkeeping const next = this.nextKey.get(key); const previous = this.previousKey.get(key); - if (next && previous) { + if (next !== undefined && previous !== undefined) { this.nextKey.set(previous, next); this.previousKey.set(next, previous); - } else if (next) { + } else if (next !== undefined) { this.firstKey = next; - this.previousKey.set(next, undefined); - } else if (previous) { + this.previousKey.set(next, undefined!); + } else if (previous !== undefined) { this.lastKey = previous; - this.nextKey.set(previous, undefined); + this.nextKey.set(previous, undefined!); } else { this.firstKey = undefined; this.lastKey = undefined; } - this.nextKey.set(key, undefined); - this.previousKey.set(key, undefined); + this.nextKey.set(key, undefined!); + this.previousKey.set(key, undefined!); } - this.items.set(key, undefined); + this.items.set(key, undefined!); return contains; } @@ -100,8 +100,8 @@ Map = class Map { this.firstKey = key; this.lastKey = key; } else if (isNewValue) { - this.nextKey.set(this.lastKey, key); - this.previousKey.set(key, this.lastKey); + this.nextKey.set(this.lastKey!, key); + this.previousKey.set(key, this.lastKey!); this.lastKey = key; } @@ -113,47 +113,65 @@ Map = class Map { } public entries(): IterableIterator<[K, V]> { + const getFirstKey = () => this.firstKey; const { items, nextKey } = this; - let key = this.firstKey; + let key: K | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator<[K, V]> { return this; }, next(): IteratorResult<[K, V]> { - const result = { done: !key, value: [key, items.get(key)] as [K, V] }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: [key!, items.get(key!)] as [K, V] }; }, }; } public keys(): IterableIterator { + const getFirstKey = () => this.firstKey; const nextKey = this.nextKey; - let key = this.firstKey; + let key: K | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator { return this; }, next(): IteratorResult { - const result = { done: !key, value: key }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: key! }; }, }; } public values(): IterableIterator { + const getFirstKey = () => this.firstKey; const { items, nextKey } = this; - let key = this.firstKey; + let key: K | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator { return this; }, next(): IteratorResult { - const result = { done: !key, value: items.get(key) }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: items.get(key!) }; }, }; } -}; +} diff --git a/src/lualib/MapGroupBy.ts b/src/lualib/MapGroupBy.ts new file mode 100644 index 000000000..d3e079192 --- /dev/null +++ b/src/lualib/MapGroupBy.ts @@ -0,0 +1,22 @@ +export function __TS__MapGroupBy( + this: void, + items: Iterable, + keySelector: (item: T, index: number) => K +): Map { + const result = new Map(); + + let i = 0; + for (const item of items) { + const key = keySelector(item, i); + + if (result.has(key)) { + result.get(key)!.push(item); + } else { + result.set(key, [item]); + } + + i++; + } + + return result; +} diff --git a/src/lualib/MathAtan2.ts b/src/lualib/MathAtan2.ts index fdf322664..185cfe678 100644 --- a/src/lualib/MathAtan2.ts +++ b/src/lualib/MathAtan2.ts @@ -1 +1 @@ -const __TS__MathAtan2 = math.atan2 || math.atan; +export const __TS__MathAtan2 = math.atan2 || math.atan; diff --git a/src/lualib/MathSign.ts b/src/lualib/MathSign.ts new file mode 100644 index 000000000..629895a11 --- /dev/null +++ b/src/lualib/MathSign.ts @@ -0,0 +1,15 @@ +// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.sign + +import { __TS__NumberIsNaN } from "./NumberIsNaN"; + +export function __TS__MathSign(this: void, val: number) { + if (__TS__NumberIsNaN(val) || val === 0) { + return val; + } + + if (val < 0) { + return -1; + } + + return 1; +} diff --git a/src/lualib/MathTrunc.ts b/src/lualib/MathTrunc.ts new file mode 100644 index 000000000..f244c2147 --- /dev/null +++ b/src/lualib/MathTrunc.ts @@ -0,0 +1,10 @@ +// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-math.trunc + +import { __TS__NumberIsFinite } from "./NumberIsFinite"; +export function __TS__MathTrunc(this: void, val: number) { + if (!__TS__NumberIsFinite(val) || val === 0) { + return val; + } + + return val > 0 ? math.floor(val) : math.ceil(val); +} diff --git a/src/lualib/New.ts b/src/lualib/New.ts index 8b33ec837..b54890917 100644 --- a/src/lualib/New.ts +++ b/src/lualib/New.ts @@ -1,4 +1,4 @@ -function __TS__New(this: void, target: LuaClass, ...args: any[]): any { +export function __TS__New(this: void, target: LuaClass, ...args: any[]): any { const instance: any = setmetatable({}, target.prototype); instance.____constructor(...args); return instance; diff --git a/src/lualib/Number.ts b/src/lualib/Number.ts index 0b19a1600..b258b48f6 100644 --- a/src/lualib/Number.ts +++ b/src/lualib/Number.ts @@ -1,4 +1,4 @@ -function __TS__Number(this: void, value: unknown): number { +export function __TS__Number(this: void, value: unknown): number { const valueType = type(value); if (valueType === "number") { return value as number; diff --git a/src/lualib/NumberIsFinite.ts b/src/lualib/NumberIsFinite.ts index 98df30790..f225b8c5c 100644 --- a/src/lualib/NumberIsFinite.ts +++ b/src/lualib/NumberIsFinite.ts @@ -1,3 +1,3 @@ -function __TS__NumberIsFinite(this: void, value: unknown): boolean { +export function __TS__NumberIsFinite(this: void, value: unknown): boolean { return typeof value === "number" && value === value && value !== Infinity && value !== -Infinity; } diff --git a/src/lualib/NumberIsInteger.ts b/src/lualib/NumberIsInteger.ts new file mode 100644 index 000000000..275fcae03 --- /dev/null +++ b/src/lualib/NumberIsInteger.ts @@ -0,0 +1,6 @@ +import { __TS__NumberIsFinite } from "./NumberIsFinite"; + +/// https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.isinteger +export function __TS__NumberIsInteger(this: void, value: unknown): boolean { + return __TS__NumberIsFinite(value) && math.floor(value as number) === (value as number); +} diff --git a/src/lualib/NumberIsNaN.ts b/src/lualib/NumberIsNaN.ts index b040f5e5b..e57631cc1 100644 --- a/src/lualib/NumberIsNaN.ts +++ b/src/lualib/NumberIsNaN.ts @@ -1,3 +1,3 @@ -function __TS__NumberIsNaN(this: void, value: unknown): boolean { +export function __TS__NumberIsNaN(this: void, value: unknown): boolean { return value !== value; } diff --git a/src/lualib/NumberToFixed.ts b/src/lualib/NumberToFixed.ts new file mode 100644 index 000000000..355da13f0 --- /dev/null +++ b/src/lualib/NumberToFixed.ts @@ -0,0 +1,14 @@ +/// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-number.prototype.tofixed +export function __TS__NumberToFixed(this: number, fractionDigits?: number): string { + if (Math.abs(this) >= 1e21 || this !== this) { + return this.toString(); + } + const f = Math.floor(fractionDigits ?? 0); + // reduced to 99 as string.format only supports 2-digit numbers + if (f < 0 || f > 99) { + throw "toFixed() digits argument must be between 0 and 99"; + } + // throws "invalid format (width or precision too long)" if strlen > 99 + // if (f < 80) return fmt; else try {return fmt} catch(_) { throw "toFixed() digits argument..." } + return string.format(`%.${f}f`, this); +} diff --git a/src/lualib/NumberToString.ts b/src/lualib/NumberToString.ts index 52da58d7c..6cdbaadc3 100644 --- a/src/lualib/NumberToString.ts +++ b/src/lualib/NumberToString.ts @@ -1,7 +1,9 @@ -const ____radixChars = "0123456789abcdefghijklmnopqrstuvwxyz"; +import { __TS__MathModf } from "./MathModf"; + +const radixChars = "0123456789abcdefghijklmnopqrstuvwxyz"; // https://www.ecma-international.org/ecma-262/10.0/index.html#sec-number.prototype.tostring -function __TS__NumberToString(this: number, radix?: number): string { +export function __TS__NumberToString(this: number, radix?: number): string { if (radix === undefined || radix === 10 || this === Infinity || this === -Infinity || this !== this) { return this.toString(); } @@ -11,7 +13,7 @@ function __TS__NumberToString(this: number, radix?: number): string { throw "toString() radix argument must be between 2 and 36"; } - let [integer, fraction] = math.modf(Math.abs(this)); + let [integer, fraction] = __TS__MathModf(Math.abs(this)); let result = ""; if (radix === 8) { @@ -20,7 +22,7 @@ function __TS__NumberToString(this: number, radix?: number): string { result = string.format("%x", integer); } else { do { - result = ____radixChars[integer % radix] + result; + result = radixChars[integer % radix] + result; integer = Math.floor(integer / radix); } while (integer !== 0); } @@ -33,7 +35,7 @@ function __TS__NumberToString(this: number, radix?: number): string { fraction *= radix; delta *= radix; const digit = Math.floor(fraction); - result += ____radixChars[digit]; + result += radixChars[digit]; fraction -= digit; // TODO: Round to even } while (fraction >= delta); diff --git a/src/lualib/ObjectAssign.ts b/src/lualib/ObjectAssign.ts index bcf521c07..7d0a3a9b1 100644 --- a/src/lualib/ObjectAssign.ts +++ b/src/lualib/ObjectAssign.ts @@ -1,15 +1,13 @@ // https://tc39.github.io/ecma262/#sec-object.assign -// eslint-disable-next-line @typescript-eslint/ban-types -function __TS__ObjectAssign(this: void, to: T, ...sources: object[]): T { - if (to === undefined) { - return to; - } - - for (const source of sources) { - for (const key in source) { - to[key] = source[key]; +export function __TS__ObjectAssign(this: void, target: T, ...sources: T[]): T { + for (const i of $range(1, sources.length)) { + const source = sources[i - 1]; + if (type(source) === "table") { + for (const key in source) { + target[key] = source[key]; + } } } - return to; + return target; } diff --git a/src/lualib/ObjectDefineProperty.ts b/src/lualib/ObjectDefineProperty.ts index e9aa599d5..c0dc40a1f 100644 --- a/src/lualib/ObjectDefineProperty.ts +++ b/src/lualib/ObjectDefineProperty.ts @@ -1,5 +1,13 @@ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty -function __TS__ObjectDefineProperty(this: void, target: T, key: any, desc: PropertyDescriptor): T { + +import { __TS__SetDescriptor } from "./SetDescriptor"; + +export function __TS__ObjectDefineProperty( + this: void, + target: T, + key: any, + desc: PropertyDescriptor +): T { const luaKey = typeof key === "number" ? key + 1 : key; const value = rawget(target, luaKey); @@ -17,9 +25,9 @@ function __TS__ObjectDefineProperty(this: void, target: T, key: any, desc: Pr descriptor = { set: desc.set, get: desc.get, - configurable: desc.configurable !== undefined ? desc.configurable : valueExists, - enumerable: desc.enumerable !== undefined ? desc.enumerable : valueExists, - writable: desc.writable !== undefined ? desc.writable : valueExists, + configurable: desc.configurable ?? valueExists, + enumerable: desc.enumerable ?? valueExists, + writable: desc.writable ?? valueExists, value: desc.value !== undefined ? desc.value : value, }; } diff --git a/src/lualib/ObjectEntries.ts b/src/lualib/ObjectEntries.ts index f491bd039..20fde96ad 100644 --- a/src/lualib/ObjectEntries.ts +++ b/src/lualib/ObjectEntries.ts @@ -1,7 +1,12 @@ -function __TS__ObjectEntries(this: void, obj: any): Array { - const result = []; +export function __TS__ObjectEntries( + this: void, + obj: Record +): Array<[TKey, TValue]> { + const result: Array<[TKey, TValue]> = []; + let len = 0; for (const key in obj) { - result[result.length] = [key, obj[key]]; + len++; + result[len - 1] = [key, obj[key]]; } return result; } diff --git a/src/lualib/ObjectFromEntries.ts b/src/lualib/ObjectFromEntries.ts index efdf7dd90..88c224cf7 100644 --- a/src/lualib/ObjectFromEntries.ts +++ b/src/lualib/ObjectFromEntries.ts @@ -1,4 +1,4 @@ -function __TS__ObjectFromEntries( +export function __TS__ObjectFromEntries( this: void, entries: ReadonlyArray<[string, T]> | Iterable<[string, T]> ): Record { diff --git a/src/lualib/ObjectGetOwnPropertyDescriptor.ts b/src/lualib/ObjectGetOwnPropertyDescriptor.ts index 84dab33df..975de6712 100644 --- a/src/lualib/ObjectGetOwnPropertyDescriptor.ts +++ b/src/lualib/ObjectGetOwnPropertyDescriptor.ts @@ -1,6 +1,10 @@ -function __TS__ObjectGetOwnPropertyDescriptor(this: void, object: any, key: any): PropertyDescriptor | undefined { +export function __TS__ObjectGetOwnPropertyDescriptor( + this: void, + object: any, + key: any +): PropertyDescriptor | undefined { const metatable = getmetatable(object); if (!metatable) return; if (!rawget(metatable, "_descriptors")) return; - return rawget(metatable, "_descriptors")[key]; + return rawget(metatable, "_descriptors")![key]; } diff --git a/src/lualib/ObjectGetOwnPropertyDescriptors.ts b/src/lualib/ObjectGetOwnPropertyDescriptors.ts index 04aee8b51..69d23af06 100644 --- a/src/lualib/ObjectGetOwnPropertyDescriptors.ts +++ b/src/lualib/ObjectGetOwnPropertyDescriptors.ts @@ -1,5 +1,8 @@ -function __TS__ObjectGetOwnPropertyDescriptors(this: void, object: any): Record { +export function __TS__ObjectGetOwnPropertyDescriptors( + this: void, + object: any +): Record { const metatable = getmetatable(object); if (!metatable) return {}; - return rawget(metatable, "_descriptors") || {}; + return rawget(metatable, "_descriptors") ?? {}; } diff --git a/src/lualib/ObjectGroupBy.ts b/src/lualib/ObjectGroupBy.ts new file mode 100644 index 000000000..6328ad2aa --- /dev/null +++ b/src/lualib/ObjectGroupBy.ts @@ -0,0 +1,22 @@ +export function __TS__ObjectGroupBy( + this: void, + items: Iterable, + keySelector: (item: T, index: number) => K +): Partial> { + const result: Partial> = {}; + + let i = 0; + for (const item of items) { + const key = keySelector(item, i); + + if (key in result) { + result[key]!.push(item); + } else { + result[key] = [item]; + } + + i++; + } + + return result; +} diff --git a/src/lualib/ObjectKeys.ts b/src/lualib/ObjectKeys.ts index 8163a620a..c7a0c0208 100644 --- a/src/lualib/ObjectKeys.ts +++ b/src/lualib/ObjectKeys.ts @@ -1,7 +1,9 @@ -function __TS__ObjectKeys(this: void, obj: any): Array { +export function __TS__ObjectKeys(this: void, obj: any): Array { const result = []; + let len = 0; for (const key in obj) { - result[result.length] = key; + len++; + result[len - 1] = key; } return result; } diff --git a/src/lualib/ObjectRest.ts b/src/lualib/ObjectRest.ts index 7da14b2fb..276135ce5 100644 --- a/src/lualib/ObjectRest.ts +++ b/src/lualib/ObjectRest.ts @@ -1,4 +1,4 @@ -function __TS__ObjectRest( +export function __TS__ObjectRest( this: void, target: Record, usedProperties: Partial> diff --git a/src/lualib/ObjectValues.ts b/src/lualib/ObjectValues.ts index e850f6a31..925a61ab3 100644 --- a/src/lualib/ObjectValues.ts +++ b/src/lualib/ObjectValues.ts @@ -1,7 +1,9 @@ -function __TS__ObjectValues(this: void, obj: any): Array { +export function __TS__ObjectValues(this: void, obj: any): Array { const result = []; + let len = 0; for (const key in obj) { - result[result.length] = obj[key]; + len++; + result[len - 1] = obj[key]; } return result; } diff --git a/src/lualib/OptionalChainAccess.ts b/src/lualib/OptionalChainAccess.ts deleted file mode 100644 index 7924aa282..000000000 --- a/src/lualib/OptionalChainAccess.ts +++ /dev/null @@ -1,10 +0,0 @@ -function __TS__OptionalChainAccess( - this: void, - table: Record, - key: TKey -): TReturn | undefined { - if (table) { - return table[key]; - } - return undefined; -} diff --git a/src/lualib/OptionalFunctionCall.ts b/src/lualib/OptionalFunctionCall.ts deleted file mode 100644 index 85b52a047..000000000 --- a/src/lualib/OptionalFunctionCall.ts +++ /dev/null @@ -1,10 +0,0 @@ -function __TS__OptionalFunctionCall( - this: void, - f: (this: void, ...args: [...TArgs]) => TReturn, - ...args: [...TArgs] -): TReturn | undefined { - if (f) { - return f(...args); - } - return undefined; -} diff --git a/src/lualib/OptionalMethodCall.ts b/src/lualib/OptionalMethodCall.ts deleted file mode 100644 index 8829e4a4d..000000000 --- a/src/lualib/OptionalMethodCall.ts +++ /dev/null @@ -1,14 +0,0 @@ -function __TS__OptionalMethodCall( - this: void, - table: Record TReturn>, - methodName: string, - ...args: [...TArgs] -): TReturn | undefined { - if (table) { - const method = table[methodName]; - if (method) { - return method.call(table, ...args); - } - } - return undefined; -} diff --git a/src/lualib/ParseFloat.ts b/src/lualib/ParseFloat.ts index 1cd069111..7720acb6b 100644 --- a/src/lualib/ParseFloat.ts +++ b/src/lualib/ParseFloat.ts @@ -1,11 +1,13 @@ -function __TS__ParseFloat(this: void, numberString: string): number { +import { __TS__Match } from "./Match"; + +export function __TS__ParseFloat(this: void, numberString: string): number { // Check if string is infinity - const infinityMatch = string.match(numberString, "^%s*(-?Infinity)"); - if (infinityMatch) { + const [infinityMatch] = __TS__Match(numberString, "^%s*(-?Infinity)"); + if (infinityMatch !== undefined) { // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with return infinityMatch[0] === "-" ? -Infinity : Infinity; } - const number = tonumber(string.match(numberString, "^%s*(-?%d+%.?%d*)")); + const number = tonumber(__TS__Match(numberString, "^%s*(-?%d+%.?%d*)")[0]); return number ?? NaN; } diff --git a/src/lualib/ParseInt.ts b/src/lualib/ParseInt.ts index b1d5710a0..c27d62662 100644 --- a/src/lualib/ParseInt.ts +++ b/src/lualib/ParseInt.ts @@ -1,15 +1,17 @@ -const __TS__parseInt_base_pattern = "0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTvVwWxXyYzZ"; +import { __TS__Match } from "./Match"; -function __TS__ParseInt(this: void, numberString: string, base?: number): number { +const parseIntBasePattern = "0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTvVwWxXyYzZ"; + +export function __TS__ParseInt(this: void, numberString: string, base?: number): number { // Check which base to use if none specified if (base === undefined) { base = 10; - const hexMatch = string.match(numberString, "^%s*-?0[xX]"); - if (hexMatch) { + const [hexMatch] = __TS__Match(numberString, "^%s*-?0[xX]"); + if (hexMatch !== undefined) { base = 16; - numberString = string.match(hexMatch, "-") - ? "-" + numberString.substr(hexMatch.length) - : numberString.substr(hexMatch.length); + numberString = __TS__Match(hexMatch, "-")[0] + ? "-" + numberString.substring(hexMatch.length) + : numberString.substring(hexMatch.length); } } @@ -20,13 +22,11 @@ function __TS__ParseInt(this: void, numberString: string, base?: number): number // Calculate string match pattern to use const allowedDigits = - base <= 10 - ? __TS__parseInt_base_pattern.substring(0, base) - : __TS__parseInt_base_pattern.substr(0, 10 + 2 * (base - 10)); + base <= 10 ? parseIntBasePattern.substring(0, base) : parseIntBasePattern.substring(0, 10 + 2 * (base - 10)); const pattern = `^%s*(-?[${allowedDigits}]*)`; // Try to parse with Lua tonumber - const number = tonumber(string.match(numberString, pattern), base); + const number = tonumber(__TS__Match(numberString, pattern)[0], base); if (number === undefined) { return NaN; diff --git a/src/lualib/Promise.ts b/src/lualib/Promise.ts new file mode 100644 index 000000000..e8121f1b3 --- /dev/null +++ b/src/lualib/Promise.ts @@ -0,0 +1,236 @@ +/* eslint-disable @typescript-eslint/promise-function-async */ + +// Promises implemented based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise +// and https://promisesaplus.com/ + +export const enum PromiseState { + Pending, + Fulfilled, + Rejected, +} + +type PromiseExecutor = ConstructorParameters>[0]; +type PromiseResolve = Parameters>[0]; +type PromiseReject = Parameters>[1]; +type PromiseResolveCallback = (value: TValue) => TResult | PromiseLike; +type PromiseRejectCallback = (reason: any) => TResult | PromiseLike; + +function makeDeferredPromiseFactory(this: void) { + let resolve: PromiseResolve; + let reject: PromiseReject; + const executor: PromiseExecutor = (res, rej) => { + resolve = res; + reject = rej; + }; + return function (this: void) { + const promise = new Promise(executor); + return $multi(promise, resolve, reject); + }; +} + +const makeDeferredPromise = makeDeferredPromiseFactory(); + +function isPromiseLike(this: void, value: unknown): value is PromiseLike { + return value instanceof __TS__Promise; +} + +function doNothing(): void {} + +const pcall = _G.pcall; + +export class __TS__Promise implements Promise { + public state = PromiseState.Pending; + public value?: T; + public rejectionReason?: any; + + private fulfilledCallbacks: Array> = []; + private rejectedCallbacks: PromiseReject[] = []; + + // @ts-ignore + public [Symbol.toStringTag]: string; // Required to implement interface, no output Lua + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve + public static resolve(this: void, value: T | PromiseLike): __TS__Promise> { + if (value instanceof __TS__Promise) { + return value; + } + // Create and return a promise instance that is already resolved + const promise = new __TS__Promise>(doNothing); + promise.state = PromiseState.Fulfilled; + promise.value = value as Awaited; + return promise; + } + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject + public static reject(this: void, reason?: any): __TS__Promise { + // Create and return a promise instance that is already rejected + const promise = new __TS__Promise(doNothing); + promise.state = PromiseState.Rejected; + promise.rejectionReason = reason; + return promise; + } + + constructor(executor: PromiseExecutor) { + // Avoid unnecessary local functions allocations by using `pcall` explicitly + const [success, error] = pcall( + executor, + undefined, + v => this.resolve(v), + err => this.reject(err) + ); + if (!success) { + // When a promise executor throws, the promise should be rejected with the thrown object as reason + this.reject(error); + } + } + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then + public then( + onFulfilled?: PromiseResolveCallback, + onRejected?: PromiseRejectCallback + ): Promise { + const [promise, resolve, reject] = makeDeferredPromise(); + + this.addCallbacks( + // We always want to resolve our child promise if this promise is resolved, even if we have no handler + onFulfilled ? this.createPromiseResolvingCallback(onFulfilled, resolve, reject) : resolve, + // We always want to reject our child promise if this promise is rejected, even if we have no handler + onRejected ? this.createPromiseResolvingCallback(onRejected, resolve, reject) : reject + ); + + return promise as Promise; + } + + // Both callbacks should never throw! + public addCallbacks(fulfilledCallback: (value: T) => void, rejectedCallback: (rejectionReason: any) => void): void { + if (this.state === PromiseState.Fulfilled) { + // If promise already resolved, immediately call callback. We don't even need to store rejected callback + // Tail call return is important! + return fulfilledCallback(this.value!); + } + if (this.state === PromiseState.Rejected) { + // Similar thing + return rejectedCallback(this.rejectionReason); + } + + this.fulfilledCallbacks.push(fulfilledCallback as any); + this.rejectedCallbacks.push(rejectedCallback); + } + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch + public catch(onRejected?: (reason: any) => TResult | PromiseLike): Promise { + return this.then(undefined, onRejected); + } + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally + // Delegates to .then() so that a new Promise is returned (per ES spec §27.2.5.3) + // and the original fulfillment value / rejection reason is preserved. + // reference: https://github.com/tc39/proposal-promise-finally/blob/fd934c0b42d59bf8d9446e737ba14d50a9067216/polyfill.js#L34-L41 + public finally(onFinally?: () => void): Promise { + if (typeof onFinally !== "function") { + return this.then(onFinally, onFinally); + } + return this.then( + x => new __TS__Promise(resolve => resolve(onFinally())).then(() => x), + e => + new __TS__Promise(resolve => resolve(onFinally())).then(() => { + throw e; + }) + ); + } + + private resolve(value: T | PromiseLike): void { + if (isPromiseLike(value)) { + // Tail call return is important! + return (value as __TS__Promise).addCallbacks( + v => this.resolve(v), + err => this.reject(err) + ); + } + + // Resolve this promise, if it is still pending. This function is passed to the constructor function. + if (this.state === PromiseState.Pending) { + this.state = PromiseState.Fulfilled; + this.value = value; + + // Tail call return is important! + return this.invokeCallbacks(this.fulfilledCallbacks, value); + } + } + + private reject(reason: any): void { + // Reject this promise, if it is still pending. This function is passed to the constructor function. + if (this.state === PromiseState.Pending) { + this.state = PromiseState.Rejected; + this.rejectionReason = reason; + + // Tail call return is important! + return this.invokeCallbacks(this.rejectedCallbacks, reason); + } + } + + private invokeCallbacks(callbacks: ReadonlyArray<(value: T) => void>, value: T): void { + const callbacksLength = callbacks.length; + + if (callbacksLength !== 0) { + for (const i of $range(1, callbacksLength - 1)) { + callbacks[i - 1](value); + } + // Tail call optimization for a common case. + return callbacks[callbacksLength - 1](value); + } + } + + private createPromiseResolvingCallback( + f: PromiseResolveCallback | PromiseRejectCallback, + resolve: (data: TResult1 | TResult2) => void, + reject: (reason: any) => void + ) { + return (value: T): void => { + const [success, resultOrError] = pcall< + undefined, + [T], + TResult1 | PromiseLike | TResult2 | PromiseLike + >(f, undefined, value); + if (!success) { + // Tail call return is important! + return reject(resultOrError); + } + // Tail call return is important! + return this.handleCallbackValue(resultOrError, resolve, reject); + }; + } + + private handleCallbackValue( + value: TResult | PromiseLike, + resolve: (data: TResult1 | TResult2) => void, + reject: (reason: any) => void + ): void { + if (isPromiseLike(value)) { + const nextpromise = value as __TS__Promise; + if (nextpromise.state === PromiseState.Fulfilled) { + // If a handler function returns an already fulfilled promise, + // the promise returned by then gets fulfilled with that promise's value. + // Tail call return is important! + return resolve(nextpromise.value!); + } else if (nextpromise.state === PromiseState.Rejected) { + // If a handler function returns an already rejected promise, + // the promise returned by then gets fulfilled with that promise's value. + // Tail call return is important! + return reject(nextpromise.rejectionReason); + } else { + // If a handler function returns another pending promise object, the resolution/rejection + // of the promise returned by then will be subsequent to the resolution/rejection of + // the promise returned by the handler. + // We cannot use `then` because we need to do tail call, and `then` returns a Promise. + // `resolve` and `reject` should never throw. + return nextpromise.addCallbacks(resolve, reject); + } + } else { + // If a handler returns a value, the promise returned by then gets resolved with the returned value as its value + // If a handler doesn't return anything, the promise returned by then gets resolved with undefined + // Tail call return is important! + return resolve(value); + } + } +} diff --git a/src/lualib/PromiseAll.ts b/src/lualib/PromiseAll.ts new file mode 100644 index 000000000..c9263b645 --- /dev/null +++ b/src/lualib/PromiseAll.ts @@ -0,0 +1,56 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all +import { __TS__Promise, PromiseState } from "./Promise"; + +// eslint-disable-next-line @typescript-eslint/promise-function-async +export function __TS__PromiseAll(this: void, iterable: Iterable>): Promise { + const results: T[] = []; + + const toResolve = new LuaTable>(); + let numToResolve = 0; + + let i = 0; + for (const item of iterable) { + if (item instanceof __TS__Promise) { + if (item.state === PromiseState.Fulfilled) { + // If value is a resolved promise, add its value to our results array + results[i] = item.value; + } else if (item.state === PromiseState.Rejected) { + // If value is a rejected promise, return a rejected promise with the rejection reason + return Promise.reject(item.rejectionReason); + } else { + // If value is a pending promise, add it to the list of pending promises + numToResolve++; + toResolve.set(i, item); + } + } else { + // If value is not a promise, add it to the results array + results[i] = item as T; + } + i++; + } + + // If there are no remaining pending promises, return a resolved promise with the results + if (numToResolve === 0) { + return Promise.resolve(results); + } + + return new Promise((resolve, reject) => { + for (const [index, promise] of pairs(toResolve)) { + promise.then( + data => { + // When resolved, store value in results array + results[index] = data; + numToResolve--; + if (numToResolve === 0) { + // If there are no more promises to resolve, resolve with our filled results array + resolve(results); + } + }, + reason => { + // When rejected, immediately reject the returned promise + reject(reason); + } + ); + } + }); +} diff --git a/src/lualib/PromiseAllSettled.ts b/src/lualib/PromiseAllSettled.ts new file mode 100644 index 000000000..4bcd13123 --- /dev/null +++ b/src/lualib/PromiseAllSettled.ts @@ -0,0 +1,64 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled +import { __TS__Promise, PromiseState } from "./Promise"; + +// eslint-disable-next-line @typescript-eslint/promise-function-async +export function __TS__PromiseAllSettled( + this: void, + iterable: Iterable +): Promise ? U : T>>> { + const results: Array ? U : T>> = []; + + const toResolve = new LuaTable>(); + let numToResolve = 0; + + let i = 0; + for (const item of iterable) { + if (item instanceof __TS__Promise) { + if (item.state === PromiseState.Fulfilled) { + // If value is a resolved promise, add a fulfilled PromiseSettledResult + results[i] = { status: "fulfilled", value: item.value }; + } else if (item.state === PromiseState.Rejected) { + // If value is a rejected promise, add a rejected PromiseSettledResult + results[i] = { status: "rejected", reason: item.rejectionReason }; + } else { + // If value is a pending promise, add it to the list of pending promises + numToResolve++; + toResolve.set(i, item); + } + } else { + // If value is not a promise, add it to the results as fulfilled PromiseSettledResult + results[i] = { status: "fulfilled", value: item as any }; + } + i++; + } + + // If there are no remaining pending promises, return a resolved promise with the results + if (numToResolve === 0) { + return Promise.resolve(results); + } + + return new Promise(resolve => { + for (const [index, promise] of pairs(toResolve)) { + promise.then( + data => { + // When resolved, add a fulfilled PromiseSettledResult + results[index] = { status: "fulfilled", value: data as any }; + numToResolve--; + if (numToResolve === 0) { + // If there are no more promises to resolve, resolve with our filled results array + resolve(results); + } + }, + reason => { + // When resolved, add a rejected PromiseSettledResult + results[index] = { status: "rejected", reason }; + numToResolve--; + if (numToResolve === 0) { + // If there are no more promises to resolve, resolve with our filled results array + resolve(results); + } + } + ); + } + }); +} diff --git a/src/lualib/PromiseAny.ts b/src/lualib/PromiseAny.ts new file mode 100644 index 000000000..17c77f273 --- /dev/null +++ b/src/lualib/PromiseAny.ts @@ -0,0 +1,57 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any +import { __TS__Promise, PromiseState } from "./Promise"; + +// eslint-disable-next-line @typescript-eslint/promise-function-async +export function __TS__PromiseAny(this: void, iterable: Iterable>): Promise { + const rejections: string[] = []; + const pending: Array> = []; + + for (const item of iterable) { + if (item instanceof __TS__Promise) { + if (item.state === PromiseState.Fulfilled) { + // If value is a resolved promise, return a new resolved promise with its value + return Promise.resolve(item.value); + } else if (item.state === PromiseState.Rejected) { + // If value is a rejected promise, add its value to our list of rejections + rejections.push(item.rejectionReason); + } else { + // If value is a pending promise, add it to the list of pending promises + pending.push(item); + } + } else { + // If value is not a promise, return a resolved promise with it as its value + return Promise.resolve(item); + } + } + + // If we have not returned yet and there are no pending promises, reject + if (pending.length === 0) { + return Promise.reject("No promises to resolve with .any()"); + } + + let numResolved = 0; + + return new Promise((resolve, reject) => { + for (const promise of pending) { + promise.then( + data => { + // If any pending promise resolves, resolve this promise with its data + resolve(data); + }, + reason => { + // If a pending promise rejects, add its rejection to our rejection list + rejections.push(reason); + numResolved++; + if (numResolved === pending.length) { + // If there are no more pending promises, reject with the list of rejections + reject({ + name: "AggregateError", + message: "All Promises rejected", + errors: rejections, + }); + } + } + ); + } + }); +} diff --git a/src/lualib/PromiseRace.ts b/src/lualib/PromiseRace.ts new file mode 100644 index 000000000..238aaf33b --- /dev/null +++ b/src/lualib/PromiseRace.ts @@ -0,0 +1,36 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race +import { PromiseState, __TS__Promise } from "./Promise"; + +// eslint-disable-next-line @typescript-eslint/promise-function-async +export function __TS__PromiseRace(this: void, iterable: Iterable>): Promise { + const pending: Array> = []; + + for (const item of iterable) { + if (item instanceof __TS__Promise) { + if (item.state === PromiseState.Fulfilled) { + // If value is a fulfilled promise, return a resolved promise with its value + return Promise.resolve(item.value); + } else if (item.state === PromiseState.Rejected) { + // If value is a rejected promise, return rejected promise with its value + return Promise.reject(item.rejectionReason); + } else { + // If value is a pending promise, add it to the list of pending promises + pending.push(item); + } + } else { + // If value is not a promise, return a promise resolved with it as its value + return Promise.resolve(item); + } + } + + // If not yet returned, wait for any pending promise to resolve or reject. + // If there are no pending promise, this promise will be pending forever as per specification. + return new Promise((resolve, reject) => { + for (const promise of pending) { + promise.then( + value => resolve(value), + reason => reject(reason) + ); + } + }); +} diff --git a/src/lualib/Set.ts b/src/lualib/Set.ts index 71a8265ff..e302e4094 100644 --- a/src/lualib/Set.ts +++ b/src/lualib/Set.ts @@ -1,4 +1,4 @@ -Set = class Set { +export class Set { public static [Symbol.species] = Set; public [Symbol.toStringTag] = "Set"; @@ -42,8 +42,8 @@ Set = class Set { this.firstKey = value; this.lastKey = value; } else if (isNewValue) { - this.nextKey.set(this.lastKey, value); - this.previousKey.set(value, this.lastKey); + this.nextKey.set(this.lastKey!, value); + this.previousKey.set(value, this.lastKey!); this.lastKey = value; } @@ -66,22 +66,22 @@ Set = class Set { // Do order bookkeeping const next = this.nextKey.get(value); const previous = this.previousKey.get(value); - if (next && previous) { + if (next !== undefined && previous !== undefined) { this.nextKey.set(previous, next); this.previousKey.set(next, previous); - } else if (next) { + } else if (next !== undefined) { this.firstKey = next; - this.previousKey.set(next, undefined); - } else if (previous) { + this.previousKey.set(next, undefined!); + } else if (previous !== undefined) { this.lastKey = previous; - this.nextKey.set(previous, undefined); + this.nextKey.set(previous, undefined!); } else { this.firstKey = undefined; this.lastKey = undefined; } - this.nextKey.set(value, undefined); - this.previousKey.set(value, undefined); + this.nextKey.set(value, undefined!); + this.previousKey.set(value, undefined!); } return contains; @@ -102,47 +102,151 @@ Set = class Set { } public entries(): IterableIterator<[T, T]> { + const getFirstKey = () => this.firstKey; const nextKey = this.nextKey; - let key: T = this.firstKey; + let key: T | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator<[T, T]> { return this; }, next(): IteratorResult<[T, T]> { - const result = { done: !key, value: [key, key] as [T, T] }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: [key!, key!] as [T, T] }; }, }; } public keys(): IterableIterator { + const getFirstKey = () => this.firstKey; const nextKey = this.nextKey; - let key: T = this.firstKey; + let key: T | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator { return this; }, next(): IteratorResult { - const result = { done: !key, value: key }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: key! }; }, }; } public values(): IterableIterator { + const getFirstKey = () => this.firstKey; const nextKey = this.nextKey; - let key: T = this.firstKey; + let key: T | undefined; + let started = false; return { [Symbol.iterator](): IterableIterator { return this; }, next(): IteratorResult { - const result = { done: !key, value: key }; - key = nextKey.get(key); - return result; + if (!started) { + started = true; + key = getFirstKey(); + } else { + key = nextKey.get(key!); + } + return { done: !key, value: key! }; }, }; } -}; + + /** + * @returns a new Set containing all the elements in this Set and also all the elements in the argument. + */ + public union(other: ReadonlySet): Set { + const result = new Set(this); + for (const item of other) { + result.add(item); + } + return result; + } + + /** + * @returns a new Set containing all the elements which are both in this Set and in the argument. + */ + public intersection(other: ReadonlySet) { + const result = new Set(); + for (const item of this) { + if (other.has(item)) { + result.add(item); + } + } + return result; + } + + /** + * @returns a new Set containing all the elements in this Set which are not also in the argument. + */ + public difference(other: ReadonlySet): Set { + const result = new Set(this); + for (const item of other) { + result.delete(item); + } + return result; + } + + /** + * @returns a new Set containing all the elements which are in either this Set or in the argument, but not in both. + */ + public symmetricDifference(other: ReadonlySet): Set { + const result = new Set(this); + for (const item of other) { + if (this.has(item)) { + result.delete(item); + } else { + result.add(item); + } + } + return result; + } + + /** + * @returns a boolean indicating whether all the elements in this Set are also in the argument. + */ + public isSubsetOf(other: ReadonlySet): boolean { + for (const item of this) { + if (!other.has(item)) { + return false; + } + } + return true; + } + + /** + * @returns a boolean indicating whether all the elements in the argument are also in this Set. + */ + public isSupersetOf(other: ReadonlySet): boolean { + for (const item of other) { + if (!this.has(item as T)) { + return false; + } + } + return true; + } + + /** + * @returns a boolean indicating whether this Set has no elements in common with the argument. + */ + public isDisjointFrom(other: ReadonlySetLike): boolean { + for (const item of this) { + if (other.has(item)) { + return false; + } + } + return true; + } +} diff --git a/src/lualib/SetDescriptor.ts b/src/lualib/SetDescriptor.ts index 49c7a0bf2..ccb4bf3f0 100644 --- a/src/lualib/SetDescriptor.ts +++ b/src/lualib/SetDescriptor.ts @@ -1,72 +1,47 @@ -function ____descriptorIndex(this: any, key: string): void { - const value = rawget(this, key); - if (value !== null) { - return value; - } - - let metatable = getmetatable(this); - while (metatable) { - const rawResult = rawget(metatable, key); - if (rawResult !== undefined) { - return rawResult; - } - - const descriptors = rawget(metatable, "_descriptors"); - if (descriptors) { - const descriptor: PropertyDescriptor = descriptors[key]; - if (descriptor) { - if (descriptor.get) { - return descriptor.get.call(this); - } +import { __TS__CloneDescriptor } from "./CloneDescriptor"; +import { __TS__DescriptorGet } from "./DescriptorGet"; +import { __TS__DescriptorSet } from "./DescriptorSet"; - return descriptor.value; - } - } +const getmetatable = _G.getmetatable; - metatable = getmetatable(metatable); - } +function descriptorIndex(this: any, key: string): void { + return __TS__DescriptorGet.call(this, getmetatable(this), key); } -function ____descriptorNewindex(this: any, key: string, value: any): void { - let metatable = getmetatable(this); - while (metatable) { - const descriptors = rawget(metatable, "_descriptors"); - if (descriptors) { - const descriptor: PropertyDescriptor = descriptors[key]; - if (descriptor) { - if (descriptor.set) { - descriptor.set.call(this, value); - } else { - if (descriptor.writable === false) { - throw `Cannot assign to read only property '${key}' of object '${this}'`; - } - - descriptor.value = value; - } - return; - } - } - - metatable = getmetatable(metatable); - } - - rawset(this, key, value); +function descriptorNewIndex(this: any, key: string, value: any): void { + return __TS__DescriptorSet.call(this, getmetatable(this), key, value); } // It's also used directly in class transform to add descriptors to the prototype -function __TS__SetDescriptor(this: void, target: any, key: any, desc: PropertyDescriptor, isPrototype = false): void { +export function __TS__SetDescriptor( + this: void, + target: any, + key: any, + desc: PropertyDescriptor, + isPrototype = false +): void { let metatable = isPrototype ? target : getmetatable(target); if (!metatable) { metatable = {}; setmetatable(target, metatable); } + // When setting a descriptor on an instance (not a prototype), ensure it has + // its own metatable so descriptors are not shared across instances. + // See: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1625 + if (!isPrototype && !rawget(metatable, "_isOwnDescriptorMetatable")) { + const instanceMetatable: any = {}; + instanceMetatable._isOwnDescriptorMetatable = true; + setmetatable(instanceMetatable, metatable); + setmetatable(target, instanceMetatable); + metatable = instanceMetatable; + } + const value = rawget(target, key); if (value !== undefined) rawset(target, key, undefined); if (!rawget(metatable, "_descriptors")) metatable._descriptors = {}; - const descriptor = __TS__CloneDescriptor(desc); - metatable._descriptors[key] = descriptor; - metatable.__index = ____descriptorIndex; - metatable.__newindex = ____descriptorNewindex; + metatable._descriptors[key] = __TS__CloneDescriptor(desc); + metatable.__index = descriptorIndex; + metatable.__newindex = descriptorNewIndex; } diff --git a/src/lualib/SourceMapTraceBack.ts b/src/lualib/SourceMapTraceBack.ts index 3a264ead9..4597fa3dd 100644 --- a/src/lualib/SourceMapTraceBack.ts +++ b/src/lualib/SourceMapTraceBack.ts @@ -1,32 +1,80 @@ // TODO: In the future, change this to __TS__RegisterFileInfo and provide tstl interface to // get some metadata about transpilation. -function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: { [line: number]: number }): void { + +import { __TS__Match } from "./Match"; + +interface SourceMap { + [line: string]: number | { line: number; file: string }; +} + +declare global { + function __TS__originalTraceback(this: void, thread?: LuaThread, message?: string, level?: number): void; + var __TS__sourcemap: Record; +} + +export function __TS__SourceMapTraceBack(this: void, fileName: string, sourceMap: SourceMap): void { globalThis.__TS__sourcemap = globalThis.__TS__sourcemap || {}; globalThis.__TS__sourcemap[fileName] = sourceMap; if (globalThis.__TS__originalTraceback === undefined) { - globalThis.__TS__originalTraceback = debug.traceback; - debug.traceback = (thread, message, level) => { + const originalTraceback = debug.traceback; + globalThis.__TS__originalTraceback = originalTraceback as typeof __TS__originalTraceback; + debug.traceback = ((thread?: LuaThread, message?: string, level?: number) => { let trace: string; if (thread === undefined && message === undefined && level === undefined) { - trace = globalThis.__TS__originalTraceback(); + trace = originalTraceback(); + } else if (_VERSION.includes("Lua 5.0")) { + trace = originalTraceback(`[Level ${level}] ${message}`); } else { - trace = globalThis.__TS__originalTraceback(thread, message, level); + // @ts-ignore Fails when compiled with Lua 5.0 types + trace = originalTraceback(thread, message, level); } if (typeof trace !== "string") { return trace; } - const [result] = string.gsub(trace, "(%S+).lua:(%d+)", (file, line) => { - const fileSourceMap = globalThis.__TS__sourcemap[file + ".lua"]; - if (fileSourceMap && fileSourceMap[line]) { - return `${file}.ts:${fileSourceMap[line]}`; + const replacer = (file: string, srcFile: string, line: string) => { + const fileSourceMap: SourceMap = globalThis.__TS__sourcemap[file]; + if (fileSourceMap !== undefined && fileSourceMap[line] !== undefined) { + const data = fileSourceMap[line]; + if (typeof data === "number") { + return `${srcFile}:${data}`; + } + + return `${data.file}:${data.line}`; } - return `${file}.lua:${line}`; - }); + + return `${file}:${line}`; + }; + + // Rewrite stack trace frames from "{PATH}.lua:{LINE}" to "{PATH}.ts:{ORIGINAL_LINE}". + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1665 + // Avoid matching anonymous function stack entries like `in function <...>` + // by excluding `<` before the file path. + // TODO: This will still fail for paths containing spaces. + let [result] = string.gsub(trace, "([^%s<]+)%.lua:(%d+)", (file, line) => + replacer(`${file}.lua`, `${file}.ts`, line) + ); + + const stringReplacer = (file: string, line: string) => { + const fileSourceMap: SourceMap = globalThis.__TS__sourcemap[file]; + if (fileSourceMap !== undefined && fileSourceMap[line] !== undefined) { + const chunkName = __TS__Match(file, '%[string "([^"]+)"%]')[0]; + const [sourceName] = string.gsub(chunkName, ".lua$", ".ts"); + const data = fileSourceMap[line]; + if (typeof data === "number") { + return `${sourceName}:${data}`; + } + + return `${data.file}:${data.line}`; + } + + return `${file}:${line}`; + }; + [result] = string.gsub(result, '(%[string "[^"]+"%]):(%d+)', (file, line) => stringReplacer(file, line)); return result; - }; + }) as typeof debug.traceback; } } diff --git a/src/lualib/SparseArray.d.ts b/src/lualib/SparseArray.d.ts new file mode 100644 index 000000000..768d93d7f --- /dev/null +++ b/src/lualib/SparseArray.d.ts @@ -0,0 +1 @@ +export type __TS__SparseArray = T[] & { sparseLength: number }; diff --git a/src/lualib/SparseArrayNew.ts b/src/lualib/SparseArrayNew.ts new file mode 100644 index 000000000..c6877b9c2 --- /dev/null +++ b/src/lualib/SparseArrayNew.ts @@ -0,0 +1,9 @@ +import { __TS__CountVarargs } from "./CountVarargs"; +import { __TS__SparseArray } from "./SparseArray"; + +export function __TS__SparseArrayNew(this: void, ...args: T[]): __TS__SparseArray { + const sparseArray = [...args] as __TS__SparseArray; + // Note that we're depending on vararg optimization to occur here. + sparseArray.sparseLength = __TS__CountVarargs(...args); + return sparseArray; +} diff --git a/src/lualib/SparseArrayPush.ts b/src/lualib/SparseArrayPush.ts new file mode 100644 index 000000000..253d6e223 --- /dev/null +++ b/src/lualib/SparseArrayPush.ts @@ -0,0 +1,11 @@ +import { __TS__CountVarargs } from "./CountVarargs"; +import { __TS__SparseArray } from "./SparseArray"; + +export function __TS__SparseArrayPush(this: void, sparseArray: __TS__SparseArray, ...args: T[]): void { + const argsLen = __TS__CountVarargs(...args); + const listLen = sparseArray.sparseLength; + for (const i of $range(1, argsLen)) { + sparseArray[listLen + i - 1] = args[i - 1]; + } + sparseArray.sparseLength = listLen + argsLen; +} diff --git a/src/lualib/Spread.ts b/src/lualib/Spread.ts index 2bc96395b..3c736060d 100644 --- a/src/lualib/Spread.ts +++ b/src/lualib/Spread.ts @@ -1,14 +1,15 @@ -function __TS__Spread(this: void, iterable: string | Iterable): T[] { - const arr = []; +export function __TS__Spread(this: void, iterable: string | Iterable): LuaMultiReturn { + const arr: T[] = []; if (typeof iterable === "string") { - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = 0; i < iterable.length; i += 1) { - arr[arr.length] = iterable[i]; + for (const i of $range(0, iterable.length - 1)) { + arr[i] = iterable[i] as T; } } else { + let len = 0; for (const item of iterable) { - arr[arr.length] = item; + len++; + arr[len - 1] = item; } } - return __TS__Unpack(arr); + return $multi(...arr); } diff --git a/src/lualib/StringAccess.ts b/src/lualib/StringAccess.ts index 8695fd4e7..c273506c2 100644 --- a/src/lualib/StringAccess.ts +++ b/src/lualib/StringAccess.ts @@ -1,4 +1,4 @@ -function __TS__StringAccess(this: string, index: number) { +export function __TS__StringAccess(this: string, index: number) { if (index >= 0 && index < this.length) { return string.sub(this, index + 1, index + 1); } diff --git a/src/lualib/StringCharAt.ts b/src/lualib/StringCharAt.ts index 3c0e5161f..d76e94654 100644 --- a/src/lualib/StringCharAt.ts +++ b/src/lualib/StringCharAt.ts @@ -1,4 +1,4 @@ -function __TS__StringCharAt(this: string, pos: number): string { +export function __TS__StringCharAt(this: string, pos: number): string { if (pos !== pos) pos = 0; if (pos < 0) return ""; return string.sub(this, pos + 1, pos + 1); diff --git a/src/lualib/StringCharCodeAt.ts b/src/lualib/StringCharCodeAt.ts index 0044cc6cf..a3c722b9d 100644 --- a/src/lualib/StringCharCodeAt.ts +++ b/src/lualib/StringCharCodeAt.ts @@ -1,4 +1,4 @@ -function __TS__StringCharCodeAt(this: string, index: number): number { +export function __TS__StringCharCodeAt(this: string, index: number): number { if (index !== index) index = 0; if (index < 0) return NaN; return string.byte(this, index + 1) ?? NaN; diff --git a/src/lualib/StringConcat.ts b/src/lualib/StringConcat.ts deleted file mode 100644 index 657ae5c24..000000000 --- a/src/lualib/StringConcat.ts +++ /dev/null @@ -1,7 +0,0 @@ -function __TS__StringConcat(this: void, str1: string, ...args: string[]): string { - let out = str1; - for (const arg of args) { - out += arg; - } - return out; -} diff --git a/src/lualib/StringEndsWith.ts b/src/lualib/StringEndsWith.ts index b519a77eb..ea7d9020e 100644 --- a/src/lualib/StringEndsWith.ts +++ b/src/lualib/StringEndsWith.ts @@ -1,4 +1,4 @@ -function __TS__StringEndsWith(this: string, searchString: string, endPosition?: number): boolean { +export function __TS__StringEndsWith(this: string, searchString: string, endPosition?: number): boolean { if (endPosition === undefined || endPosition > this.length) { endPosition = this.length; } diff --git a/src/lualib/StringIncludes.ts b/src/lualib/StringIncludes.ts index 7508a2a42..3d896c8fa 100644 --- a/src/lualib/StringIncludes.ts +++ b/src/lualib/StringIncludes.ts @@ -1,4 +1,4 @@ -function __TS__StringIncludes(this: string, searchString: string, position?: number): boolean { +export function __TS__StringIncludes(this: string, searchString: string, position?: number): boolean { // http://lua-users.org/wiki/StringLibraryTutorial if (!position) { position = 1; diff --git a/src/lualib/StringPadEnd.ts b/src/lualib/StringPadEnd.ts index 24c8d48da..1f1c30e2e 100644 --- a/src/lualib/StringPadEnd.ts +++ b/src/lualib/StringPadEnd.ts @@ -1,4 +1,4 @@ -function __TS__StringPadEnd(this: string, maxLength: number, fillString = " "): string { +export function __TS__StringPadEnd(this: string, maxLength: number, fillString = " "): string { if (maxLength !== maxLength) maxLength = 0; if (maxLength === -Infinity || maxLength === Infinity) { throw "Invalid string length"; diff --git a/src/lualib/StringPadStart.ts b/src/lualib/StringPadStart.ts index 0e73f06fc..a6cb8e601 100644 --- a/src/lualib/StringPadStart.ts +++ b/src/lualib/StringPadStart.ts @@ -1,4 +1,4 @@ -function __TS__StringPadStart(this: string, maxLength: number, fillString = " "): string { +export function __TS__StringPadStart(this: string, maxLength: number, fillString = " "): string { if (maxLength !== maxLength) maxLength = 0; if (maxLength === -Infinity || maxLength === Infinity) { throw "Invalid string length"; diff --git a/src/lualib/StringReplace.ts b/src/lualib/StringReplace.ts index 51a093bef..9a2da017b 100644 --- a/src/lualib/StringReplace.ts +++ b/src/lualib/StringReplace.ts @@ -1,22 +1,17 @@ -function __TS__StringReplace( +const sub = string.sub; +export function __TS__StringReplace( this: void, source: string, searchValue: string, - replaceValue: string | ((substring: string) => string) + replaceValue: string | ((match: string, offset: number, string: string) => string) ): string { - [searchValue] = string.gsub(searchValue, "[%%%(%)%.%+%-%*%?%[%^%$]", "%%%1"); - - if (typeof replaceValue === "string") { - [replaceValue] = string.gsub(replaceValue, "%%", "%%%%"); - const [result] = string.gsub(source, searchValue, replaceValue, 1); - return result; - } else { - const [result] = string.gsub( - source, - searchValue, - match => (replaceValue as (substring: string) => string)(match), - 1 - ); - return result; + const [startPos, endPos] = string.find(source, searchValue, undefined, true); + if (!startPos) { + return source; } + const before = sub(source, 1, startPos - 1); + const replacement = + typeof replaceValue === "string" ? replaceValue : replaceValue(searchValue, startPos - 1, source); + const after = sub(source, endPos + 1); + return before + replacement + after; } diff --git a/src/lualib/StringReplaceAll.ts b/src/lualib/StringReplaceAll.ts new file mode 100644 index 000000000..c110512e9 --- /dev/null +++ b/src/lualib/StringReplaceAll.ts @@ -0,0 +1,41 @@ +const sub = string.sub; +const find = string.find; +export function __TS__StringReplaceAll( + this: void, + source: string, + searchValue: string, + replaceValue: string | ((match: string, offset: number, string: string) => string) +): string { + if (typeof replaceValue === "string") { + const concat = table.concat(source.split(searchValue), replaceValue); + if (searchValue.length === 0) { + return replaceValue + concat + replaceValue; + } + return concat; + } + const parts: string[] = []; + let partsIndex = 1; + + if (searchValue.length === 0) { + parts[0] = replaceValue("", 0, source); + partsIndex = 2; + for (const i of $range(1, source.length)) { + parts[partsIndex - 1] = sub(source, i, i); + parts[partsIndex] = replaceValue("", i, source); + partsIndex += 2; + } + } else { + let currentPos = 1; + while (true) { + const [startPos, endPos] = find(source, searchValue, currentPos, true); + if (!startPos) break; + parts[partsIndex - 1] = sub(source, currentPos, startPos - 1); + parts[partsIndex] = replaceValue(searchValue, startPos - 1, source); + partsIndex += 2; + + currentPos = endPos + 1; + } + parts[partsIndex - 1] = sub(source, currentPos); + } + return table.concat(parts); +} diff --git a/src/lualib/StringSlice.ts b/src/lualib/StringSlice.ts index 42355d9e1..307d86894 100644 --- a/src/lualib/StringSlice.ts +++ b/src/lualib/StringSlice.ts @@ -1,4 +1,4 @@ -function __TS__StringSlice(this: string, start?: number, end?: number): string { +export function __TS__StringSlice(this: string, start?: number, end?: number): string { if (start === undefined || start !== start) start = 0; if (end !== end) end = 0; diff --git a/src/lualib/StringSplit.ts b/src/lualib/StringSplit.ts index 734dac38c..f89ffb57d 100644 --- a/src/lualib/StringSplit.ts +++ b/src/lualib/StringSplit.ts @@ -1,36 +1,34 @@ -function __TS__StringSplit(this: void, source: string, separator?: string, limit?: number): string[] { - if (limit === undefined) { - limit = 4294967295; - } +const sub = string.sub; +const find = string.find; +export function __TS__StringSplit(this: void, source: string, separator?: string, limit?: number): string[] { + limit ??= 4294967295; if (limit === 0) { return []; } - const out = []; - let index = 0; - let count = 0; + const result = []; + let resultIndex = 1; if (separator === undefined || separator === "") { - while (index < source.length - 1 && count < limit) { - out[count] = source[index]; - count++; - index++; + for (const i of $range(1, source.length)) { + result[resultIndex - 1] = sub(source, i, i); + resultIndex++; } } else { - const separatorLength = separator.length; - let nextIndex = source.indexOf(separator); - while (nextIndex >= 0 && count < limit) { - out[count] = source.substring(index, nextIndex); - count++; - index = nextIndex + separatorLength; - nextIndex = source.indexOf(separator, index); + let currentPos = 1; + while (resultIndex <= limit) { + const [startPos, endPos] = find(source, separator, currentPos, true); + if (!startPos) break; + result[resultIndex - 1] = sub(source, currentPos, startPos - 1); + resultIndex++; + currentPos = endPos + 1; } - } - if (count < limit) { - out[count] = source.substring(index); + if (resultIndex <= limit) { + result[resultIndex - 1] = sub(source, currentPos); + } } - return out; + return result; } diff --git a/src/lualib/StringStartsWith.ts b/src/lualib/StringStartsWith.ts index 8de8fa8ec..82f542143 100644 --- a/src/lualib/StringStartsWith.ts +++ b/src/lualib/StringStartsWith.ts @@ -1,4 +1,4 @@ -function __TS__StringStartsWith(this: string, searchString: string, position?: number): boolean { +export function __TS__StringStartsWith(this: string, searchString: string, position?: number): boolean { if (position === undefined || position < 0) { position = 0; } diff --git a/src/lualib/StringSubstr.ts b/src/lualib/StringSubstr.ts index e14c3c4a5..1940daf4d 100644 --- a/src/lualib/StringSubstr.ts +++ b/src/lualib/StringSubstr.ts @@ -1,4 +1,4 @@ -function __TS__StringSubstr(this: string, from: number, length?: number): string { +export function __TS__StringSubstr(this: string, from: number, length?: number): string { if (from !== from) from = 0; if (length !== undefined) { diff --git a/src/lualib/StringSubstring.ts b/src/lualib/StringSubstring.ts index df8210555..f3480081a 100644 --- a/src/lualib/StringSubstring.ts +++ b/src/lualib/StringSubstring.ts @@ -1,4 +1,4 @@ -function __TS__StringSubstring(this: string, start: number, end?: number): string { +export function __TS__StringSubstring(this: string, start: number, end?: number): string { if (end !== end) end = 0; if (end !== undefined && start > end) { diff --git a/src/lualib/StringTrim.ts b/src/lualib/StringTrim.ts index 8a231118a..f1d71d712 100644 --- a/src/lualib/StringTrim.ts +++ b/src/lualib/StringTrim.ts @@ -1,4 +1,4 @@ -function __TS__StringTrim(this: string): string { +export function __TS__StringTrim(this: string): string { // http://lua-users.org/wiki/StringTrim const [result] = string.gsub(this, "^[%s\xA0\uFEFF]*(.-)[%s\xA0\uFEFF]*$", "%1"); return result; diff --git a/src/lualib/StringTrimEnd.ts b/src/lualib/StringTrimEnd.ts index c45238235..711c91538 100644 --- a/src/lualib/StringTrimEnd.ts +++ b/src/lualib/StringTrimEnd.ts @@ -1,4 +1,4 @@ -function __TS__StringTrimEnd(this: string): string { +export function __TS__StringTrimEnd(this: string): string { // http://lua-users.org/wiki/StringTrim const [result] = string.gsub(this, "[%s\xA0\uFEFF]*$", ""); return result; diff --git a/src/lualib/StringTrimStart.ts b/src/lualib/StringTrimStart.ts index 47e6e8a66..258ea4f8b 100644 --- a/src/lualib/StringTrimStart.ts +++ b/src/lualib/StringTrimStart.ts @@ -1,4 +1,4 @@ -function __TS__StringTrimStart(this: string): string { +export function __TS__StringTrimStart(this: string): string { // http://lua-users.org/wiki/StringTrim const [result] = string.gsub(this, "^[%s\xA0\uFEFF]*", ""); return result; diff --git a/src/lualib/Symbol.ts b/src/lualib/Symbol.ts index 61a5c0423..5c1d7076b 100644 --- a/src/lualib/Symbol.ts +++ b/src/lualib/Symbol.ts @@ -1,14 +1,16 @@ -const ____symbolMetatable = { +const symbolMetatable = { __tostring(this: symbol): string { - return `Symbol(${this.description || ""})`; + return `Symbol(${this.description ?? ""})`; }, }; -function __TS__Symbol(this: void, description?: string | number): symbol { - return setmetatable({ description }, ____symbolMetatable) as any; +export function __TS__Symbol(this: void, description?: string | number): symbol { + return setmetatable({ description }, symbolMetatable) as unknown as symbol; } -Symbol = { +export const Symbol = { + asyncDispose: __TS__Symbol("Symbol.asyncDispose"), + dispose: __TS__Symbol("Symbol.dispose"), iterator: __TS__Symbol("Symbol.iterator"), hasInstance: __TS__Symbol("Symbol.hasInstance"), diff --git a/src/lualib/SymbolRegistry.ts b/src/lualib/SymbolRegistry.ts index 460edcc86..4deaa0993 100644 --- a/src/lualib/SymbolRegistry.ts +++ b/src/lualib/SymbolRegistry.ts @@ -1,15 +1,18 @@ -const ____symbolRegistry: Record = {}; +import { __TS__Symbol } from "./Symbol"; -function __TS__SymbolRegistryFor(this: void, key: string): symbol { - if (!____symbolRegistry[key]) { - ____symbolRegistry[key] = __TS__Symbol(key); +const symbolRegistry: Record = {}; +export function __TS__SymbolRegistryFor(this: void, key: string): symbol { + if (!symbolRegistry[key]) { + symbolRegistry[key] = __TS__Symbol(key); } - return ____symbolRegistry[key]; + return symbolRegistry[key]; } -function __TS__SymbolRegistryKeyFor(this: void, sym: symbol): string { - for (const key in ____symbolRegistry) { - if (____symbolRegistry[key] === sym) return key; +export function __TS__SymbolRegistryKeyFor(this: void, sym: symbol): string | undefined { + for (const key in symbolRegistry) { + if (symbolRegistry[key] === sym) return key; } + + return undefined; } diff --git a/src/lualib/TypeOf.ts b/src/lualib/TypeOf.ts index 158062cd4..5afbbde04 100644 --- a/src/lualib/TypeOf.ts +++ b/src/lualib/TypeOf.ts @@ -1,4 +1,4 @@ -function __TS__TypeOf(this: void, value: unknown): string { +export function __TS__TypeOf(this: void, value: unknown): string { const luaType = type(value); if (luaType === "table") { return "object"; diff --git a/src/lualib/Unpack.ts b/src/lualib/Unpack.ts deleted file mode 100644 index 99aedf253..000000000 --- a/src/lualib/Unpack.ts +++ /dev/null @@ -1 +0,0 @@ -const __TS__Unpack = table.unpack || unpack; diff --git a/src/lualib/Using.ts b/src/lualib/Using.ts new file mode 100644 index 000000000..a720f6e60 --- /dev/null +++ b/src/lualib/Using.ts @@ -0,0 +1,22 @@ +export function __TS__Using( + this: undefined, + cb: (this: void, ...args: TArgs) => TReturn, + ...args: TArgs +): TReturn { + let thrownError; + const [ok, result] = xpcall( + () => cb(...args), + err => (thrownError = err) + ); + + const argArray = [...args]; + for (let i = argArray.length - 1; i >= 0; i--) { + argArray[i][Symbol.dispose](); + } + + if (!ok) { + throw thrownError; + } + + return result; +} diff --git a/src/lualib/UsingAsync.ts b/src/lualib/UsingAsync.ts new file mode 100644 index 000000000..e4b7593f9 --- /dev/null +++ b/src/lualib/UsingAsync.ts @@ -0,0 +1,27 @@ +export async function __TS__UsingAsync, TReturn>( + this: undefined, + cb: (...args: TArgs) => TReturn, + ...args: TArgs +): Promise { + let thrownError; + const [ok, result] = xpcall( + () => cb(...args), + err => (thrownError = err) + ); + + const argArray = [...args]; + for (let i = argArray.length - 1; i >= 0; i--) { + if (Symbol.dispose in argArray[i]) { + (argArray[i] as Disposable)[Symbol.dispose](); + } + if (Symbol.asyncDispose in argArray[i]) { + await (argArray[i] as AsyncDisposable)[Symbol.asyncDispose](); + } + } + + if (!ok) { + throw thrownError; + } + + return result; +} diff --git a/src/lualib/WeakMap.ts b/src/lualib/WeakMap.ts index 7b7df1e99..65d1ae4da 100644 --- a/src/lualib/WeakMap.ts +++ b/src/lualib/WeakMap.ts @@ -1,4 +1,4 @@ -WeakMap = class WeakMap { +export class WeakMap { public static [Symbol.species] = WeakMap; public [Symbol.toStringTag] = "WeakMap"; @@ -30,7 +30,7 @@ WeakMap = class WeakMap { public delete(key: K): boolean { const contains = this.has(key); - this.items.set(key, undefined); + this.items.set(key, undefined!); return contains; } @@ -46,4 +46,4 @@ WeakMap = class WeakMap { this.items.set(key, value); return this; } -}; +} diff --git a/src/lualib/WeakSet.ts b/src/lualib/WeakSet.ts index 670b3c695..b921efc17 100644 --- a/src/lualib/WeakSet.ts +++ b/src/lualib/WeakSet.ts @@ -1,4 +1,4 @@ -WeakSet = class WeakSet { +export class WeakSet { public static [Symbol.species] = WeakSet; public [Symbol.toStringTag] = "WeakSet"; @@ -33,11 +33,11 @@ WeakSet = class WeakSet { public delete(value: T): boolean { const contains = this.has(value); - this.items.set(value, undefined); + this.items.set(value, undefined!); return contains; } public has(value: T): boolean { return this.items.get(value) === true; } -}; +} diff --git a/src/lualib/declarations/coroutine.d.ts b/src/lualib/declarations/coroutine.d.ts deleted file mode 100644 index 1e648d6c8..000000000 --- a/src/lualib/declarations/coroutine.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** @noSelfInFile */ - -interface LuaThread { - readonly __internal__: unique symbol; -} - -declare namespace coroutine { - function create(f: (...args: any[]) => any): LuaThread; - - /** @tupleReturn */ - function resume(co: LuaThread, ...val: any[]): [true, ...any[]] | [false, string]; - - function status(co: LuaThread): "running" | "suspended" | "normal" | "dead"; - - function wrap(f: (...args: any[]) => any): /** @tupleReturn */ (...args: any[]) => any[]; - - /** @tupleReturn */ - function yield(...args: any[]): any[]; -} diff --git a/src/lualib/declarations/debug.d.ts b/src/lualib/declarations/debug.d.ts deleted file mode 100644 index 2333f95d4..000000000 --- a/src/lualib/declarations/debug.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** @noSelfInFile */ - -declare const _VERSION: string; -declare function error(...args: any[]): never; - -declare namespace debug { - function traceback(...args: any[]): string; - - interface FunctionInfo any = () => any> { - func: T; - name?: string; - namewhat: "global" | "local" | "method" | "field" | ""; - source: string; - short_src: string; - linedefined: number; - lastlinedefined: number; - what: "Lua" | "C" | "main"; - currentline: number; - nups: number; - } - - function getinfo(i: number, what?: string): Partial; -} diff --git a/src/lualib/declarations/global.d.ts b/src/lualib/declarations/global.d.ts deleted file mode 100644 index 488586275..000000000 --- a/src/lualib/declarations/global.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable no-var */ -/** @noSelfInFile */ - -type AnyTable = Record; -// eslint-disable-next-line -type AnyNotNil = {}; - -declare var __TS__sourcemap: Record | undefined; -declare var __TS__originalTraceback: - | ((this: void, thread?: any, message?: string, level?: number) => string) - | undefined; - -// Override next declaration so we can omit extra return values -declare type NextEmptyCheck = (this: void, table: any, index: undefined) => unknown | undefined; - -declare function tonumber(value: any, base?: number): number | undefined; -declare function type( - value: any -): "nil" | "number" | "string" | "boolean" | "table" | "function" | "thread" | "userdata"; -declare function setmetatable(table: T, metatable: any): T; -declare function getmetatable(table: T): any; -declare function rawget(table: T, key: K): T[K]; -declare function rawset(table: T, key: K, val: T[K]): void; -/** @tupleReturn */ -declare function next(table: Record, index?: K): [K, V]; -declare function pcall(func: () => any): any; -declare function unpack(list: T[], i?: number, j?: number): T[]; - -declare function select(index: number, ...args: T[]): T; -declare function select(index: "#", ...args: T[]): number; - -declare function ipairs(t: Record): LuaIterable, Record>; diff --git a/src/lualib/declarations/math.d.ts b/src/lualib/declarations/math.d.ts deleted file mode 100644 index 54568c031..000000000 --- a/src/lualib/declarations/math.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** @noSelf */ -declare namespace math { - /** @tupleReturn */ - function modf(x: number): [number, number]; - - function atan(x: number): number; - // eslint-disable-next-line @typescript-eslint/unified-signatures - function atan(y: number, x?: number): number; - - function atan2(y: number, x: number): number; - - function ceil(x: number): number; - function floor(x: number): number; -} diff --git a/src/lualib/declarations/string.d.ts b/src/lualib/declarations/string.d.ts deleted file mode 100644 index ed5aa27e5..000000000 --- a/src/lualib/declarations/string.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** @noSelf */ -declare namespace string { - function byte(s: string, i?: number): number | undefined; - /** @tupleReturn */ - function byte(s: string, i?: number, j?: number): number[]; - - /** @tupleReturn */ - function gsub( - source: string, - searchValue: string, - replaceValue: string | ((...groups: string[]) => string), - n?: number - ): [string, number]; - function sub(s: string, i: number, j?: number): string; - function format(formatstring: string, ...args: any[]): string; - function match(string: string, pattern: string): string; - function find( - string: string, - pattern: string, - start?: number, - plainflag?: boolean - ): LuaMultiReturn<[number, number] | [undefined]>; -} diff --git a/src/lualib/declarations/table.d.ts b/src/lualib/declarations/table.d.ts deleted file mode 100644 index 776fe72b0..000000000 --- a/src/lualib/declarations/table.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** @noSelfInFile */ - -declare namespace table { - function sort(list: T[], compareFn?: (a: T, b: T) => boolean): void; - function remove(list: T[], idx: number): T; - function insert(list: T[], idx: number, val: T): void; - function unpack(list: T[], i?: number, j?: number): T[]; -} diff --git a/src/lualib/declarations/tstl.d.ts b/src/lualib/declarations/tstl.d.ts index f68237190..9de44be80 100644 --- a/src/lualib/declarations/tstl.d.ts +++ b/src/lualib/declarations/tstl.d.ts @@ -1,18 +1,24 @@ /** @noSelfInFile */ -interface Metatable { +interface LuaMetatable { _descriptors?: Record; __index?: any; __newindex?: any; __tostring?: any; + __errorToStringPatched?: boolean; } -interface LuaClass extends Metatable { +interface LuaClass extends LuaMetatable { prototype: LuaClassInstance; [Symbol.hasInstance]?(instance: LuaClassInstance): any; ____super?: LuaClass; } -interface LuaClassInstance extends Metatable { +interface LuaClassInstance extends LuaMetatable { constructor: LuaClass; } + +// Declare math atan2 for versions that have it instead of math.atan +declare namespace math { + const atan2: typeof atan; +} diff --git a/src/lualib/declarations/universal/unpack.d.ts b/src/lualib/declarations/universal/unpack.d.ts new file mode 100644 index 000000000..c199c09df --- /dev/null +++ b/src/lualib/declarations/universal/unpack.d.ts @@ -0,0 +1,4 @@ +/** @noSelfInFile */ + +// Declare unpack for versions that have it instead of table.unpack +declare const unpack: typeof table.unpack | undefined; diff --git a/src/lualib/tsconfig.json b/src/lualib/tsconfig.json index f16968dc1..0f0874d0d 100644 --- a/src/lualib/tsconfig.json +++ b/src/lualib/tsconfig.json @@ -1,16 +1,18 @@ { "compilerOptions": { - "outDir": "../../dist/lualib", + "outDir": "../../dist/lualib/universal", "target": "esnext", "lib": ["esnext"], - "types": ["../../language-extensions"], + "types": ["lua-types/5.4"], "skipLibCheck": true, + "rootDirs": [".", "universal"], - "noUnusedLocals": true, - "noUnusedParameters": true + "strict": true }, "tstl": { "luaLibImport": "none", - "noHeader": true - } + "noHeader": true, + "luaPlugins": [{ "name": "../../dist/lualib-build/plugin.js" }] + }, + "include": ["*.ts", "universal/**/*.ts", "declarations/**/*.ts", "../../language-extensions/index.d.ts"] } diff --git a/src/lualib/tsconfig.lua50.json b/src/lualib/tsconfig.lua50.json new file mode 100644 index 000000000..a0b5aee4b --- /dev/null +++ b/src/lualib/tsconfig.lua50.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "outDir": "../../dist/lualib/5.0", + "target": "esnext", + "lib": ["esnext"], + "types": ["lua-types/5.0"], + "skipLibCheck": true, + "rootDirs": [".", "5.0"], + + "strict": true + }, + "tstl": { + "luaLibImport": "none", + "noHeader": true, + "luaTarget": "5.0", + "luaPlugins": [{ "name": "../../dist/lualib-build/plugin.js" }] + }, + "include": ["*.ts", "5.0/**/*.ts", "declarations/**/*.ts", "../../language-extensions/index.d.ts"] +} diff --git a/src/lualib/universal/CountVarargs.ts b/src/lualib/universal/CountVarargs.ts new file mode 100644 index 000000000..dc6107bb5 --- /dev/null +++ b/src/lualib/universal/CountVarargs.ts @@ -0,0 +1,6 @@ +/** @noSelfInFile */ + +export function __TS__CountVarargs(...args: T[]): number { + // Note that we need vararg optimization for this call. + return select("#", ...args); +} diff --git a/src/lualib/universal/Match.ts b/src/lualib/universal/Match.ts new file mode 100644 index 000000000..de9420b59 --- /dev/null +++ b/src/lualib/universal/Match.ts @@ -0,0 +1 @@ +export const __TS__Match = string.match; diff --git a/src/lualib/universal/MathModf.ts b/src/lualib/universal/MathModf.ts new file mode 100644 index 000000000..139ae8f6a --- /dev/null +++ b/src/lualib/universal/MathModf.ts @@ -0,0 +1 @@ +export const __TS__MathModf = math.modf; diff --git a/src/lualib/universal/SparseArraySpread.ts b/src/lualib/universal/SparseArraySpread.ts new file mode 100644 index 000000000..99871cb89 --- /dev/null +++ b/src/lualib/universal/SparseArraySpread.ts @@ -0,0 +1,6 @@ +import { __TS__SparseArray } from "./SparseArray"; + +export function __TS__SparseArraySpread(this: void, sparseArray: __TS__SparseArray): LuaMultiReturn { + const _unpack = unpack ?? table.unpack; + return _unpack(sparseArray, 1, sparseArray.sparseLength); +} diff --git a/src/lualib/universal/Unpack.ts b/src/lualib/universal/Unpack.ts new file mode 100644 index 000000000..f138f2d7d --- /dev/null +++ b/src/lualib/universal/Unpack.ts @@ -0,0 +1 @@ +export const __TS__Unpack = table.unpack || unpack; diff --git a/src/measure-performance.ts b/src/measure-performance.ts new file mode 100644 index 000000000..1d66af7e8 --- /dev/null +++ b/src/measure-performance.ts @@ -0,0 +1,83 @@ +import { performance } from "perf_hooks"; + +// We use our own performance hooks implementation for easier use, but also call node's performance hooks, so it shows up in the profiler. + +let enabled = false; +const marks = new Map(); +const durations = new Map(); + +function timestamp() { + return performance.now(); +} + +/** + * Marks a performance event, with the given markName. + */ +function mark(markName: string) { + if (enabled) { + marks.set(markName, timestamp()); + performance.mark(markName); + } +} + +/** + * Adds a performance measurement with the specified name. + * + * @param measureName The name of the performance measurement. + * @param startMarkName The name of the starting mark + * @param endMarkName The name of the ending mark + */ +function measure(measureName: string, startMarkName: string, endMarkName: string) { + if (enabled) { + const end = marks.get(endMarkName) ?? timestamp(); + const start = marks.get(startMarkName) ?? performance.timeOrigin; + const previousDuration = durations.get(measureName) ?? 0; + durations.set(measureName, previousDuration + (end - start)); + performance.measure(measureName, startMarkName, endMarkName); + } +} + +/** + * Starts a performance measurement section. + * @param name name of the measurement + */ +export function startSection(name: string) { + mark("start " + name); +} + +/** + * Ends a performance measurement section. + * @param name name of the measurement + */ +export function endSection(name: string) { + mark("end " + name); + measure(name, "start " + name, "end " + name); +} + +export function isMeasurementEnabled() { + return enabled; +} + +export function enableMeasurement() { + if (!enabled) { + enabled = true; + } +} + +export function disableMeasurement() { + if (enabled) { + enabled = false; + marks.clear(); + durations.clear(); + } +} + +export function forEachMeasure(callback: (measureName: string, duration: number) => void) { + durations.forEach((duration, measureName) => callback(measureName, duration)); +} + +export function getTotalDuration() { + let total = 0; + forEachMeasure((_, duration) => (total += duration)); + return total; +} diff --git a/src/transformation/builtins/array.ts b/src/transformation/builtins/array.ts index d8bd4dd3b..b22bff01d 100644 --- a/src/transformation/builtins/array.ts +++ b/src/transformation/builtins/array.ts @@ -1,49 +1,127 @@ import * as ts from "typescript"; +import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; -import { isStringType, isNumberType } from "../utils/typescript"; +import { transformArguments, transformCallAndArguments } from "../visitors/call"; +import { expressionResultIsUsed, typeAlwaysHasSomeOfFlags } from "../utils/typescript"; +import { moveToPrecedingTemp } from "../visitors/expression-list"; +import { isUnpackCall, wrapInTable } from "../utils/lua-ast"; export function transformArrayConstructorCall( context: TransformationContext, - node: PropertyCallExpression -): lua.CallExpression | undefined { - const expression = node.expression; + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +): lua.Expression | undefined { const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { + case "from": + return transformLuaLibFunction(context, LuaLibFeature.ArrayFrom, node, ...params); case "isArray": return transformLuaLibFunction(context, LuaLibFeature.ArrayIsArray, node, ...params); + case "of": + return wrapInTable(...params); default: - context.diagnostics.push(unsupportedProperty(expression.name, "Array", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Array", expressionName)); } } +function createTableLengthExpression(context: TransformationContext, expression: lua.Expression, node?: ts.Expression) { + if (context.luaTarget === LuaTarget.Lua50) { + const tableGetn = lua.createTableIndexExpression( + lua.createIdentifier("table"), + lua.createStringLiteral("getn") + ); + return lua.createCallExpression(tableGetn, [expression], node); + } else { + return lua.createUnaryExpression(expression, lua.SyntaxKind.LengthOperator, node); + } +} + +/** + * Optimized single element Array.push + * + * array[#array+1] = el + * return (#array + 1) + */ +function transformSingleElementArrayPush( + context: TransformationContext, + node: ts.CallExpression, + caller: lua.Expression, + param: lua.Expression +): lua.Expression { + const arrayIdentifier = lua.isIdentifier(caller) ? caller : moveToPrecedingTemp(context, caller); + + // #array + 1 + let lengthExpression: lua.Expression = lua.createBinaryExpression( + createTableLengthExpression(context, arrayIdentifier), + lua.createNumericLiteral(1), + lua.SyntaxKind.AdditionOperator + ); + + const expressionIsUsed = expressionResultIsUsed(node); + if (expressionIsUsed) { + // store length in a temp + lengthExpression = moveToPrecedingTemp(context, lengthExpression); + } + + const pushStatement = lua.createAssignmentStatement( + lua.createTableIndexExpression(arrayIdentifier, lengthExpression), + param, + node + ); + context.addPrecedingStatements(pushStatement); + return expressionIsUsed ? lengthExpression : lua.createNilLiteral(); +} + export function transformArrayPrototypeCall( context: TransformationContext, - node: PropertyCallExpression -): lua.CallExpression | undefined { - const expression = node.expression; + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +): lua.Expression | undefined { const signature = context.checker.getResolvedSignature(node); - const params = transformArguments(context, node.arguments, signature); - const caller = context.transformExpression(expression.expression); + const [caller, params] = transformCallAndArguments(context, calledMethod.expression, node.arguments, signature); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { + case "at": + return transformLuaLibFunction(context, LuaLibFeature.ArrayAt, node, caller, ...params); case "concat": return transformLuaLibFunction(context, LuaLibFeature.ArrayConcat, node, caller, ...params); case "entries": return transformLuaLibFunction(context, LuaLibFeature.ArrayEntries, node, caller); + case "fill": + return transformLuaLibFunction(context, LuaLibFeature.ArrayFill, node, caller, ...params); case "push": + if (node.arguments.length === 1) { + const param = params[0] ?? lua.createNilLiteral(); + if (isUnpackCall(param)) { + return transformLuaLibFunction( + context, + LuaLibFeature.ArrayPushArray, + node, + caller, + (param as lua.CallExpression).params[0] ?? lua.createNilLiteral() + ); + } + if (!lua.isDotsLiteral(param)) { + return transformSingleElementArrayPush(context, node, caller, param); + } + } + return transformLuaLibFunction(context, LuaLibFeature.ArrayPush, node, caller, ...params); case "reverse": return transformLuaLibFunction(context, LuaLibFeature.ArrayReverse, node, caller); case "shift": - return transformLuaLibFunction(context, LuaLibFeature.ArrayShift, node, caller); + return lua.createCallExpression( + lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("remove")), + [caller, lua.createNumericLiteral(1)], + node + ); case "unshift": return transformLuaLibFunction(context, LuaLibFeature.ArrayUnshift, node, caller, ...params); case "sort": @@ -81,15 +159,21 @@ export function transformArrayPrototypeCall( case "splice": return transformLuaLibFunction(context, LuaLibFeature.ArraySplice, node, caller, ...params); case "join": - const callerType = context.checker.getTypeAtLocation(expression.expression); + const callerType = context.checker.getTypeAtLocation(calledMethod.expression); const elementType = context.checker.getElementTypeOfArrayType(callerType); - if (elementType && (isStringType(context, elementType) || isNumberType(context, elementType))) { + if ( + elementType && + typeAlwaysHasSomeOfFlags(context, elementType, ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike) + ) { const defaultSeparatorLiteral = lua.createStringLiteral(","); + const param = params[0] ?? lua.createNilLiteral(); const parameters = [ caller, node.arguments.length === 0 ? defaultSeparatorLiteral - : lua.createBinaryExpression(params[0], defaultSeparatorLiteral, lua.SyntaxKind.OrOperator), + : lua.isStringLiteral(param) + ? param + : lua.createBinaryExpression(param, defaultSeparatorLiteral, lua.SyntaxKind.OrOperator), ]; return lua.createCallExpression( @@ -104,19 +188,27 @@ export function transformArrayPrototypeCall( return transformLuaLibFunction(context, LuaLibFeature.ArrayFlat, node, caller, ...params); case "flatMap": return transformLuaLibFunction(context, LuaLibFeature.ArrayFlatMap, node, caller, ...params); + case "toReversed": + return transformLuaLibFunction(context, LuaLibFeature.ArrayToReversed, node, caller, ...params); + case "toSorted": + return transformLuaLibFunction(context, LuaLibFeature.ArrayToSorted, node, caller, ...params); + case "toSpliced": + return transformLuaLibFunction(context, LuaLibFeature.ArrayToSpliced, node, caller, ...params); + case "with": + return transformLuaLibFunction(context, LuaLibFeature.ArrayWith, node, caller, ...params); default: - context.diagnostics.push(unsupportedProperty(expression.name, "array", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "array", expressionName)); } } export function transformArrayProperty( context: TransformationContext, node: ts.PropertyAccessExpression -): lua.UnaryExpression | undefined { +): lua.Expression | undefined { switch (node.name.text) { case "length": const expression = context.transformExpression(node.expression); - return lua.createUnaryExpression(expression, lua.SyntaxKind.LengthOperator, node); + return createTableLengthExpression(context, expression, node); default: return undefined; } diff --git a/src/transformation/builtins/console.ts b/src/transformation/builtins/console.ts index af7ceb87e..a32f547da 100644 --- a/src/transformation/builtins/console.ts +++ b/src/transformation/builtins/console.ts @@ -2,25 +2,25 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments } from "../visitors/call"; const isStringFormatTemplate = (node: ts.Expression) => ts.isStringLiteral(node) && node.text.includes("%"); export function transformConsoleCall( context: TransformationContext, - expression: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const method = expression.expression; - const methodName = method.name.text; - const signature = context.checker.getResolvedSignature(expression); - const parameters = transformArguments(context, expression.arguments, signature); + const methodName = calledMethod.name.text; + const signature = context.checker.getResolvedSignature(node); + const parameters = transformArguments(context, node.arguments, signature); switch (methodName) { case "error": case "info": case "log": case "warn": - if (expression.arguments.length > 0 && isStringFormatTemplate(expression.arguments[0])) { + if (node.arguments.length > 0 && isStringFormatTemplate(node.arguments[0])) { // print(string.format([arguments])) const stringFormatCall = lua.createCallExpression( lua.createTableIndexExpression(lua.createIdentifier("string"), lua.createStringLiteral("format")), @@ -31,7 +31,7 @@ export function transformConsoleCall( // print([arguments]) return lua.createCallExpression(lua.createIdentifier("print"), parameters); case "assert": - if (expression.arguments.length > 1 && isStringFormatTemplate(expression.arguments[1])) { + if (node.arguments.length > 1 && isStringFormatTemplate(node.arguments[1])) { // assert([condition], string.format([arguments])) const stringFormatCall = lua.createCallExpression( lua.createTableIndexExpression(lua.createIdentifier("string"), lua.createStringLiteral("format")), @@ -42,7 +42,7 @@ export function transformConsoleCall( // assert() return lua.createCallExpression(lua.createIdentifier("assert"), parameters); case "trace": - if (expression.arguments.length > 0 && isStringFormatTemplate(expression.arguments[0])) { + if (node.arguments.length > 0 && isStringFormatTemplate(node.arguments[0])) { // print(debug.traceback(string.format([arguments]))) const stringFormatCall = lua.createCallExpression( lua.createTableIndexExpression(lua.createIdentifier("string"), lua.createStringLiteral("format")), @@ -61,6 +61,6 @@ export function transformConsoleCall( ); return lua.createCallExpression(lua.createIdentifier("print"), [debugTracebackCall]); default: - context.diagnostics.push(unsupportedProperty(method.name, "console", methodName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "console", methodName)); } } diff --git a/src/transformation/builtins/function.ts b/src/transformation/builtins/function.ts index f6cb8a6a0..8b219b6ba 100644 --- a/src/transformation/builtins/function.ts +++ b/src/transformation/builtins/function.ts @@ -4,37 +4,33 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedForTarget, unsupportedProperty, unsupportedSelfFunctionConversion } from "../utils/diagnostics"; import { ContextType, getFunctionContextType } from "../utils/function-context"; -import { createUnpackCall } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformCallAndArguments } from "../visitors/call"; +import { createUnpackCall } from "../utils/lua-ast"; export function transformFunctionPrototypeCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.CallExpression | undefined { - const expression = node.expression; - const callerType = context.checker.getTypeAtLocation(expression.expression); + const callerType = context.checker.getTypeAtLocation(calledMethod.expression); if (getFunctionContextType(context, callerType) === ContextType.Void) { context.diagnostics.push(unsupportedSelfFunctionConversion(node)); } const signature = context.checker.getResolvedSignature(node); - const params = transformArguments(context, node.arguments, signature); - const caller = context.transformExpression(expression.expression); - const expressionName = expression.name.text; + const [caller, params] = transformCallAndArguments(context, calledMethod.expression, node.arguments, signature); + const expressionName = calledMethod.name.text; switch (expressionName) { case "apply": - return lua.createCallExpression( - caller, - [params[0], createUnpackCall(context, params[1], node.arguments[1])], - node - ); + const nonContextArgs = params.length > 1 ? [createUnpackCall(context, params[1], node.arguments[1])] : []; + return lua.createCallExpression(caller, [params[0], ...nonContextArgs], node); case "bind": return transformLuaLibFunction(context, LuaLibFeature.FunctionBind, node, caller, ...params); case "call": return lua.createCallExpression(caller, params, node); - default: - context.diagnostics.push(unsupportedProperty(expression.name, "function", expressionName)); + case "toString": + context.diagnostics.push(unsupportedProperty(calledMethod.name, "function", expressionName)); } } @@ -44,8 +40,12 @@ export function transformFunctionProperty( ): lua.Expression | undefined { switch (node.name.text) { case "length": - if (context.luaTarget === LuaTarget.Lua51 || context.luaTarget === LuaTarget.Universal) { - context.diagnostics.push(unsupportedForTarget(node, "function.length", LuaTarget.Lua51)); + if ( + context.luaTarget === LuaTarget.Lua50 || + context.luaTarget === LuaTarget.Lua51 || + context.luaTarget === LuaTarget.Universal + ) { + context.diagnostics.push(unsupportedForTarget(node, "function.length", context.luaTarget)); } // debug.getinfo(fn) @@ -61,7 +61,10 @@ export function transformFunctionProperty( ? lua.createBinaryExpression(nparams, lua.createNumericLiteral(1), lua.SyntaxKind.SubtractionOperator) : nparams; - default: + case "arguments": + case "caller": + case "displayName": + case "name": context.diagnostics.push(unsupportedProperty(node.name, "function", node.name.text)); } } diff --git a/src/transformation/builtins/global.ts b/src/transformation/builtins/global.ts index 79f359bbd..288414a60 100644 --- a/src/transformation/builtins/global.ts +++ b/src/transformation/builtins/global.ts @@ -4,25 +4,31 @@ import { TransformationContext } from "../context"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { isNumberType } from "../utils/typescript"; import { transformArguments } from "../visitors/call"; +import { transformStringConstructorCall } from "./string"; -export function transformGlobalCall( +export function tryTransformBuiltinGlobalCall( context: TransformationContext, - node: ts.CallExpression + node: ts.CallExpression, + expressionType: ts.Type ): lua.Expression | undefined { - const signature = context.checker.getResolvedSignature(node); - const parameters = transformArguments(context, node.arguments, signature); - const expressionType = context.checker.getTypeAtLocation(node.expression); + function getParameters() { + const signature = context.checker.getResolvedSignature(node); + return transformArguments(context, node.arguments, signature); + } + const name = expressionType.symbol.name; switch (name) { case "SymbolConstructor": - return transformLuaLibFunction(context, LuaLibFeature.Symbol, node, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.Symbol, node, ...getParameters()); case "NumberConstructor": - return transformLuaLibFunction(context, LuaLibFeature.Number, node, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.Number, node, ...getParameters()); + case "StringConstructor": + return transformStringConstructorCall(node, ...getParameters()); case "isNaN": case "isFinite": const numberParameters = isNumberType(context, expressionType) - ? parameters - : [transformLuaLibFunction(context, LuaLibFeature.Number, undefined, ...parameters)]; + ? getParameters() + : [transformLuaLibFunction(context, LuaLibFeature.Number, undefined, ...getParameters())]; return transformLuaLibFunction( context, @@ -31,8 +37,8 @@ export function transformGlobalCall( ...numberParameters ); case "parseFloat": - return transformLuaLibFunction(context, LuaLibFeature.ParseFloat, node, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.ParseFloat, node, ...getParameters()); case "parseInt": - return transformLuaLibFunction(context, LuaLibFeature.ParseInt, node, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.ParseInt, node, ...getParameters()); } } diff --git a/src/transformation/builtins/index.ts b/src/transformation/builtins/index.ts index 6d7f0bd8b..3eefd64c9 100644 --- a/src/transformation/builtins/index.ts +++ b/src/transformation/builtins/index.ts @@ -1,29 +1,24 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; -import { assume } from "../../utils"; import { TransformationContext } from "../context"; import { createNaN } from "../utils/lua-ast"; import { importLuaLibFeature, LuaLibFeature } from "../utils/lualib"; import { getIdentifierSymbolId } from "../utils/symbols"; -import { - hasStandardLibrarySignature, - isArrayType, - isFunctionType, - isNumberType, - isStandardLibraryType, - isStringType, -} from "../utils/typescript"; -import { PropertyCallExpression } from "../visitors/call"; -import { checkForLuaLibType } from "../visitors/class/new"; +import { isStandardLibraryType, isStringType, isArrayType, isFunctionType } from "../utils/typescript"; +import { getCalledExpression } from "../visitors/call"; import { transformArrayConstructorCall, transformArrayProperty, transformArrayPrototypeCall } from "./array"; import { transformConsoleCall } from "./console"; import { transformFunctionPrototypeCall, transformFunctionProperty } from "./function"; -import { transformGlobalCall } from "./global"; +import { tryTransformBuiltinGlobalCall } from "./global"; import { transformMathCall, transformMathProperty } from "./math"; -import { transformNumberConstructorCall, transformNumberPrototypeCall } from "./number"; -import { transformObjectConstructorCall, transformObjectPrototypeCall } from "./object"; -import { transformStringConstructorCall, transformStringProperty, transformStringPrototypeCall } from "./string"; +import { transformNumberConstructorCall, transformNumberPrototypeCall, transformNumberProperty } from "./number"; +import { transformObjectConstructorCall, tryTransformObjectPrototypeCall } from "./object"; +import { transformPromiseConstructorCall } from "./promise"; +import { transformStringConstructorMethodCall, transformStringProperty, transformStringPrototypeCall } from "./string"; import { transformSymbolConstructorCall } from "./symbol"; +import { unsupportedBuiltinOptionalCall } from "../utils/diagnostics"; +import { LuaTarget } from "../../CompilerOptions"; +import { transformMapConstructorCall } from "./map"; export function transformBuiltinPropertyAccessExpression( context: TransformationContext, @@ -31,6 +26,17 @@ export function transformBuiltinPropertyAccessExpression( ): lua.Expression | undefined { const ownerType = context.checker.getTypeAtLocation(node.expression); + if (ts.isIdentifier(node.expression) && isStandardLibraryType(context, ownerType, undefined)) { + switch (ownerType.symbol.name) { + case "NumberConstructor": + return transformNumberProperty(context, node); + case "Math": + return transformMathProperty(context, node); + case "SymbolConstructor": + importLuaLibFeature(context, LuaLibFeature.Symbol); + } + } + if (isStringType(context, ownerType)) { return transformStringProperty(context, node); } @@ -39,18 +45,9 @@ export function transformBuiltinPropertyAccessExpression( return transformArrayProperty(context, node); } - if (isFunctionType(context, ownerType)) { + if (isFunctionType(ownerType)) { return transformFunctionProperty(context, node); } - - if (ts.isIdentifier(node.expression) && isStandardLibraryType(context, ownerType, undefined)) { - switch (node.expression.text) { - case "Math": - return transformMathProperty(context, node); - case "Symbol": - importLuaLibFeature(context, LuaLibFeature.Symbol); - } - } } export function transformBuiltinCallExpression( @@ -59,79 +56,183 @@ export function transformBuiltinCallExpression( ): lua.Expression | undefined { const expressionType = context.checker.getTypeAtLocation(node.expression); if (ts.isIdentifier(node.expression) && isStandardLibraryType(context, expressionType, undefined)) { - // TODO: checkForLuaLibType(context, expressionType); - const result = transformGlobalCall(context, node); - if (result) { - return result; - } + const result = tryTransformBuiltinGlobalCall(context, node, expressionType); + if (result) return result; } - if (!ts.isPropertyAccessExpression(node.expression)) { - return; - } - - assume(node); - - // If the function being called is of type owner.func, get the type of owner - const ownerType = context.checker.getTypeAtLocation(node.expression.expression); - - if (isStandardLibraryType(context, ownerType, undefined)) { - const symbol = ownerType.getSymbol(); - switch (symbol?.name) { - case "ArrayConstructor": - return transformArrayConstructorCall(context, node); - case "Console": - return transformConsoleCall(context, node); - case "Math": - return transformMathCall(context, node); - case "StringConstructor": - return transformStringConstructorCall(context, node); - case "ObjectConstructor": - return transformObjectConstructorCall(context, node); - case "SymbolConstructor": - return transformSymbolConstructorCall(context, node); - case "NumberConstructor": - return transformNumberConstructorCall(context, node); - } - } + const calledMethod = ts.getOriginalNode(getCalledExpression(node)); + if (ts.isPropertyAccessExpression(calledMethod)) { + const globalResult = tryTransformBuiltinGlobalMethodCall(context, node, calledMethod); + if (globalResult) return globalResult; - if (isStringType(context, ownerType) && hasStandardLibrarySignature(context, node)) { - return transformStringPrototypeCall(context, node); - } + const prototypeResult = tryTransformBuiltinPropertyCall(context, node, calledMethod); + if (prototypeResult) return prototypeResult; - if (isNumberType(context, ownerType) && hasStandardLibrarySignature(context, node)) { - return transformNumberPrototypeCall(context, node); + // object prototype call may work even without resolved signature/type (which the other builtin calls use) + // e.g. (foo as any).toString() + // prototype methods take precedence (e.g. number.toString(2)) + const objectResult = tryTransformObjectPrototypeCall(context, node, calledMethod); + if (objectResult) return objectResult; } +} - if (isArrayType(context, ownerType) && hasStandardLibrarySignature(context, node)) { - return transformArrayPrototypeCall(context, node); +function tryTransformBuiltinGlobalMethodCall( + context: TransformationContext, + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +) { + const ownerType = context.checker.getTypeAtLocation(calledMethod.expression); + const ownerSymbol = tryGetStandardLibrarySymbolOfType(context, ownerType); + if (!ownerSymbol || ownerSymbol.parent) return; + + let result: lua.Expression | undefined; + switch (ownerSymbol.name) { + case "ArrayConstructor": + result = transformArrayConstructorCall(context, node, calledMethod); + break; + case "Console": + result = transformConsoleCall(context, node, calledMethod); + break; + case "MapConstructor": + result = transformMapConstructorCall(context, node, calledMethod); + break; + case "Math": + result = transformMathCall(context, node, calledMethod); + break; + case "StringConstructor": + result = transformStringConstructorMethodCall(context, node, calledMethod); + break; + case "ObjectConstructor": + result = transformObjectConstructorCall(context, node, calledMethod); + break; + case "SymbolConstructor": + result = transformSymbolConstructorCall(context, node, calledMethod); + break; + case "NumberConstructor": + result = transformNumberConstructorCall(context, node, calledMethod); + break; + case "PromiseConstructor": + result = transformPromiseConstructorCall(context, node, calledMethod); + break; } - - if (isFunctionType(context, ownerType) && hasStandardLibrarySignature(context, node)) { - return transformFunctionPrototypeCall(context, node); + if (result && calledMethod.questionDotToken) { + // e.g. console?.log() + context.diagnostics.push(unsupportedBuiltinOptionalCall(calledMethod)); } + return result; +} - const objectResult = transformObjectPrototypeCall(context, node); - if (objectResult) { - return objectResult; +function tryTransformBuiltinPropertyCall( + context: TransformationContext, + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +) { + const functionType = context.checker.getTypeAtLocation(node.expression); + const callSymbol = tryGetStandardLibrarySymbolOfType(context, functionType); + if (!callSymbol) return; + const ownerSymbol = callSymbol.parent; + if (!ownerSymbol || ownerSymbol.parent) return; + + switch (ownerSymbol.name) { + case "String": + return transformStringPrototypeCall(context, node, calledMethod); + case "Number": + return transformNumberPrototypeCall(context, node, calledMethod); + case "Array": + case "ReadonlyArray": + return transformArrayPrototypeCall(context, node, calledMethod); + case "Function": + case "CallableFunction": + case "NewableFunction": + return transformFunctionPrototypeCall(context, node, calledMethod); } } export function transformBuiltinIdentifierExpression( context: TransformationContext, - node: ts.Identifier + node: ts.Identifier, + symbol: ts.Symbol | undefined ): lua.Expression | undefined { switch (node.text) { case "NaN": return createNaN(node); case "Infinity": - const math = lua.createIdentifier("math"); - const huge = lua.createStringLiteral("huge"); - return lua.createTableIndexExpression(math, huge, node); - + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createTableIndexExpression(math, huge, node); + } case "globalThis": - return lua.createIdentifier("_G", node, getIdentifierSymbolId(context, node), "globalThis"); + return lua.createIdentifier("_G", node, getIdentifierSymbolId(context, node, symbol), "globalThis"); } } + +const builtinErrorTypeNames = new Set([ + "Error", + "ErrorConstructor", + "RangeError", + "RangeErrorConstructor", + "ReferenceError", + "ReferenceErrorConstructor", + "SyntaxError", + "SyntaxErrorConstructor", + "TypeError", + "TypeErrorConstructor", + "URIError", + "URIErrorConstructor", +]); + +export function checkForLuaLibType(context: TransformationContext, type: ts.Type): void { + const symbol = type.symbol; + if (!symbol || symbol.parent) return; + const name = symbol.name; + + switch (name) { + case "Map": + case "MapConstructor": + importLuaLibFeature(context, LuaLibFeature.Map); + return; + case "Set": + case "SetConstructor": + importLuaLibFeature(context, LuaLibFeature.Set); + return; + case "WeakMap": + case "WeakMapConstructor": + importLuaLibFeature(context, LuaLibFeature.WeakMap); + return; + case "WeakSet": + case "WeakSetConstructor": + importLuaLibFeature(context, LuaLibFeature.WeakSet); + return; + case "Promise": + case "PromiseConstructor": + importLuaLibFeature(context, LuaLibFeature.Promise); + return; + } + + if (builtinErrorTypeNames.has(name)) { + importLuaLibFeature(context, LuaLibFeature.Error); + } +} + +export function tryGetStandardLibrarySymbolOfType( + context: TransformationContext, + type: ts.Type +): ts.Symbol | undefined { + if (type.isUnionOrIntersection()) { + for (const subType of type.types) { + const symbol = tryGetStandardLibrarySymbolOfType(context, subType); + if (symbol) return symbol; + } + } else if (isStandardLibraryType(context, type, undefined)) { + return type.symbol; + } + + return undefined; +} diff --git a/src/transformation/builtins/map.ts b/src/transformation/builtins/map.ts new file mode 100644 index 000000000..556578591 --- /dev/null +++ b/src/transformation/builtins/map.ts @@ -0,0 +1,22 @@ +import * as lua from "../../LuaAST"; +import * as ts from "typescript"; +import { TransformationContext } from "../context"; +import { unsupportedProperty } from "../utils/diagnostics"; +import { transformArguments } from "../visitors/call"; +import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; + +export function transformMapConstructorCall( + context: TransformationContext, + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +): lua.Expression | undefined { + const args = transformArguments(context, node.arguments); + const methodName = calledMethod.name.text; + + switch (methodName) { + case "groupBy": + return transformLuaLibFunction(context, LuaLibFeature.MapGroupBy, node, ...args); + default: + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Map", methodName)); + } +} diff --git a/src/transformation/builtins/math.ts b/src/transformation/builtins/math.ts index af742214f..82a118ec1 100644 --- a/src/transformation/builtins/math.ts +++ b/src/transformation/builtins/math.ts @@ -4,7 +4,7 @@ import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments } from "../visitors/call"; export function transformMathProperty( context: TransformationContext, @@ -33,23 +33,29 @@ export function transformMathProperty( export function transformMathCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); const math = lua.createIdentifier("math"); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { - // Lua 5.3: math.atan(y, x) + // Lua 5.3+: math.atan(y, x) // Otherwise: math.atan2(y, x) case "atan2": { if (context.luaTarget === LuaTarget.Universal) { return transformLuaLibFunction(context, LuaLibFeature.MathAtan2, node, ...params); } - const method = lua.createStringLiteral(context.luaTarget === LuaTarget.Lua53 ? "atan" : "atan2"); + const useAtan2 = + context.luaTarget === LuaTarget.Lua50 || + context.luaTarget === LuaTarget.Lua51 || + context.luaTarget === LuaTarget.Lua52 || + context.luaTarget === LuaTarget.LuaJIT || + context.luaTarget === LuaTarget.Luau; + const method = lua.createStringLiteral(useAtan2 ? "atan2" : "atan"); return lua.createCallExpression(lua.createTableIndexExpression(math, method), params, node); } @@ -66,18 +72,44 @@ export function transformMathCall( case "log1p": { const log = lua.createStringLiteral("log"); const one = lua.createNumericLiteral(1); - const add = lua.createBinaryExpression(one, params[0], lua.SyntaxKind.AdditionOperator); + const add = lua.createBinaryExpression( + one, + params[0] ?? lua.createNilLiteral(), + lua.SyntaxKind.AdditionOperator + ); return lua.createCallExpression(lua.createTableIndexExpression(math, log), [add], node); } + case "pow": { + // Translate to base ^ power + return lua.createBinaryExpression( + params[0] ?? lua.createNilLiteral(), + params[1] ?? lua.createNilLiteral(), + lua.SyntaxKind.PowerOperator, + node + ); + } + // math.floor(x + 0.5) case "round": { const floor = lua.createStringLiteral("floor"); const half = lua.createNumericLiteral(0.5); - const add = lua.createBinaryExpression(params[0], half, lua.SyntaxKind.AdditionOperator); + const add = lua.createBinaryExpression( + params[0] ?? lua.createNilLiteral(), + half, + lua.SyntaxKind.AdditionOperator + ); return lua.createCallExpression(lua.createTableIndexExpression(math, floor), [add], node); } + case "sign": { + return transformLuaLibFunction(context, LuaLibFeature.MathSign, node, ...params); + } + + case "trunc": { + return transformLuaLibFunction(context, LuaLibFeature.MathTrunc, node, ...params); + } + case "abs": case "acos": case "asin": @@ -89,7 +121,6 @@ export function transformMathCall( case "log": case "max": case "min": - case "pow": case "random": case "sin": case "sqrt": @@ -99,6 +130,6 @@ export function transformMathCall( } default: - context.diagnostics.push(unsupportedProperty(expression.name, "Math", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Math", expressionName)); } } diff --git a/src/transformation/builtins/number.ts b/src/transformation/builtins/number.ts index 227d82b23..ecb98da64 100644 --- a/src/transformation/builtins/number.ts +++ b/src/transformation/builtins/number.ts @@ -1,42 +1,165 @@ +import ts = require("typescript"); import * as lua from "../../LuaAST"; +import { createNaN } from "../utils/lua-ast"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments } from "../visitors/call"; +import { LuaTarget } from "../../CompilerOptions"; export function transformNumberPrototypeCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); - const caller = context.transformExpression(expression.expression); + const caller = context.transformExpression(calledMethod.expression); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { case "toString": return params.length === 0 ? lua.createCallExpression(lua.createIdentifier("tostring"), [caller], node) : transformLuaLibFunction(context, LuaLibFeature.NumberToString, node, caller, ...params); + case "toFixed": + return transformLuaLibFunction(context, LuaLibFeature.NumberToFixed, node, caller, ...params); default: - context.diagnostics.push(unsupportedProperty(expression.name, "number", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "number", expressionName)); + } +} + +export function transformNumberProperty( + context: TransformationContext, + node: ts.PropertyAccessExpression +): lua.Expression | undefined { + const name = node.name.text; + + /* + Read the docs on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number for further info about what these numbers entail. + Most of them should be fairly straight forward base on their name(s) though. + */ + + switch (name) { + case "POSITIVE_INFINITY": + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createTableIndexExpression(math, huge, node); + } + case "NEGATIVE_INFINITY": + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createUnaryExpression( + lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator), + lua.SyntaxKind.NegationOperator + ); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createUnaryExpression( + lua.createTableIndexExpression(math, huge, node), + lua.SyntaxKind.NegationOperator + ); + } + case "NaN": + return createNaN(node); + case "EPSILON": + return lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(-52), + lua.SyntaxKind.PowerOperator, + node + ); + case "MIN_VALUE": + // 2 ^ -1074 = 5e-324 (smallest positive double) + return lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(-1074), + lua.SyntaxKind.PowerOperator, + node + ); + case "MIN_SAFE_INTEGER": + // -(2 ^ 53 - 1) = -9007199254740991 + return lua.createUnaryExpression( + lua.createParenthesizedExpression( + lua.createBinaryExpression( + lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(53), + lua.SyntaxKind.PowerOperator + ), + lua.createNumericLiteral(1), + lua.SyntaxKind.SubtractionOperator + ) + ), + lua.SyntaxKind.NegationOperator, + node + ); + case "MAX_SAFE_INTEGER": + // 2 ^ 53 - 1 = 9007199254740991 + return lua.createBinaryExpression( + lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(53), + lua.SyntaxKind.PowerOperator + ), + lua.createNumericLiteral(1), + lua.SyntaxKind.SubtractionOperator, + node + ); + case "MAX_VALUE": + // (2 - 2 ^ -52) * 2 ^ 1023 = 1.7976931348623157e+308 + return lua.createBinaryExpression( + lua.createParenthesizedExpression( + lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(-52), + lua.SyntaxKind.PowerOperator + ), + lua.SyntaxKind.SubtractionOperator + ) + ), + lua.createBinaryExpression( + lua.createNumericLiteral(2), + lua.createNumericLiteral(1023), + lua.SyntaxKind.PowerOperator + ), + lua.SyntaxKind.MultiplicationOperator, + node + ); + + default: + context.diagnostics.push(unsupportedProperty(node.name, "Number", name)); } } export function transformNumberConstructorCall( context: TransformationContext, - expression: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.CallExpression | undefined { - const method = expression.expression; - const parameters = transformArguments(context, expression.arguments); - const methodName = method.name.text; + const parameters = transformArguments(context, node.arguments); + const methodName = calledMethod.name.text; switch (methodName) { + case "isInteger": + return transformLuaLibFunction(context, LuaLibFeature.NumberIsInteger, node, ...parameters); case "isNaN": - return transformLuaLibFunction(context, LuaLibFeature.NumberIsNaN, expression, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.NumberIsNaN, node, ...parameters); case "isFinite": - return transformLuaLibFunction(context, LuaLibFeature.NumberIsFinite, expression, ...parameters); + return transformLuaLibFunction(context, LuaLibFeature.NumberIsFinite, node, ...parameters); + case "parseInt": + return transformLuaLibFunction(context, LuaLibFeature.NumberParseInt, node, ...parameters); + case "parseFloat": + return transformLuaLibFunction(context, LuaLibFeature.NumberParseFloat, node, ...parameters); default: - context.diagnostics.push(unsupportedProperty(method.name, "Number", methodName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Number", methodName)); } } diff --git a/src/transformation/builtins/object.ts b/src/transformation/builtins/object.ts index 2db793f91..43dd8a165 100644 --- a/src/transformation/builtins/object.ts +++ b/src/transformation/builtins/object.ts @@ -1,57 +1,59 @@ import * as lua from "../../LuaAST"; +import * as ts from "typescript"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments } from "../visitors/call"; export function transformObjectConstructorCall( context: TransformationContext, - expression: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const method = expression.expression; - const args = transformArguments(context, expression.arguments); - const methodName = method.name.text; + const args = transformArguments(context, node.arguments); + const methodName = calledMethod.name.text; switch (methodName) { case "assign": - return transformLuaLibFunction(context, LuaLibFeature.ObjectAssign, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectAssign, node, ...args); case "defineProperty": - return transformLuaLibFunction(context, LuaLibFeature.ObjectDefineProperty, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectDefineProperty, node, ...args); case "entries": - return transformLuaLibFunction(context, LuaLibFeature.ObjectEntries, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectEntries, node, ...args); case "fromEntries": - return transformLuaLibFunction(context, LuaLibFeature.ObjectFromEntries, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectFromEntries, node, ...args); case "getOwnPropertyDescriptor": - return transformLuaLibFunction(context, LuaLibFeature.ObjectGetOwnPropertyDescriptor, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectGetOwnPropertyDescriptor, node, ...args); case "getOwnPropertyDescriptors": - return transformLuaLibFunction(context, LuaLibFeature.ObjectGetOwnPropertyDescriptors, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectGetOwnPropertyDescriptors, node, ...args); + case "groupBy": + return transformLuaLibFunction(context, LuaLibFeature.ObjectGroupBy, node, ...args); case "keys": - return transformLuaLibFunction(context, LuaLibFeature.ObjectKeys, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectKeys, node, ...args); case "values": - return transformLuaLibFunction(context, LuaLibFeature.ObjectValues, expression, ...args); + return transformLuaLibFunction(context, LuaLibFeature.ObjectValues, node, ...args); default: - context.diagnostics.push(unsupportedProperty(method.name, "Object", methodName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Object", methodName)); } } -export function transformObjectPrototypeCall( +export function tryTransformObjectPrototypeCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const expression = node.expression; - const signature = context.checker.getResolvedSignature(node); - - const name = expression.name.text; + const name = calledMethod.name.text; switch (name) { case "toString": const toStringIdentifier = lua.createIdentifier("tostring"); return lua.createCallExpression( toStringIdentifier, - [context.transformExpression(expression.expression)], + [context.transformExpression(calledMethod.expression)], node ); case "hasOwnProperty": - const expr = context.transformExpression(expression.expression); + const expr = context.transformExpression(calledMethod.expression); + const signature = context.checker.getResolvedSignature(node); const parameters = transformArguments(context, node.arguments, signature); const rawGetIdentifier = lua.createIdentifier("rawget"); const rawGetCall = lua.createCallExpression(rawGetIdentifier, [expr, ...parameters]); diff --git a/src/transformation/builtins/promise.ts b/src/transformation/builtins/promise.ts new file mode 100644 index 000000000..19c7284e7 --- /dev/null +++ b/src/transformation/builtins/promise.ts @@ -0,0 +1,54 @@ +import * as ts from "typescript"; +import * as lua from "../../LuaAST"; +import { TransformationContext } from "../context"; +import { unsupportedProperty } from "../utils/diagnostics"; +import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; +import { transformArguments } from "../visitors/call"; +import { isStandardLibraryType } from "../utils/typescript"; + +export function isPromiseClass(context: TransformationContext, node: ts.Identifier) { + if (node.text !== "Promise") return false; + const type = context.checker.getTypeAtLocation(node); + return isStandardLibraryType(context, type, undefined); +} + +export function createPromiseIdentifier(original: ts.Node) { + return lua.createIdentifier("__TS__Promise", original); +} + +export function transformPromiseConstructorCall( + context: TransformationContext, + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +): lua.Expression | undefined { + const signature = context.checker.getResolvedSignature(node); + const params = transformArguments(context, node.arguments, signature); + + const expressionName = calledMethod.name.text; + switch (expressionName) { + case "all": + return transformLuaLibFunction(context, LuaLibFeature.PromiseAll, node, ...params); + case "allSettled": + return transformLuaLibFunction(context, LuaLibFeature.PromiseAllSettled, node, ...params); + case "any": + return transformLuaLibFunction(context, LuaLibFeature.PromiseAny, node, ...params); + case "race": + return transformLuaLibFunction(context, LuaLibFeature.PromiseRace, node, ...params); + case "resolve": + importLuaLibFeature(context, LuaLibFeature.Promise); + return lua.createCallExpression(createStaticPromiseFunctionAccessor("resolve", calledMethod), params, node); + case "reject": + importLuaLibFeature(context, LuaLibFeature.Promise); + return lua.createCallExpression(createStaticPromiseFunctionAccessor("reject", calledMethod), params, node); + default: + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Promise", expressionName)); + } +} + +export function createStaticPromiseFunctionAccessor(functionName: string, node: ts.Node) { + return lua.createTableIndexExpression( + lua.createIdentifier("__TS__Promise"), + lua.createStringLiteral(functionName), + node + ); +} diff --git a/src/transformation/builtins/string.ts b/src/transformation/builtins/string.ts index 4cb21ea93..98bd62303 100644 --- a/src/transformation/builtins/string.ts +++ b/src/transformation/builtins/string.ts @@ -1,10 +1,11 @@ import * as ts from "typescript"; +import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; -import { addToNumericExpression, createNaN, getNumberLiteralValue } from "../utils/lua-ast"; +import { addToNumericExpression, createNaN, getNumberLiteralValue, wrapInTable } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments, transformCallAndArguments } from "../visitors/call"; function createStringCall(methodName: string, tsOriginal: ts.Node, ...params: lua.Expression[]): lua.CallExpression { const stringIdentifier = lua.createIdentifier("string"); @@ -17,26 +18,31 @@ function createStringCall(methodName: string, tsOriginal: ts.Node, ...params: lu export function transformStringPrototypeCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const expression = node.expression; const signature = context.checker.getResolvedSignature(node); - const params = transformArguments(context, node.arguments, signature); - const caller = context.transformExpression(expression.expression); + const [caller, params] = transformCallAndArguments(context, calledMethod.expression, node.arguments, signature); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { case "replace": return transformLuaLibFunction(context, LuaLibFeature.StringReplace, node, caller, ...params); + case "replaceAll": + return transformLuaLibFunction(context, LuaLibFeature.StringReplaceAll, node, caller, ...params); case "concat": - return transformLuaLibFunction(context, LuaLibFeature.StringConcat, node, caller, ...params); + return lua.createCallExpression( + lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("concat")), + [wrapInTable(caller, ...params)], + node + ); case "indexOf": { const stringExpression = createStringCall( "find", node, caller, - params[0], + params[0] ?? lua.createNilLiteral(), params[1] ? // string.find handles negative indexes by making it relative to string end, but for indexOf it's the same as 0 lua.createCallExpression( @@ -104,7 +110,7 @@ export function transformStringPrototypeCall( const literalValue = getNumberLiteralValue(params[0]); // Inline string.sub call if we know that parameter is pure and isn't negative if (literalValue !== undefined && literalValue >= 0) { - const firstParamPlusOne = addToNumericExpression(params[0], 1); + const firstParamPlusOne = addToNumericExpression(params[0] ?? lua.createNilLiteral(), 1); return createStringCall("sub", node, caller, firstParamPlusOne, firstParamPlusOne); } @@ -116,7 +122,12 @@ export function transformStringPrototypeCall( // Inline string.sub call if we know that parameter is pure and isn't negative if (literalValue !== undefined && literalValue >= 0) { return lua.createBinaryExpression( - createStringCall("byte", node, caller, addToNumericExpression(params[0], 1)), + createStringCall( + "byte", + node, + caller, + addToNumericExpression(params[0] ?? lua.createNilLiteral(), 1) + ), createNaN(), lua.SyntaxKind.OrOperator ); @@ -134,26 +145,30 @@ export function transformStringPrototypeCall( case "repeat": const math = lua.createIdentifier("math"); const floor = lua.createStringLiteral("floor"); - const parameter = lua.createCallExpression(lua.createTableIndexExpression(math, floor), [params[0]]); + const parameter = lua.createCallExpression(lua.createTableIndexExpression(math, floor), [ + params[0] ?? lua.createNilLiteral(), + ]); return createStringCall("rep", node, caller, parameter); case "padStart": return transformLuaLibFunction(context, LuaLibFeature.StringPadStart, node, caller, ...params); case "padEnd": return transformLuaLibFunction(context, LuaLibFeature.StringPadEnd, node, caller, ...params); + case "toString": + return; // will be handled by transformObjectPrototypeCall default: - context.diagnostics.push(unsupportedProperty(expression.name, "string", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "string", expressionName)); } } -export function transformStringConstructorCall( +export function transformStringConstructorMethodCall( context: TransformationContext, - node: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.Expression | undefined { - const expression = node.expression; const signature = context.checker.getResolvedSignature(node); const params = transformArguments(context, node.arguments, signature); - const expressionName = expression.name.text; + const expressionName = calledMethod.name.text; switch (expressionName) { case "fromCharCode": return lua.createCallExpression( @@ -163,19 +178,35 @@ export function transformStringConstructorCall( ); default: - context.diagnostics.push(unsupportedProperty(expression.name, "String", expressionName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "String", expressionName)); } } export function transformStringProperty( context: TransformationContext, node: ts.PropertyAccessExpression -): lua.UnaryExpression | undefined { +): lua.Expression | undefined { switch (node.name.text) { case "length": const expression = context.transformExpression(node.expression); - return lua.createUnaryExpression(expression, lua.SyntaxKind.LengthOperator, node); + if (context.luaTarget === LuaTarget.Lua50) { + const stringLen = lua.createTableIndexExpression( + lua.createIdentifier("string"), + lua.createStringLiteral("len") + ); + return lua.createCallExpression(stringLen, [expression], node); + } else { + return lua.createUnaryExpression(expression, lua.SyntaxKind.LengthOperator, node); + } default: context.diagnostics.push(unsupportedProperty(node.name, "string", node.name.text)); } } + +export function transformStringConstructorCall( + originalNode: ts.CallExpression, + ...args: lua.Expression[] +): lua.Expression | undefined { + const tostring = lua.createIdentifier("tostring", originalNode.expression); + return lua.createCallExpression(tostring, args, originalNode); +} diff --git a/src/transformation/builtins/symbol.ts b/src/transformation/builtins/symbol.ts index 04329e059..4c5b7cbde 100644 --- a/src/transformation/builtins/symbol.ts +++ b/src/transformation/builtins/symbol.ts @@ -1,25 +1,26 @@ +import ts = require("typescript"); import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; import { unsupportedProperty } from "../utils/diagnostics"; import { importLuaLibFeature, LuaLibFeature } from "../utils/lualib"; -import { PropertyCallExpression, transformArguments } from "../visitors/call"; +import { transformArguments } from "../visitors/call"; export function transformSymbolConstructorCall( context: TransformationContext, - expression: PropertyCallExpression + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression ): lua.CallExpression | undefined { - const method = expression.expression; - const signature = context.checker.getResolvedSignature(expression); - const parameters = transformArguments(context, expression.arguments, signature); - const methodName = method.name.text; + const signature = context.checker.getResolvedSignature(node); + const parameters = transformArguments(context, node.arguments, signature); + const methodName = calledMethod.name.text; switch (methodName) { case "for": case "keyFor": importLuaLibFeature(context, LuaLibFeature.SymbolRegistry); const upperMethodName = methodName[0].toUpperCase() + methodName.slice(1); const functionIdentifier = lua.createIdentifier(`__TS__SymbolRegistry${upperMethodName}`); - return lua.createCallExpression(functionIdentifier, parameters, expression); + return lua.createCallExpression(functionIdentifier, parameters, node); default: - context.diagnostics.push(unsupportedProperty(method.name, "Symbol", methodName)); + context.diagnostics.push(unsupportedProperty(calledMethod.name, "Symbol", methodName)); } } diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 4dbcf9e10..ad40d48c5 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -1,14 +1,20 @@ import * as ts from "typescript"; import { CompilerOptions, LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; -import { castArray } from "../../utils"; +import { assert, castArray } from "../../utils"; import { unsupportedNodeKind } from "../utils/diagnostics"; -import { unwrapVisitorResult } from "../utils/lua-ast"; -import { ExpressionLikeNode, ObjectVisitor, StatementLikeNode, VisitorMap } from "./visitors"; +import { unwrapVisitorResult, OneToManyVisitorResult } from "../utils/lua-ast"; +import { createSafeName } from "../utils/safe-names"; +import { ExpressionLikeNode, StatementLikeNode, VisitorMap, FunctionVisitor } from "./visitors"; +import { SymbolInfo } from "../utils/symbols"; +import { LuaLibFeature } from "../../LuaLib"; +import { Scope, ScopeType } from "../utils/scope"; +import { ClassSuperInfo } from "../visitors/class"; + +export const tempSymbolId = -1 as lua.SymbolId; export interface AllAccessorDeclarations { firstAccessor: ts.AccessorDeclaration; - secondAccessor: ts.AccessorDeclaration | undefined; getAccessor: ts.GetAccessorDeclaration | undefined; setAccessor: ts.SetAccessorDeclaration | undefined; } @@ -17,23 +23,23 @@ export interface EmitResolver { isValueAliasDeclaration(node: ts.Node): boolean; isReferencedAliasDeclaration(node: ts.Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ts.ImportEqualsDeclaration): boolean; - moduleExportsSomeValue(moduleReferenceExpression: ts.Expression): boolean; - getAllAccessorDeclarations(declaration: ts.AccessorDeclaration): AllAccessorDeclarations; } -export interface DiagnosticsProducingTypeChecker extends ts.TypeChecker { +export interface TypeCheckerWithEmitResolver extends ts.TypeChecker { getEmitResolver(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): EmitResolver; } export class TransformationContext { public readonly diagnostics: ts.Diagnostic[] = []; - public readonly checker: DiagnosticsProducingTypeChecker = this.program.getDiagnosticsProducingTypeChecker(); + public readonly checker = this.program.getTypeChecker() as TypeCheckerWithEmitResolver; public readonly resolver: EmitResolver; + public readonly precedingStatementsStack: lua.Statement[][] = []; public readonly options: CompilerOptions = this.program.getCompilerOptions(); public readonly luaTarget = this.options.luaTarget ?? LuaTarget.Universal; public readonly isModule = ts.isExternalModule(this.sourceFile); public readonly isStrict = + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (this.options.alwaysStrict ?? this.options.strict) || (this.isModule && this.options.target !== undefined && this.options.target >= ts.ScriptTarget.ES2015); @@ -45,69 +51,219 @@ export class TransformationContext { this.resolver = this.checker.getEmitResolver(originalSourceFile); } - private currentNodeVisitors: Array> = []; + private currentNodeVisitors: ReadonlyArray> = []; + private currentNodeVisitorsIndex = 0; + + private nextTempId = 0; + + public transformNode(node: ts.Node): lua.Node[] { + return unwrapVisitorResult(this.transformNodeRaw(node)); + } - public transformNode(node: ts.Node): lua.Node[]; /** @internal */ - // eslint-disable-next-line @typescript-eslint/unified-signatures - public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[]; - public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[] { + public transformNodeRaw(node: ts.Node, isExpression?: boolean) { // TODO: Move to visitors? - if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword)) { + if ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword) + ) { return []; } const nodeVisitors = this.visitorMap.get(node.kind); - if (!nodeVisitors || nodeVisitors.length === 0) { + if (!nodeVisitors) { this.diagnostics.push(unsupportedNodeKind(node, node.kind)); return isExpression ? [lua.createNilLiteral()] : []; } const previousNodeVisitors = this.currentNodeVisitors; - this.currentNodeVisitors = [...nodeVisitors]; + const previousNodeVisitorsIndex = this.currentNodeVisitorsIndex; + this.currentNodeVisitors = nodeVisitors; + this.currentNodeVisitorsIndex = nodeVisitors.length - 1; - const visitor = this.currentNodeVisitors.pop()!; - const result = unwrapVisitorResult(visitor.transform(node, this)); + const visitor = this.currentNodeVisitors[this.currentNodeVisitorsIndex]; + const result = visitor(node, this); this.currentNodeVisitors = previousNodeVisitors; + this.currentNodeVisitorsIndex = previousNodeVisitorsIndex; return result; } public superTransformNode(node: ts.Node): lua.Node[] { - if (this.currentNodeVisitors.length === 0) { + return unwrapVisitorResult(this.doSuperTransformNode(node)); + } + + private doSuperTransformNode(node: ts.Node): OneToManyVisitorResult { + if (--this.currentNodeVisitorsIndex < 0) { throw new Error(`There is no super transform for ${ts.SyntaxKind[node.kind]} visitor`); } - const visitor = this.currentNodeVisitors.pop()!; - return unwrapVisitorResult(visitor.transform(node, this)); + const visitor = this.currentNodeVisitors[this.currentNodeVisitorsIndex]; + return unwrapVisitorResult(visitor(node, this)); } public transformExpression(node: ExpressionLikeNode): lua.Expression { - const [result] = this.transformNode(node, true); + const result = this.transformNodeRaw(node, true); + return this.assertIsExpression(node, result); + } + private assertIsExpression(node: ExpressionLikeNode, result: OneToManyVisitorResult): lua.Expression { if (result === undefined) { throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`); } - + if (Array.isArray(result)) { + return result[0] as lua.Expression; + } return result as lua.Expression; } public superTransformExpression(node: ExpressionLikeNode): lua.Expression { - const [result] = this.superTransformNode(node); + const result = this.doSuperTransformNode(node); + return this.assertIsExpression(node, result); + } - if (result === undefined) { - throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`); + public transformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] { + return castArray(node).flatMap(n => { + this.pushPrecedingStatements(); + const statements = this.transformNode(n) as lua.Statement[]; + const result = this.popPrecedingStatements(); + result.push(...statements); + return result; + }); + } + + public superTransformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] { + return castArray(node).flatMap(n => { + this.pushPrecedingStatements(); + const statements = this.superTransformNode(n) as lua.Statement[]; + const result = this.popPrecedingStatements(); + result.push(...statements); + return result; + }); + } + + public pushPrecedingStatements() { + this.precedingStatementsStack.push([]); + } + + public popPrecedingStatements() { + const precedingStatements = this.precedingStatementsStack.pop(); + assert(precedingStatements); + return precedingStatements; + } + + public addPrecedingStatements(statements: lua.Statement | lua.Statement[]) { + const precedingStatements = this.precedingStatementsStack[this.precedingStatementsStack.length - 1]; + assert(precedingStatements); + if (Array.isArray(statements)) { + precedingStatements.push(...statements); + } else { + precedingStatements.push(statements); } + } - return result as lua.Expression; + public prependPrecedingStatements(statements: lua.Statement | lua.Statement[]) { + const precedingStatements = this.precedingStatementsStack[this.precedingStatementsStack.length - 1]; + assert(precedingStatements); + if (Array.isArray(statements)) { + precedingStatements.unshift(...statements); + } else { + precedingStatements.unshift(statements); + } } - public transformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] { - return castArray(node).flatMap(n => this.transformNode(n) as lua.Statement[]); + public createTempName(prefix = "temp") { + prefix = prefix.replace(/^_*/, ""); // Strip leading underscores because createSafeName will add them again + return createSafeName(`${prefix}_${this.nextTempId++}`); } - public superTransformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] { - return castArray(node).flatMap(n => this.superTransformNode(n) as lua.Statement[]); + private getTempNameForLuaExpression(expression: lua.Expression): string | undefined { + if (lua.isStringLiteral(expression)) { + return expression.value; + } else if (lua.isNumericLiteral(expression)) { + return `_${expression.value.toString()}`; + } else if (lua.isIdentifier(expression)) { + return expression.text; + } else if (lua.isCallExpression(expression)) { + const name = this.getTempNameForLuaExpression(expression.expression); + if (name) { + return `${name}_result`; + } + } else if (lua.isTableIndexExpression(expression)) { + const tableName = this.getTempNameForLuaExpression(expression.table); + const indexName = this.getTempNameForLuaExpression(expression.index); + if (tableName || indexName) { + return `${tableName ?? "table"}_${indexName ?? "index"}`; + } + } + } + + public createTempNameForLuaExpression(expression: lua.Expression) { + const name = this.getTempNameForLuaExpression(expression); + const identifier = lua.createIdentifier(this.createTempName(name), undefined, tempSymbolId); + lua.setNodePosition(identifier, lua.getOriginalPos(expression)); + return identifier; + } + + private getTempNameForNode(node: ts.Node): string | undefined { + if (ts.isStringLiteral(node) || ts.isIdentifier(node) || ts.isMemberName(node)) { + return node.text; + } else if (ts.isNumericLiteral(node)) { + return `_${node.text}`; + } else if (ts.isCallExpression(node)) { + const name = this.getTempNameForNode(node.expression); + if (name) { + return `${name}_result`; + } + } else if (ts.isElementAccessExpression(node) || ts.isPropertyAccessExpression(node)) { + const tableName = this.getTempNameForNode(node.expression); + const indexName = ts.isElementAccessExpression(node) + ? this.getTempNameForNode(node.argumentExpression) + : node.name.text; + if (tableName || indexName) { + return `${tableName ?? "table"}_${indexName ?? "index"}`; + } + } + } + + public createTempNameForNode(node: ts.Node) { + const name = this.getTempNameForNode(node); + return lua.createIdentifier(this.createTempName(name), node, tempSymbolId); + } + + // other utils + + private lastSymbolId = 0; + public readonly symbolInfoMap = new Map(); + public readonly symbolIdMaps = new Map(); + + public nextSymbolId(): lua.SymbolId { + return ++this.lastSymbolId as lua.SymbolId; + } + + public readonly usedLuaLibFeatures = new Set(); + + public readonly scopeStack: Scope[] = []; + private lastScopeId = 0; + + public pushScope(type: ScopeType, node: ts.Node): Scope { + const scope: Scope = { type, id: ++this.lastScopeId, node }; + this.scopeStack.push(scope); + return scope; } + + public popScope(): Scope { + const scope = this.scopeStack.pop(); + assert(scope); + return scope; + } + + // Static context -> namespace dictionary keeping the current namespace for each transformation context + // see visitors/namespace.ts + /** @internal */ + public currentNamespaces: ts.ModuleDeclaration | undefined; + + /** @internal */ + public classSuperInfos: ClassSuperInfo[] = []; } diff --git a/src/transformation/context/visitors.ts b/src/transformation/context/visitors.ts index df7cd7acb..429cce1b4 100644 --- a/src/transformation/context/visitors.ts +++ b/src/transformation/context/visitors.ts @@ -61,6 +61,7 @@ interface NodesBySyntaxKind { [ts.SyntaxKind.AsExpression]: ts.AsExpression; [ts.SyntaxKind.NonNullExpression]: ts.NonNullExpression; [ts.SyntaxKind.MetaProperty]: ts.MetaProperty; + [ts.SyntaxKind.SatisfiesExpression]: ts.SatisfiesExpression; [ts.SyntaxKind.TemplateSpan]: ts.TemplateSpan; [ts.SyntaxKind.SemicolonClassElement]: ts.SemicolonClassElement; [ts.SyntaxKind.Block]: ts.Block; @@ -148,6 +149,7 @@ export type VisitorResult = T extends ExpressionLikeNode export type Visitor = FunctionVisitor | ObjectVisitor; export type FunctionVisitor = (node: T, context: TransformationContext) => VisitorResult; + export interface ObjectVisitor { transform: FunctionVisitor; @@ -162,4 +164,4 @@ export interface ObjectVisitor { } export type Visitors = { [P in keyof NodesBySyntaxKind]?: Visitor }; -export type VisitorMap = Map>>; +export type VisitorMap = Map>>; diff --git a/src/transformation/index.ts b/src/transformation/index.ts index 5b6fca647..b9e1f6241 100644 --- a/src/transformation/index.ts +++ b/src/transformation/index.ts @@ -3,16 +3,17 @@ import * as lua from "../LuaAST"; import { getOrUpdate } from "../utils"; import { ObjectVisitor, TransformationContext, VisitorMap, Visitors } from "./context"; import { standardVisitors } from "./visitors"; +import { usingTransformer } from "./pre-transformers/using-transformer"; export function createVisitorMap(customVisitors: Visitors[]): VisitorMap { - const visitorMap: VisitorMap = new Map(); + const objectVisitorMap: Map>> = new Map(); for (const visitors of [standardVisitors, ...customVisitors]) { const priority = visitors === standardVisitors ? -Infinity : 0; for (const [syntaxKindKey, visitor] of Object.entries(visitors)) { if (!visitor) continue; const syntaxKind = Number(syntaxKindKey) as ts.SyntaxKind; - const nodeVisitors = getOrUpdate(visitorMap, syntaxKind, () => []); + const nodeVisitors = getOrUpdate(objectVisitorMap, syntaxKind, () => []); const objectVisitor: ObjectVisitor = typeof visitor === "function" ? { transform: visitor, priority } : visitor; @@ -20,16 +21,25 @@ export function createVisitorMap(customVisitors: Visitors[]): VisitorMap { } } - for (const nodeVisitors of visitorMap.values()) { - nodeVisitors.sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)); + const result: VisitorMap = new Map(); + for (const [kind, nodeVisitors] of objectVisitorMap) { + result.set( + kind, + nodeVisitors.sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)).map(visitor => visitor.transform) + ); } - - return visitorMap; + return result; } export function transformSourceFile(program: ts.Program, sourceFile: ts.SourceFile, visitorMap: VisitorMap) { const context = new TransformationContext(program, sourceFile, visitorMap); - const [file] = context.transformNode(sourceFile) as [lua.File]; + + // TS -> TS pre-transformation + const preTransformers = [usingTransformer(context)]; + const result = ts.transform(sourceFile, preTransformers); + + // TS -> Lua transformation + const [file] = context.transformNode(result.transformed[0]) as [lua.File]; return { file, diagnostics: context.diagnostics }; } diff --git a/src/transformation/pre-transformers/using-transformer.ts b/src/transformation/pre-transformers/using-transformer.ts new file mode 100644 index 000000000..1229b71c2 --- /dev/null +++ b/src/transformation/pre-transformers/using-transformer.ts @@ -0,0 +1,139 @@ +import * as ts from "typescript"; +import { TransformationContext } from "../context"; +import { LuaLibFeature, importLuaLibFeature } from "../utils/lualib"; + +export function usingTransformer(context: TransformationContext): ts.TransformerFactory { + return ctx => sourceFile => { + function visit(node: ts.Node): ts.Node { + if (ts.isBlock(node) || ts.isSourceFile(node)) { + const [hasUsings, newStatements] = transformBlockWithUsing(context, node.statements, node); + if (hasUsings) { + // Recurse visitor into updated block to find further usings + const updatedBlock = ts.isBlock(node) + ? ts.factory.updateBlock(node, newStatements) + : ts.factory.updateSourceFile(node, newStatements); + const result = ts.visitEachChild(updatedBlock, visit, ctx); + + // Set all the synthetic node parents to something that makes sense + const parent: ts.Node[] = [updatedBlock]; + function setParent(node2: ts.Node): ts.Node { + ts.setParent(node2, parent[parent.length - 1]); + parent.push(node2); + ts.visitEachChild(node2, setParent, ctx); + parent.pop(); + return node2; + } + ts.visitEachChild(updatedBlock, setParent, ctx); + ts.setParent(updatedBlock, node.parent); + + return result; + } + } + return ts.visitEachChild(node, visit, ctx); + } + const transformedSourceFile = ts.visitEachChild(sourceFile, visit, ctx); + return visit(transformedSourceFile) as ts.SourceFile; + }; +} + +function isUsingDeclarationList(node: ts.Node): node is ts.VariableStatement { + return ts.isVariableStatement(node) && (node.declarationList.flags & ts.NodeFlags.Using) !== 0; +} + +function transformBlockWithUsing( + context: TransformationContext, + statements: ts.NodeArray | ts.Statement[], + block: ts.Block | ts.SourceFile +): [true, ts.Statement[]] | [false] { + const newStatements: ts.Statement[] = []; + + for (let i = 0; i < statements.length; i++) { + const statement = statements[i]; + if (isUsingDeclarationList(statement)) { + const isAwaitUsing = (statement.declarationList.flags & ts.NodeFlags.AwaitContext) !== 0; + + if (isAwaitUsing) { + importLuaLibFeature(context, LuaLibFeature.UsingAsync); + } else { + importLuaLibFeature(context, LuaLibFeature.Using); + } + + // Make declared using variables callback function parameters + const variableNames = statement.declarationList.declarations.map(d => + ts.factory.createParameterDeclaration(undefined, undefined, d.name) + ); + // Add this: void as first parameter + variableNames.unshift(createThisVoidParameter(context.checker)); + + // Put all following statements in the callback body + const followingStatements = statements.slice(i + 1); + const [followingHasUsings, replacedFollowingStatements] = transformBlockWithUsing( + context, + followingStatements, + block + ); + const callbackBody = ts.factory.createBlock( + followingHasUsings ? replacedFollowingStatements : followingStatements + ); + + const callback = ts.factory.createFunctionExpression( + // Put async keyword in front of callback when we are in an async using + isAwaitUsing ? [ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined, + undefined, + undefined, + undefined, + variableNames, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), // Required for TS to not freak out trying to infer the type of synthetic nodes + callbackBody + ); + + // Replace using variable list with call to lualib function with callback and followed by all variable initializers + const functionIdentifier = ts.factory.createIdentifier(isAwaitUsing ? "__TS__UsingAsync" : "__TS__Using"); + let call: ts.Expression = ts.factory.createCallExpression( + functionIdentifier, + [], + [ + callback, + ...statement.declarationList.declarations.map( + d => d.initializer ?? ts.factory.createIdentifier("unidentified") + ), + ] + ); + + // If this is an 'await using ...', add an await statement here + if (isAwaitUsing) { + call = ts.factory.createAwaitExpression(call); + } + + if (ts.isSourceFile(block)) { + // If block is a sourcefile, don't insert a return statement into root code + newStatements.push(ts.factory.createExpressionStatement(call)); + } else if ( + block.parent && + ts.isBlock(block.parent) && + block.parent.statements[block.parent.statements.length - 1] !== block + ) { + // If this is a free-standing block in a function (not the last statement), dont return the value + newStatements.push(ts.factory.createExpressionStatement(call)); + } else { + newStatements.push(ts.factory.createReturnStatement(call)); + } + + return [true, newStatements]; + } else { + newStatements.push(statement); + } + } + return [false]; +} + +function createThisVoidParameter(checker: ts.TypeChecker) { + const voidType = checker.typeToTypeNode(checker.getVoidType(), undefined, undefined); + return ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier("this"), + undefined, + voidType + ); +} diff --git a/src/transformation/utils/annotations.ts b/src/transformation/utils/annotations.ts index 212f30416..b66704c97 100644 --- a/src/transformation/utils/annotations.ts +++ b/src/transformation/utils/annotations.ts @@ -1,188 +1,112 @@ import * as ts from "typescript"; -import { TransformationContext } from "../context"; -import { findFirstNodeAbove, inferAssignedType } from "./typescript"; export enum AnnotationKind { - Extension = "extension", - MetaExtension = "metaExtension", CustomConstructor = "customConstructor", CompileMembersOnly = "compileMembersOnly", NoResolution = "noResolution", - PureAbstract = "pureAbstract", - Phantom = "phantom", - TupleReturn = "tupleReturn", - LuaIterator = "luaIterator", - LuaTable = "luaTable", NoSelf = "noSelf", + CustomName = "customName", NoSelfInFile = "noSelfInFile", - Vararg = "vararg", - ForRange = "forRange", } +const annotationValues = new Map(Object.values(AnnotationKind).map(k => [k.toLowerCase(), k])); + export interface Annotation { kind: AnnotationKind; args: string[]; } -function createAnnotation(name: string, args: string[]): Annotation | undefined { - const kind = Object.values(AnnotationKind).find(k => k.toLowerCase() === name.toLowerCase()); - if (kind !== undefined) { - return { kind, args }; - } -} - export type AnnotationsMap = Map; function collectAnnotations(source: ts.Symbol | ts.Signature, annotationsMap: AnnotationsMap): void { for (const tag of source.getJsDocTags()) { - const annotation = createAnnotation(tag.name, tag.text?.map(p => p.text) ?? []); - if (annotation) { - annotationsMap.set(annotation.kind, annotation); - } + const tagName = annotationValues.get(tag.name.toLowerCase()); + if (!tagName) continue; + const annotation: Annotation = { + kind: tag.name as AnnotationKind, + args: tag.text?.map(p => p.text) ?? [], + }; + annotationsMap.set(tagName, annotation); } } +const symbolAnnotations = new WeakMap(); + export function getSymbolAnnotations(symbol: ts.Symbol): AnnotationsMap { + const known = symbolAnnotations.get(symbol); + if (known) return known; + const annotationsMap: AnnotationsMap = new Map(); collectAnnotations(symbol, annotationsMap); + + symbolAnnotations.set(symbol, annotationsMap); return annotationsMap; } export function getTypeAnnotations(type: ts.Type): AnnotationsMap { + // types are not frequently repeatedly polled for annotations, so it's not worth caching them const annotationsMap: AnnotationsMap = new Map(); - - if (type.symbol) collectAnnotations(type.symbol, annotationsMap); - if (type.aliasSymbol) collectAnnotations(type.aliasSymbol, annotationsMap); - + if (type.symbol) { + getSymbolAnnotations(type.symbol).forEach((value, key) => { + annotationsMap.set(key, value); + }); + } + if (type.aliasSymbol) { + getSymbolAnnotations(type.aliasSymbol).forEach((value, key) => { + annotationsMap.set(key, value); + }); + } return annotationsMap; } +const nodeAnnotations = new WeakMap(); export function getNodeAnnotations(node: ts.Node): AnnotationsMap { - const annotationsMap: AnnotationsMap = new Map(); + const known = nodeAnnotations.get(node); + if (known) return known; - for (const tag of ts.getJSDocTags(node)) { - const tagName = tag.tagName.text; - const annotation = createAnnotation(tagName, getTagArgsFromComment(tag)); - if (annotation) { - annotationsMap.set(annotation.kind, annotation); - } - } + const annotationsMap: AnnotationsMap = new Map(); + collectAnnotationsFromTags(annotationsMap, ts.getAllJSDocTags(node, ts.isJSDocUnknownTag)); + nodeAnnotations.set(node, annotationsMap); return annotationsMap; } +function collectAnnotationsFromTags(annotationsMap: AnnotationsMap, tags: readonly ts.JSDocTag[]) { + for (const tag of tags) { + const tagName = annotationValues.get(tag.tagName.text.toLowerCase()); + if (!tagName) continue; + annotationsMap.set(tagName, { kind: tagName, args: getTagArgsFromComment(tag) }); + } +} + +const fileAnnotations = new WeakMap(); export function getFileAnnotations(sourceFile: ts.SourceFile): AnnotationsMap { + const known = fileAnnotations.get(sourceFile); + if (known) return known; + const annotationsMap: AnnotationsMap = new Map(); if (sourceFile.statements.length > 0) { // Manually collect jsDoc because `getJSDocTags` includes tags only from closest comment const jsDoc = sourceFile.statements[0].jsDoc; if (jsDoc) { - for (const tag of jsDoc.flatMap(x => x.tags ?? [])) { - const tagName = tag.tagName.text; - const annotation = createAnnotation(tagName, getTagArgsFromComment(tag)); - if (annotation) { - annotationsMap.set(annotation.kind, annotation); + for (const jsDocElement of jsDoc) { + if (jsDocElement.tags) { + collectAnnotationsFromTags(annotationsMap, jsDocElement.tags); } } } } + fileAnnotations.set(sourceFile, annotationsMap); return annotationsMap; } -export function getSignatureAnnotations(context: TransformationContext, signature: ts.Signature): AnnotationsMap { - const annotationsMap: AnnotationsMap = new Map(); - collectAnnotations(signature, annotationsMap); - - // Function properties on interfaces have the JSDoc tags on the parent PropertySignature - const declaration = signature.getDeclaration(); - if (declaration?.parent && ts.isPropertySignature(declaration.parent)) { - const symbol = context.checker.getSymbolAtLocation(declaration.parent.name); - if (symbol) { - collectAnnotations(symbol, annotationsMap); - } - } - - return annotationsMap; -} - -export function isTupleReturnCall(context: TransformationContext, node: ts.Node): boolean { - if (!ts.isCallExpression(node)) { - return false; - } - - const signature = context.checker.getResolvedSignature(node); - if (signature) { - if (getSignatureAnnotations(context, signature).has(AnnotationKind.TupleReturn)) { - return true; - } - - // Only check function type for directive if it is declared as an interface or type alias - const declaration = signature.getDeclaration(); - const isInterfaceOrAlias = - declaration?.parent && - ((ts.isInterfaceDeclaration(declaration.parent) && ts.isCallSignatureDeclaration(declaration)) || - ts.isTypeAliasDeclaration(declaration.parent)); - if (!isInterfaceOrAlias) { - return false; - } - } - - const type = context.checker.getTypeAtLocation(node.expression); - return getTypeAnnotations(type).has(AnnotationKind.TupleReturn); -} - -export function isInTupleReturnFunction(context: TransformationContext, node: ts.Node): boolean { - const declaration = findFirstNodeAbove(node, ts.isFunctionLike); - if (!declaration) { - return false; - } - - let functionType: ts.Type | undefined; - if (ts.isFunctionExpression(declaration) || ts.isArrowFunction(declaration)) { - functionType = inferAssignedType(context, declaration); - } else if (ts.isMethodDeclaration(declaration) && ts.isObjectLiteralExpression(declaration.parent)) { - // Manually lookup type for object literal properties declared with method syntax - const interfaceType = inferAssignedType(context, declaration.parent); - const propertySymbol = interfaceType.getProperty(declaration.name.getText()); - if (propertySymbol) { - functionType = context.checker.getTypeOfSymbolAtLocation(propertySymbol, declaration); - } - } - - if (functionType === undefined) { - functionType = context.checker.getTypeAtLocation(declaration); - } - - // Check all overloads for directive - const signatures = functionType.getCallSignatures(); - if (signatures?.some(s => getSignatureAnnotations(context, s).has(AnnotationKind.TupleReturn))) { - return true; - } - - return getTypeAnnotations(functionType).has(AnnotationKind.TupleReturn); -} - -export function isLuaIteratorType(context: TransformationContext, node: ts.Node): boolean { - const type = context.checker.getTypeAtLocation(node); - return getTypeAnnotations(type).has(AnnotationKind.LuaIterator); -} - -export function isVarargType(context: TransformationContext, node: ts.Node): boolean { - const type = context.checker.getTypeAtLocation(node); - return getTypeAnnotations(type).has(AnnotationKind.Vararg); -} - -export function isForRangeType(context: TransformationContext, node: ts.Node): boolean { - const type = context.checker.getTypeAtLocation(node); - return getTypeAnnotations(type).has(AnnotationKind.ForRange); -} - -export function getTagArgsFromComment(tag: ts.JSDocTag): string[] { +function getTagArgsFromComment(tag: ts.JSDocTag): string[] { if (tag.comment) { if (typeof tag.comment === "string") { - return tag.comment.split(" "); + const firstLine = tag.comment.split("\n")[0]; + return firstLine.trim().split(" "); } else { return tag.comment.map(part => part.text); } diff --git a/src/transformation/utils/assignment-validation.ts b/src/transformation/utils/assignment-validation.ts index e62045248..d0f42d90a 100644 --- a/src/transformation/utils/assignment-validation.ts +++ b/src/transformation/utils/assignment-validation.ts @@ -34,15 +34,10 @@ export function validateAssignment( validateFunctionAssignment(context, node, fromType, toType, toName); - const fromTypeNode = context.checker.typeToTypeNode(fromType, undefined, undefined); - const toTypeNode = context.checker.typeToTypeNode(toType, undefined, undefined); - if (!fromTypeNode || !toTypeNode) { - return; - } - + const checker = context.checker; if ( - (ts.isArrayTypeNode(toTypeNode) || ts.isTupleTypeNode(toTypeNode)) && - (ts.isArrayTypeNode(fromTypeNode) || ts.isTupleTypeNode(fromTypeNode)) + (checker.isTupleType(toType) || checker.isArrayType(toType)) && + (checker.isTupleType(fromType) || checker.isArrayType(fromType)) ) { // Recurse into arrays/tuples const fromTypeArguments = (fromType as ts.TypeReference).typeArguments; @@ -58,32 +53,39 @@ export function validateAssignment( } } - if ( - (toType.flags & ts.TypeFlags.Object) !== 0 && - ((toType as ts.ObjectType).objectFlags & ts.ObjectFlags.ClassOrInterface) !== 0 && - toType.symbol && - toType.symbol.members && - fromType.symbol && - fromType.symbol.members - ) { + const fromMembers = fromType.symbol?.members; + const toMembers = toType.symbol?.members; + + if (fromMembers && toMembers) { // Recurse into interfaces - toType.symbol.members.forEach((toMember, escapedMemberName) => { - if (fromType.symbol.members) { - const fromMember = fromType.symbol.members.get(escapedMemberName); + if (toMembers.size < fromMembers.size) { + toMembers.forEach((toMember, escapedMemberName) => { + const fromMember = fromMembers.get(escapedMemberName); if (fromMember) { - const toMemberType = context.checker.getTypeOfSymbolAtLocation(toMember, node); - const fromMemberType = context.checker.getTypeOfSymbolAtLocation(fromMember, node); - const memberName = ts.unescapeLeadingUnderscores(escapedMemberName); - validateAssignment( - context, - node, - fromMemberType, - toMemberType, - toName ? `${toName}.${memberName}` : memberName - ); + validateMember(toMember, fromMember, escapedMemberName); } - } - }); + }); + } else { + fromMembers.forEach((fromMember, escapedMemberName) => { + const toMember = toMembers.get(escapedMemberName); + if (toMember) { + validateMember(toMember, fromMember, escapedMemberName); + } + }); + } + } + + function validateMember(toMember: ts.Symbol, fromMember: ts.Symbol, escapedMemberName: ts.__String): void { + const toMemberType = context.checker.getTypeOfSymbolAtLocation(toMember, node); + const fromMemberType = context.checker.getTypeOfSymbolAtLocation(fromMember, node); + const memberName = ts.unescapeLeadingUnderscores(escapedMemberName); + validateAssignment( + context, + node, + fromMemberType, + toMemberType, + toName ? `${toName}.${memberName}` : memberName + ); } } diff --git a/src/transformation/utils/diagnostics.ts b/src/transformation/utils/diagnostics.ts index 16a0c7395..e8d77c169 100644 --- a/src/transformation/utils/diagnostics.ts +++ b/src/transformation/utils/diagnostics.ts @@ -1,5 +1,6 @@ import * as ts from "typescript"; -import { LuaTarget } from "../../CompilerOptions"; +import * as lua from "../../LuaAST"; +import { LuaTarget, TypeScriptToLuaOptions } from "../../CompilerOptions"; import { createSerialDiagnosticFactory } from "../../utils"; import { AnnotationKind } from "./annotations"; @@ -10,9 +11,9 @@ const createDiagnosticFactory = ( message: MessageProvider ) => createSerialDiagnosticFactory((node: ts.Node, ...args: TArgs) => ({ - file: node.getSourceFile(), - start: node.getStart(), - length: node.getWidth(), + file: ts.getOriginalNode(node).getSourceFile(), + start: ts.getOriginalNode(node).getStart(), + length: ts.getOriginalNode(node).getWidth(), messageText: typeof message === "string" ? message : message(...args), category, })); @@ -72,20 +73,33 @@ export const invalidMultiIterableWithoutDestructuring = createErrorDiagnosticFac "LuaIterable with a LuaMultiReturn return value type must be destructured." ); +export const invalidPairsIterableWithoutDestructuring = createErrorDiagnosticFactory( + "LuaPairsIterable type must be destructured in a for...of statement." +); + export const unsupportedAccessorInObjectLiteral = createErrorDiagnosticFactory( "Accessors in object literal are not supported." ); export const unsupportedRightShiftOperator = createErrorDiagnosticFactory( - "Right shift operator is not supported for target Lua 5.3. Use `>>>` instead." + "Signed right shift `>>` is not supported on Lua 5.3+: Lua's native `>>` is logical (zero-fill) on 64-bit integers, with no built-in arithmetic shift. Use `>>>` if you don't need sign extension, or write your own helper." ); const getLuaTargetName = (version: LuaTarget) => (version === LuaTarget.LuaJIT ? "LuaJIT" : `Lua ${version}`); export const unsupportedForTarget = createErrorDiagnosticFactory( - (functionality: string, version: Exclude) => + (functionality: string, version: LuaTarget) => `${functionality} is/are not supported for target ${getLuaTargetName(version)}.` ); +export const unsupportedForTargetButOverrideAvailable = createErrorDiagnosticFactory( + (functionality: string, version: LuaTarget, optionName: keyof TypeScriptToLuaOptions) => + `As a precaution, ${functionality} is/are not supported for target ${getLuaTargetName( + version + )} due to language features/limitations. ` + + `However "--${optionName}" can be used to bypass this precaution. ` + + "See https://typescripttolua.github.io/docs/configuration for more information." +); + export const unsupportedProperty = createErrorDiagnosticFactory( (parentName: string, property: string) => `${parentName}.${property} is unsupported.` ); @@ -106,40 +120,63 @@ export const invalidMultiFunctionReturnType = createErrorDiagnosticFactory( "The $multi function cannot be cast to a non-LuaMultiReturn type." ); -export const invalidMultiTypeToNonArrayLiteral = createErrorDiagnosticFactory("Expected an array literal."); +export const invalidMultiReturnAccess = createErrorDiagnosticFactory( + "The LuaMultiReturn type can only be accessed via an element access expression of a numeric type." +); -export const invalidMultiTypeToEmptyPatternOrArrayLiteral = createErrorDiagnosticFactory( - "There must be one or more elements specified here." +export const invalidCallExtensionUse = createErrorDiagnosticFactory( + "This function must be called directly and cannot be referred to." +); +export const annotationDeprecated = createWarningDiagnosticFactory( + (kind: AnnotationKind) => + `'@${kind}' is deprecated and will be removed in a future update. Please update your code before upgrading to the next release, otherwise your project will no longer compile. ` + + `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.` ); -export const invalidMultiReturnAccess = createErrorDiagnosticFactory( - "The LuaMultiReturn type can only be accessed via an element access expression of a numeric type." +export const truthyOnlyConditionalValue = createWarningDiagnosticFactory( + "Only false and nil evaluate to 'false' in Lua, everything else is considered 'true'. Explicitly compare the value with ===." ); -export const invalidOperatorMappingUse = createErrorDiagnosticFactory( - "This function must always be directly called and cannot be referred to." +export const notAllowedOptionalAssignment = createErrorDiagnosticFactory( + "The left-hand side of an assignment expression may not be an optional property access." ); -export const invalidTableExtensionUse = createErrorDiagnosticFactory( - "This function must be called directly and cannot be referred to." +export const awaitMustBeInAsyncFunction = createErrorDiagnosticFactory( + "Await can only be used inside async functions." ); -export const invalidTableDeleteExpression = createErrorDiagnosticFactory( - "Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement." +export const unsupportedAsyncGenerator = createErrorDiagnosticFactory("Async generator functions are not supported."); + +export const unsupportedForAwaitOf = createErrorDiagnosticFactory("'for await...of' loops are not supported."); + +export const unsupportedBuiltinOptionalCall = createErrorDiagnosticFactory( + "Optional calls are not supported for builtin or language extension functions." ); -export const invalidTableSetExpression = createErrorDiagnosticFactory( - "Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement." +export const unsupportedOptionalCompileMembersOnly = createErrorDiagnosticFactory( + "Optional calls are not supported on enums marked with @compileMembersOnly." ); -export const annotationRemoved = createErrorDiagnosticFactory( - (kind: AnnotationKind) => - `'@${kind}' has been removed and will no longer have any effect.` + - `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.` +export const undefinedInArrayLiteral = createErrorDiagnosticFactory( + "Array literals may not contain undefined or null." ); -export const annotationDeprecated = createWarningDiagnosticFactory( - (kind: AnnotationKind) => - `'@${kind}' is deprecated and will be removed in a future update. Please update your code before upgrading to the next release, otherwise your project will no longer compile. ` + - `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.` +export const invalidMethodCallExtensionUse = createErrorDiagnosticFactory( + "This language extension must be called as a method." +); + +export const invalidSpreadInCallExtension = createErrorDiagnosticFactory( + "Spread elements are not supported in call extensions." +); + +export const cannotAssignToNodeOfKind = createErrorDiagnosticFactory( + (kind: lua.SyntaxKind) => `Cannot create assignment assigning to a node of type ${lua.SyntaxKind[kind]}.` +); + +export const incompleteFieldDecoratorWarning = createWarningDiagnosticFactory( + "You are using a class field decorator, note that tstl ignores returned value initializers!" +); + +export const unsupportedArrayWithLengthConstructor = createErrorDiagnosticFactory( + `Constructing new Array with length is not supported.` ); diff --git a/src/transformation/utils/export.ts b/src/transformation/utils/export.ts index 1edee936c..f0ef437e5 100644 --- a/src/transformation/utils/export.ts +++ b/src/transformation/utils/export.ts @@ -1,19 +1,34 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { TransformationContext } from "../context"; -import { createModuleLocalNameIdentifier } from "../visitors/namespace"; +import { createModuleLocalName } from "../visitors/namespace"; import { createExportsIdentifier } from "./lua-ast"; import { getSymbolInfo } from "./symbols"; import { findFirstNodeAbove } from "./typescript"; export function hasDefaultExportModifier(node: ts.Node): boolean { - return (node.modifiers ?? []).some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword); + return ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword) === true + ); +} + +export function hasExportModifier(node: ts.Node): boolean { + return ( + ts.canHaveModifiers(node) && + node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword) === true + ); } -export const createDefaultExportIdentifier = (original: ts.Node): lua.Identifier => - lua.createIdentifier("default", original); +export function shouldBeExported(node: ts.Node): boolean { + if (hasExportModifier(node)) { + // Don't export if we're inside a namespace (module declaration) + return ts.findAncestor(node, ts.isModuleDeclaration) === undefined; + } + return false; +} -export const createDefaultExportStringLiteral = (original: ts.Node): lua.StringLiteral => +export const createDefaultExportStringLiteral = (original?: ts.Node): lua.StringLiteral => lua.createStringLiteral("default", original); export function getExportedSymbolDeclaration(symbol: ts.Symbol): ts.Declaration | undefined { @@ -137,8 +152,12 @@ export function createExportedIdentifier( const exportTable = exportScope && ts.isModuleDeclaration(exportScope) - ? createModuleLocalNameIdentifier(context, exportScope) + ? createModuleLocalName(context, exportScope) : createExportsIdentifier(); return lua.createTableIndexExpression(exportTable, lua.createStringLiteral(identifier.text)); } + +export function createDefaultExportExpression(node: ts.Node): lua.AssignmentLeftHandSideExpression { + return lua.createTableIndexExpression(createExportsIdentifier(), createDefaultExportStringLiteral(node), node); +} diff --git a/src/transformation/utils/function-context.ts b/src/transformation/utils/function-context.ts index 8bf05255c..4fce80f49 100644 --- a/src/transformation/utils/function-context.ts +++ b/src/transformation/utils/function-context.ts @@ -5,10 +5,10 @@ import { AnnotationKind, getFileAnnotations, getNodeAnnotations } from "./annota import { findFirstNodeAbove, getAllCallSignatures, inferAssignedType } from "./typescript"; export enum ContextType { - None, - Void, - NonVoid, - Mixed, + None = 0, + Void = 1 << 0, + NonVoid = 1 << 1, + Mixed = Void | NonVoid, } function hasNoSelfAncestor(declaration: ts.Declaration): boolean { @@ -29,21 +29,86 @@ function hasNoSelfAncestor(declaration: ts.Declaration): boolean { } function getExplicitThisParameter(signatureDeclaration: ts.SignatureDeclaration): ts.ParameterDeclaration | undefined { - return signatureDeclaration.parameters.find( - param => ts.isIdentifier(param.name) && param.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword - ); + const param = signatureDeclaration.parameters[0]; + if (param && ts.isIdentifier(param.name) && ts.identifierToKeywordKind(param.name) === ts.SyntaxKind.ThisKeyword) { + return param; + } } -export function getDeclarationContextType( - { program }: TransformationContext, +const callContextTypes = new WeakMap(); + +export function getCallContextType(context: TransformationContext, callExpression: ts.CallLikeExpression): ContextType { + const known = callContextTypes.get(callExpression); + if (known !== undefined) return known; + + const signature = context.checker.getResolvedSignature(callExpression); + const signatureDeclaration = signature?.getDeclaration(); + + let contextType = ContextType.None; + + if (signatureDeclaration) { + contextType = computeDeclarationContextType(context, signatureDeclaration); + } else { + // No signature declaration could be resolved, so instead try to see if the declaration is in a + // noSelfInFile file + const declarations = findRootDeclarations(context, callExpression); + contextType = declarations.some(d => getFileAnnotations(d.getSourceFile()).has(AnnotationKind.NoSelfInFile)) + ? ContextType.Void + : context.options.noImplicitSelf + ? ContextType.Void + : ContextType.NonVoid; + } + + callContextTypes.set(callExpression, contextType); + return contextType; +} + +const signatureDeclarationContextTypes = new WeakMap(); + +function getSignatureContextType( + context: TransformationContext, signatureDeclaration: ts.SignatureDeclaration ): ContextType { + const known = signatureDeclarationContextTypes.get(signatureDeclaration); + if (known !== undefined) return known; + const contextType = computeDeclarationContextType(context, signatureDeclaration); + signatureDeclarationContextTypes.set(signatureDeclaration, contextType); + return contextType; +} + +function findRootDeclarations(context: TransformationContext, callExpression: ts.CallLikeExpression): ts.Declaration[] { + const calledExpression = ts.isTaggedTemplateExpression(callExpression) + ? callExpression.tag + : ts.isJsxSelfClosingElement(callExpression) + ? callExpression.tagName + : ts.isJsxOpeningElement(callExpression) + ? callExpression.tagName + : ts.isCallExpression(callExpression) + ? callExpression.expression + : undefined; + + if (!calledExpression) return []; + + const calledSymbol = context.checker.getSymbolAtLocation(calledExpression); + if (calledSymbol === undefined) return []; + + return ( + calledSymbol.getDeclarations()?.flatMap(d => { + if (ts.isImportSpecifier(d)) { + const aliasSymbol = context.checker.getAliasedSymbol(calledSymbol); + return aliasSymbol.getDeclarations() ?? []; + } else { + return [d]; + } + }) ?? [] + ); +} + +function computeDeclarationContextType(context: TransformationContext, signatureDeclaration: ts.SignatureDeclaration) { const thisParameter = getExplicitThisParameter(signatureDeclaration); if (thisParameter) { // Explicit 'this' - return thisParameter.type && thisParameter.type.kind === ts.SyntaxKind.VoidKeyword - ? ContextType.Void - : ContextType.NonVoid; + return thisParameter.type?.kind === ts.SyntaxKind.VoidKeyword ? ContextType.Void : ContextType.NonVoid; } // noSelf declaration on function signature @@ -57,7 +122,8 @@ export function getDeclarationContextType( ts.isConstructSignatureDeclaration(signatureDeclaration) || ts.isConstructorDeclaration(signatureDeclaration) || (signatureDeclaration.parent && ts.isPropertyDeclaration(signatureDeclaration.parent)) || - (signatureDeclaration.parent && ts.isPropertySignature(signatureDeclaration.parent)) + (signatureDeclaration.parent && ts.isPropertySignature(signatureDeclaration.parent)) || + (signatureDeclaration.parent && ts.isIndexSignatureDeclaration(signatureDeclaration.parent)) ) { // Class/interface methods only respect @noSelf on their parent const scopeDeclaration = findFirstNodeAbove( @@ -66,21 +132,42 @@ export function getDeclarationContextType( ts.isClassDeclaration(n) || ts.isClassExpression(n) || ts.isInterfaceDeclaration(n) ); - if (scopeDeclaration === undefined) { - return ContextType.NonVoid; - } - - if (getNodeAnnotations(scopeDeclaration).has(AnnotationKind.NoSelf)) { + if (scopeDeclaration !== undefined && getNodeAnnotations(scopeDeclaration).has(AnnotationKind.NoSelf)) { return ContextType.Void; } return ContextType.NonVoid; } + if (signatureDeclaration.parent && ts.isTypeParameterDeclaration(signatureDeclaration.parent)) { + return ContextType.NonVoid; + } + + // Call signature inside a class or interface respects @noSelf on the enclosing class/interface + if (ts.isCallSignatureDeclaration(signatureDeclaration)) { + const scopeDeclaration = findFirstNodeAbove( + signatureDeclaration, + (n): n is ts.ClassLikeDeclaration | ts.InterfaceDeclaration => + ts.isClassDeclaration(n) || ts.isClassExpression(n) || ts.isInterfaceDeclaration(n) + ); + + if (scopeDeclaration !== undefined && getNodeAnnotations(scopeDeclaration).has(AnnotationKind.NoSelf)) { + return ContextType.Void; + } + } + // When using --noImplicitSelf and the signature is defined in a file targeted by the program apply the @noSelf rule. + const program = context.program; const options = program.getCompilerOptions() as CompilerOptions; - if (options.noImplicitSelf && program.getRootFileNames().includes(signatureDeclaration.getSourceFile().fileName)) { - return ContextType.Void; + if (options.noImplicitSelf) { + const sourceFile = program.getSourceFile(signatureDeclaration.getSourceFile().fileName); + if ( + sourceFile !== undefined && + !program.isSourceFileDefaultLibrary(sourceFile) && + !program.isSourceFileFromExternalLibrary(sourceFile) + ) { + return ContextType.Void; + } } // Walk up to find @noSelf or @noSelfInFile @@ -92,52 +179,63 @@ export function getDeclarationContextType( } function reduceContextTypes(contexts: ContextType[]): ContextType { - const reducer = (a: ContextType, b: ContextType) => { - if (a === ContextType.None) { - return b; - } else if (b === ContextType.None) { - return a; - } else if (a !== b) { - return ContextType.Mixed; - } else { - return a; - } - }; - - return contexts.reduce(reducer, ContextType.None); + let type = ContextType.None; + for (const context of contexts) { + type |= context; + if (type === ContextType.Mixed) break; + } + return type; } -function getSignatureDeclarations( - context: TransformationContext, - signatures: readonly ts.Signature[] -): ts.SignatureDeclaration[] { - return signatures.flatMap(signature => { - const signatureDeclaration = signature.getDeclaration(); - if ( - (ts.isFunctionExpression(signatureDeclaration) || ts.isArrowFunction(signatureDeclaration)) && - !getExplicitThisParameter(signatureDeclaration) - ) { - // Infer type of function expressions/arrow functions - const inferredType = inferAssignedType(context, signatureDeclaration); - if (inferredType) { - const inferredSignatures = getAllCallSignatures(inferredType); - if (inferredSignatures.length > 0) { - return inferredSignatures.map(s => s.getDeclaration()); - } - } +function getSignatureDeclarations(context: TransformationContext, signature: ts.Signature): ts.SignatureDeclaration[] { + if (signature.compositeSignatures) { + return signature.compositeSignatures.flatMap(s => getSignatureDeclarations(context, s)); + } + + const signatureDeclaration = signature.getDeclaration(); + if (signatureDeclaration === undefined) { + return []; + } + + let inferredType: ts.Type | undefined; + if ( + ts.isMethodDeclaration(signatureDeclaration) && + ts.isObjectLiteralExpression(signatureDeclaration.parent) && + !getExplicitThisParameter(signatureDeclaration) + ) { + inferredType = context.checker.getContextualTypeForObjectLiteralElement(signatureDeclaration); + } else if ( + (ts.isFunctionExpression(signatureDeclaration) || ts.isArrowFunction(signatureDeclaration)) && + !getExplicitThisParameter(signatureDeclaration) + ) { + // Infer type of function expressions/arrow functions + inferredType = inferAssignedType(context, signatureDeclaration); + } + + if (inferredType) { + const inferredSignatures = getAllCallSignatures(inferredType); + if (inferredSignatures.length > 0) { + return inferredSignatures.map(s => s.getDeclaration()); } + } - return signatureDeclaration; - }); + return [signatureDeclaration]; } +const typeContextTypes = new WeakMap(); + export function getFunctionContextType(context: TransformationContext, type: ts.Type): ContextType { - if (type.isTypeParameter()) { - type = type.getConstraint() ?? type; - } + const known = typeContextTypes.get(type); + if (known !== undefined) return known; + const contextType = computeFunctionContextType(context, type); + typeContextTypes.set(type, contextType); + return contextType; +} - if (type.isUnion()) { - return reduceContextTypes(type.types.map(t => getFunctionContextType(context, t))); +function computeFunctionContextType(context: TransformationContext, type: ts.Type): ContextType { + if (type.isTypeParameter()) { + const constraint = type.getConstraint(); + if (constraint) return getFunctionContextType(context, constraint); } const signatures = context.checker.getSignaturesOfType(type, ts.SignatureKind.Call); @@ -145,6 +243,7 @@ export function getFunctionContextType(context: TransformationContext, type: ts. return ContextType.None; } - const signatureDeclarations = getSignatureDeclarations(context, signatures); - return reduceContextTypes(signatureDeclarations.map(s => getDeclarationContextType(context, s))); + return reduceContextTypes( + signatures.flatMap(s => getSignatureDeclarations(context, s)).map(s => getSignatureContextType(context, s)) + ); } diff --git a/src/transformation/utils/language-extensions.ts b/src/transformation/utils/language-extensions.ts index 3861cbf57..6da38837a 100644 --- a/src/transformation/utils/language-extensions.ts +++ b/src/transformation/utils/language-extensions.ts @@ -1,130 +1,178 @@ import * as ts from "typescript"; import { TransformationContext } from "../context"; +import { invalidMethodCallExtensionUse, invalidSpreadInCallExtension } from "./diagnostics"; export enum ExtensionKind { MultiFunction = "MultiFunction", - MultiType = "MultiType", RangeFunction = "RangeFunction", VarargConstant = "VarargConstant", - IterableType = "IterableType", - AdditionOperatorType = "AdditionOperatorType", - AdditionOperatorMethodType = "AdditionOperatorMethodType", - SubtractionOperatorType = "SubtractionOperatorType", - SubtractionOperatorMethodType = "SubtractionOperatorMethodType", - MultiplicationOperatorType = "MultiplicationOperatorType", - MultiplicationOperatorMethodType = "MultiplicationOperatorMethodType", - DivisionOperatorType = "DivisionOperatorType", - DivisionOperatorMethodType = "DivisionOperatorMethodType", - ModuloOperatorType = "ModuloOperatorType", - ModuloOperatorMethodType = "ModuloOperatorMethodType", - PowerOperatorType = "PowerOperatorType", - PowerOperatorMethodType = "PowerOperatorMethodType", - FloorDivisionOperatorType = "FloorDivisionOperatorType", - FloorDivisionOperatorMethodType = "FloorDivisionOperatorMethodType", - BitwiseAndOperatorType = "BitwiseAndOperatorType", - BitwiseAndOperatorMethodType = "BitwiseAndOperatorMethodType", - BitwiseOrOperatorType = "BitwiseOrOperatorType", - BitwiseOrOperatorMethodType = "BitwiseOrOperatorMethodType", - BitwiseExclusiveOrOperatorType = "BitwiseExclusiveOrOperatorType", - BitwiseExclusiveOrOperatorMethodType = "BitwiseExclusiveOrOperatorMethodType", - BitwiseLeftShiftOperatorType = "BitwiseLeftShiftOperatorType", - BitwiseLeftShiftOperatorMethodType = "BitwiseLeftShiftOperatorMethodType", - BitwiseRightShiftOperatorType = "BitwiseRightShiftOperatorType", - BitwiseRightShiftOperatorMethodType = "BitwiseRightShiftOperatorMethodType", - ConcatOperatorType = "ConcatOperatorType", - ConcatOperatorMethodType = "ConcatOperatorMethodType", - LessThanOperatorType = "LessThanOperatorType", - LessThanOperatorMethodType = "LessThanOperatorMethodType", - GreaterThanOperatorType = "GreaterThanOperatorType", - GreaterThanOperatorMethodType = "GreaterThanOperatorMethodType", - NegationOperatorType = "NegationOperatorType", - NegationOperatorMethodType = "NegationOperatorMethodType", - BitwiseNotOperatorType = "BitwiseNotOperatorType", - BitwiseNotOperatorMethodType = "BitwiseNotOperatorMethodType", - LengthOperatorType = "LengthOperatorType", - LengthOperatorMethodType = "LengthOperatorMethodType", - TableNewType = "TableNewType", - TableDeleteType = "TableDeleteType", - TableDeleteMethodType = "TableDeleteMethodType", - TableGetType = "TableGetType", - TableGetMethodType = "TableGetMethodType", - TableHasType = "TableHasType", - TableHasMethodType = "TableHasMethodType", - TableSetType = "TableSetType", - TableSetMethodType = "TableSetMethodType", + AdditionOperatorType = "Addition", + AdditionOperatorMethodType = "AdditionMethod", + SubtractionOperatorType = "Subtraction", + SubtractionOperatorMethodType = "SubtractionMethod", + MultiplicationOperatorType = "Multiplication", + MultiplicationOperatorMethodType = "MultiplicationMethod", + DivisionOperatorType = "Division", + DivisionOperatorMethodType = "DivisionMethod", + ModuloOperatorType = "Modulo", + ModuloOperatorMethodType = "ModuloMethod", + PowerOperatorType = "Power", + PowerOperatorMethodType = "PowerMethod", + FloorDivisionOperatorType = "FloorDivision", + FloorDivisionOperatorMethodType = "FloorDivisionMethod", + BitwiseAndOperatorType = "BitwiseAnd", + BitwiseAndOperatorMethodType = "BitwiseAndMethod", + BitwiseOrOperatorType = "BitwiseOr", + BitwiseOrOperatorMethodType = "BitwiseOrMethod", + BitwiseExclusiveOrOperatorType = "BitwiseExclusiveOr", + BitwiseExclusiveOrOperatorMethodType = "BitwiseExclusiveOrMethod", + BitwiseLeftShiftOperatorType = "BitwiseLeftShift", + BitwiseLeftShiftOperatorMethodType = "BitwiseLeftShiftMethod", + BitwiseRightShiftOperatorType = "BitwiseRightShift", + BitwiseRightShiftOperatorMethodType = "BitwiseRightShiftMethod", + ConcatOperatorType = "Concat", + ConcatOperatorMethodType = "ConcatMethod", + LessThanOperatorType = "LessThan", + LessThanOperatorMethodType = "LessThanMethod", + GreaterThanOperatorType = "GreaterThan", + GreaterThanOperatorMethodType = "GreaterThanMethod", + NegationOperatorType = "Negation", + NegationOperatorMethodType = "NegationMethod", + BitwiseNotOperatorType = "BitwiseNot", + BitwiseNotOperatorMethodType = "BitwiseNotMethod", + LengthOperatorType = "Length", + LengthOperatorMethodType = "LengthMethod", + TableNewType = "TableNew", + TableDeleteType = "TableDelete", + TableDeleteMethodType = "TableDeleteMethod", + TableGetType = "TableGet", + TableGetMethodType = "TableGetMethod", + TableHasType = "TableHas", + TableHasMethodType = "TableHasMethod", + TableSetType = "TableSet", + TableSetMethodType = "TableSetMethod", + TableAddKeyType = "TableAddKey", + TableAddKeyMethodType = "TableAddKeyMethod", + TableIsEmptyType = "TableIsEmpty", + TableIsEmptyMethodType = "TableIsEmptyMethod", } -const extensionKindToValueName: { [T in ExtensionKind]?: string } = { - [ExtensionKind.MultiFunction]: "$multi", - [ExtensionKind.RangeFunction]: "$range", - [ExtensionKind.VarargConstant]: "$vararg", -}; +const extensionValues: Set = new Set(Object.values(ExtensionKind)); -const extensionKindToTypeBrand: { [T in ExtensionKind]: string } = { - [ExtensionKind.MultiFunction]: "__luaMultiFunctionBrand", - [ExtensionKind.MultiType]: "__luaMultiReturnBrand", - [ExtensionKind.RangeFunction]: "__luaRangeFunctionBrand", - [ExtensionKind.VarargConstant]: "__luaVarargConstantBrand", - [ExtensionKind.IterableType]: "__luaIterableBrand", - [ExtensionKind.AdditionOperatorType]: "__luaAdditionBrand", - [ExtensionKind.AdditionOperatorMethodType]: "__luaAdditionMethodBrand", - [ExtensionKind.SubtractionOperatorType]: "__luaSubtractionBrand", - [ExtensionKind.SubtractionOperatorMethodType]: "__luaSubtractionMethodBrand", - [ExtensionKind.MultiplicationOperatorType]: "__luaMultiplicationBrand", - [ExtensionKind.MultiplicationOperatorMethodType]: "__luaMultiplicationMethodBrand", - [ExtensionKind.DivisionOperatorType]: "__luaDivisionBrand", - [ExtensionKind.DivisionOperatorMethodType]: "__luaDivisionMethodBrand", - [ExtensionKind.ModuloOperatorType]: "__luaModuloBrand", - [ExtensionKind.ModuloOperatorMethodType]: "__luaModuloMethodBrand", - [ExtensionKind.PowerOperatorType]: "__luaPowerBrand", - [ExtensionKind.PowerOperatorMethodType]: "__luaPowerMethodBrand", - [ExtensionKind.FloorDivisionOperatorType]: "__luaFloorDivisionBrand", - [ExtensionKind.FloorDivisionOperatorMethodType]: "__luaFloorDivisionMethodBrand", - [ExtensionKind.BitwiseAndOperatorType]: "__luaBitwiseAndBrand", - [ExtensionKind.BitwiseAndOperatorMethodType]: "__luaBitwiseAndMethodBrand", - [ExtensionKind.BitwiseOrOperatorType]: "__luaBitwiseOrBrand", - [ExtensionKind.BitwiseOrOperatorMethodType]: "__luaBitwiseOrMethodBrand", - [ExtensionKind.BitwiseExclusiveOrOperatorType]: "__luaBitwiseExclusiveOrBrand", - [ExtensionKind.BitwiseExclusiveOrOperatorMethodType]: "__luaBitwiseExclusiveOrMethodBrand", - [ExtensionKind.BitwiseLeftShiftOperatorType]: "__luaBitwiseLeftShiftBrand", - [ExtensionKind.BitwiseLeftShiftOperatorMethodType]: "__luaBitwiseLeftShiftMethodBrand", - [ExtensionKind.BitwiseRightShiftOperatorType]: "__luaBitwiseRightShiftBrand", - [ExtensionKind.BitwiseRightShiftOperatorMethodType]: "__luaBitwiseRightShiftMethodBrand", - [ExtensionKind.ConcatOperatorType]: "__luaConcatBrand", - [ExtensionKind.ConcatOperatorMethodType]: "__luaConcatMethodBrand", - [ExtensionKind.LessThanOperatorType]: "__luaLessThanBrand", - [ExtensionKind.LessThanOperatorMethodType]: "__luaLessThanMethodBrand", - [ExtensionKind.GreaterThanOperatorType]: "__luaGreaterThanBrand", - [ExtensionKind.GreaterThanOperatorMethodType]: "__luaGreaterThanMethodBrand", - [ExtensionKind.NegationOperatorType]: "__luaNegationBrand", - [ExtensionKind.NegationOperatorMethodType]: "__luaNegationMethodBrand", - [ExtensionKind.BitwiseNotOperatorType]: "__luaBitwiseNotBrand", - [ExtensionKind.BitwiseNotOperatorMethodType]: "__luaBitwiseNotMethodBrand", - [ExtensionKind.LengthOperatorType]: "__luaLengthBrand", - [ExtensionKind.LengthOperatorMethodType]: "__luaLengthMethodBrand", - [ExtensionKind.TableNewType]: "__luaTableNewBrand", - [ExtensionKind.TableDeleteType]: "__luaTableDeleteBrand", - [ExtensionKind.TableDeleteMethodType]: "__luaTableDeleteMethodBrand", - [ExtensionKind.TableGetType]: "__luaTableGetBrand", - [ExtensionKind.TableGetMethodType]: "__luaTableGetMethodBrand", - [ExtensionKind.TableHasType]: "__luaTableHasBrand", - [ExtensionKind.TableHasMethodType]: "__luaTableHasMethodBrand", - [ExtensionKind.TableSetType]: "__luaTableSetBrand", - [ExtensionKind.TableSetMethodType]: "__luaTableSetMethodBrand", -}; +export function getExtensionKindForType(context: TransformationContext, type: ts.Type): ExtensionKind | undefined { + const value = getPropertyValue(context, type, "__tstlExtension"); + if (value && extensionValues.has(value)) { + return value as ExtensionKind; + } +} + +const excludedTypeFlags: ts.TypeFlags = + ((1 << 18) - 1) | // All flags from Any...Never + ts.TypeFlags.Index | + ts.TypeFlags.NonPrimitive; + +function getPropertyValue(context: TransformationContext, type: ts.Type, propertyName: string): string | undefined { + if (type.flags & excludedTypeFlags) return; + const property = type.getProperty(propertyName); + if (!property) return undefined; + const propertyType = context.checker.getTypeOfSymbolAtLocation(property, context.sourceFile); + if (propertyType.isStringLiteral()) return propertyType.value; +} + +export function getExtensionKindForNode(context: TransformationContext, node: ts.Node): ExtensionKind | undefined { + const originalNode = ts.getOriginalNode(node); + let type = context.checker.getTypeAtLocation(originalNode); + if (ts.isOptionalChain(originalNode)) { + type = context.checker.getNonNullableType(type); + } + return getExtensionKindForType(context, type); +} + +export function getExtensionKindForSymbol( + context: TransformationContext, + symbol: ts.Symbol +): ExtensionKind | undefined { + const type = context.checker.getTypeOfSymbolAtLocation(symbol, context.sourceFile); + return getExtensionKindForType(context, type); +} + +export enum IterableExtensionKind { + Iterable = "Iterable", + Pairs = "Pairs", + PairsKey = "PairsKey", +} + +export function isLuaIterable(context: TransformationContext, type: ts.Type): boolean { + return getPropertyValue(context, type, "__tstlIterable") !== undefined; +} + +export function getIterableExtensionTypeForType( + context: TransformationContext, + type: ts.Type +): IterableExtensionKind | undefined { + const value = getPropertyValue(context, type, "__tstlIterable"); + if (value && value in IterableExtensionKind) { + return value as IterableExtensionKind; + } +} + +export function getIterableExtensionKindForNode( + context: TransformationContext, + node: ts.Node +): IterableExtensionKind | undefined { + const type = context.checker.getTypeAtLocation(node); + return getIterableExtensionTypeForType(context, type); +} + +export const methodExtensionKinds: ReadonlySet = new Set( + Object.values(ExtensionKind).filter(key => key.endsWith("Method")) +); + +export function getNaryCallExtensionArgs( + context: TransformationContext, + node: ts.CallExpression, + kind: ExtensionKind, + numArgs: number +): readonly ts.Expression[] | undefined { + let expressions: readonly ts.Expression[]; + if (node.arguments.some(ts.isSpreadElement)) { + context.diagnostics.push(invalidSpreadInCallExtension(node)); + return undefined; + } + if (methodExtensionKinds.has(kind)) { + if (!(ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) { + context.diagnostics.push(invalidMethodCallExtensionUse(node)); + return undefined; + } + if (node.arguments.length < numArgs - 1) { + // assumed to be TS error + return undefined; + } + expressions = [node.expression.expression, ...node.arguments]; + } else { + if (node.arguments.length < numArgs) { + // assumed to be TS error + return undefined; + } + expressions = node.arguments; + } + return expressions; +} -export function isExtensionType(type: ts.Type, extensionKind: ExtensionKind): boolean { - const typeBrand = extensionKindToTypeBrand[extensionKind]; - return typeBrand !== undefined && type.getProperty(typeBrand) !== undefined; +export function getUnaryCallExtensionArg( + context: TransformationContext, + node: ts.CallExpression, + kind: ExtensionKind +): ts.Expression | undefined { + return getNaryCallExtensionArgs(context, node, kind, 1)?.[0]; } -export function isExtensionValue( +export function getBinaryCallExtensionArgs( context: TransformationContext, - symbol: ts.Symbol, - extensionKind: ExtensionKind -): boolean { - return ( - symbol.getName() === extensionKindToValueName[extensionKind] && - symbol.declarations?.some(d => isExtensionType(context.checker.getTypeAtLocation(d), extensionKind)) === true - ); + node: ts.CallExpression, + kind: ExtensionKind +): readonly [ts.Expression, ts.Expression] | undefined { + const expressions = getNaryCallExtensionArgs(context, node, kind, 2); + if (expressions === undefined) return undefined; + return [expressions[0], expressions[1]]; } diff --git a/src/transformation/utils/lua-ast.ts b/src/transformation/utils/lua-ast.ts index 5f3a21e4a..59f6cffd7 100644 --- a/src/transformation/utils/lua-ast.ts +++ b/src/transformation/utils/lua-ast.ts @@ -4,7 +4,7 @@ import * as lua from "../../LuaAST"; import { assert, castArray } from "../../utils"; import { TransformationContext } from "../context"; import { createExportedIdentifier, getIdentifierExportScope } from "./export"; -import { peekScope, ScopeType, Scope } from "./scope"; +import { peekScope, ScopeType, Scope, addScopeVariableDeclaration } from "./scope"; import { transformLuaLibFunction } from "./lualib"; import { LuaLibFeature } from "../../LuaLib"; @@ -62,34 +62,56 @@ export function getNumberLiteralValue(expression?: lua.Expression) { return undefined; } -// Prefer use of transformToImmediatelyInvokedFunctionExpression to maintain correct scope. If you use this directly, -// ensure you push/pop a function scope appropriately to avoid incorrect vararg optimization. -export function createImmediatelyInvokedFunctionExpression( - statements: lua.Statement[], - result: lua.Expression | lua.Expression[], +export function createUnpackCall( + context: TransformationContext, + expression: lua.Expression, tsOriginal?: ts.Node -): lua.CallExpression { - const body = [...statements, lua.createReturnStatement(castArray(result))]; - const flags = statements.length === 0 ? lua.FunctionExpressionFlags.Inline : lua.FunctionExpressionFlags.None; - const iife = lua.createFunctionExpression(lua.createBlock(body), undefined, undefined, flags); - return lua.createCallExpression(iife, [], tsOriginal); +): lua.Expression { + if (context.luaTarget === LuaTarget.Universal) { + return transformLuaLibFunction(context, LuaLibFeature.Unpack, tsOriginal, expression); + } + + const unpack = + context.luaTarget === LuaTarget.Lua50 || + context.luaTarget === LuaTarget.Lua51 || + context.luaTarget === LuaTarget.LuaJIT + ? lua.createIdentifier("unpack") + : lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("unpack")); + + return lua.setNodeFlags(lua.createCallExpression(unpack, [expression], tsOriginal), lua.NodeFlags.TableUnpackCall); } -export function createUnpackCall( +export function createBoundedUnpackCall( context: TransformationContext, expression: lua.Expression, + maxUnpackItem: number, tsOriginal?: ts.Node ): lua.Expression { if (context.luaTarget === LuaTarget.Universal) { return transformLuaLibFunction(context, LuaLibFeature.Unpack, tsOriginal, expression); } + // Lua 5.0 does not support this signature, so don't add the arguments there + const extraArgs = + context.luaTarget === LuaTarget.Lua50 + ? [] + : [lua.createNumericLiteral(1), lua.createNumericLiteral(maxUnpackItem)]; + const unpack = - context.luaTarget === LuaTarget.Lua51 || context.luaTarget === LuaTarget.LuaJIT + context.luaTarget === LuaTarget.Lua50 || + context.luaTarget === LuaTarget.Lua51 || + context.luaTarget === LuaTarget.LuaJIT ? lua.createIdentifier("unpack") : lua.createTableIndexExpression(lua.createIdentifier("table"), lua.createStringLiteral("unpack")); - return lua.createCallExpression(unpack, [expression], tsOriginal); + return lua.setNodeFlags( + lua.createCallExpression(unpack, [expression, ...extraArgs], tsOriginal), + lua.NodeFlags.TableUnpackCall + ); +} + +export function isUnpackCall(node: lua.Node): boolean { + return lua.isCallExpression(node) && (node.flags & lua.NodeFlags.TableUnpackCall) !== 0; } export function wrapInTable(...expressions: lua.Expression[]): lua.TableExpression { @@ -119,12 +141,7 @@ export function createHoistableVariableDeclarationStatement( if (identifier.symbolId !== undefined) { const scope = peekScope(context); assert(scope.type !== ScopeType.Switch); - - if (!scope.variableDeclarations) { - scope.variableDeclarations = []; - } - - scope.variableDeclarations.push(declaration); + addScopeVariableDeclaration(scope, declaration); } return declaration; @@ -151,6 +168,8 @@ export function createLocalOrExportedOrGlobalDeclaration( let declaration: lua.VariableDeclarationStatement | undefined; let assignment: lua.AssignmentStatement | undefined; + const noImplicitGlobalVariables = context.options.noImplicitGlobalVariables === true; + const isFunctionDeclaration = tsOriginal !== undefined && ts.isFunctionDeclaration(tsOriginal); const identifiers = castArray(lhs); @@ -174,26 +193,27 @@ export function createLocalOrExportedOrGlobalDeclaration( const scope = peekScope(context); const isTopLevelVariable = scope.type === ScopeType.File; - if (context.isModule || !isTopLevelVariable) { - if (scope.type === ScopeType.Switch || (!isFunctionDeclaration && hasMultipleReferences(scope, lhs))) { - // Split declaration and assignment of identifiers that reference themselves in their declaration - declaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal); + if (context.isModule || !isTopLevelVariable || noImplicitGlobalVariables) { + const isLuaFunctionExpression = rhs && !Array.isArray(rhs) && lua.isFunctionExpression(rhs); + const isSafeRecursiveFunctionDeclaration = isFunctionDeclaration && isLuaFunctionExpression; + if (!isSafeRecursiveFunctionDeclaration && hasMultipleReferences(scope, lhs)) { + // Split declaration and assignment of identifiers that reference themselves in their declaration. + // Put declaration above preceding statements in case the identifier is referenced in those. + const precedingDeclaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal); + context.prependPrecedingStatements(precedingDeclaration); if (rhs) { assignment = lua.createAssignmentStatement(lhs, rhs, tsOriginal); } + + // Remember local variable declarations for hoisting later + addScopeVariableDeclaration(scope, precedingDeclaration); } else { declaration = lua.createVariableDeclarationStatement(lhs, rhs, tsOriginal); - } - - // Remember local variable declarations for hoisting later - if (!scope.variableDeclarations) { - scope.variableDeclarations = []; - } - scope.variableDeclarations.push(declaration); - - if (scope.type === ScopeType.Switch) { - declaration = undefined; + if (!isFunctionDeclaration) { + // Remember local variable declarations for hoisting later + addScopeVariableDeclaration(scope, declaration); + } } } else if (rhs) { // global @@ -215,6 +235,8 @@ export function createLocalOrExportedOrGlobalDeclaration( } } + setJSDocComments(context, tsOriginal, declaration, assignment); + if (declaration && assignment) { return [declaration, assignment]; } else if (declaration) { @@ -226,6 +248,105 @@ export function createLocalOrExportedOrGlobalDeclaration( } } +/** + * Apply JSDoc comments to the newly-created Lua statement, if present. + * https://stackoverflow.com/questions/47429792/is-it-possible-to-get-comments-as-nodes-in-the-ast-using-the-typescript-compiler + */ +function setJSDocComments( + context: TransformationContext, + tsOriginal: ts.Node | undefined, + declaration: lua.VariableDeclarationStatement | undefined, + assignment: lua.AssignmentStatement | undefined +) { + // Respect the vanilla TypeScript option of "removeComments": + // https://www.typescriptlang.org/tsconfig#removeComments + if (context.options.removeComments) { + return; + } + + const docCommentArray = getJSDocCommentFromTSNode(context, tsOriginal); + if (docCommentArray === undefined) { + return; + } + + if (declaration && assignment) { + declaration.leadingComments = docCommentArray; + } else if (declaration) { + declaration.leadingComments = docCommentArray; + } else if (assignment) { + assignment.leadingComments = docCommentArray; + } +} + +function getJSDocCommentFromTSNode( + context: TransformationContext, + tsOriginal: ts.Node | undefined +): string[] | undefined { + if (tsOriginal === undefined) { + return undefined; + } + + // The "name" property is only on a subset of node types; we want to be permissive and get the + // comments from as many nodes as possible. + const node = tsOriginal as any; + if (node.name === undefined) { + return undefined; + } + + const symbol = context.checker.getSymbolAtLocation(node.name); + if (symbol === undefined) { + return undefined; + } + + // The TypeScript compiler separates JSDoc comments into the "documentation comment" and the + // "tags". The former is conventionally at the top of the comment, and the bottom is + // conventionally at the bottom. We need to get both from the TypeScript API and then combine + // them into one block of text. + const docCommentArray = symbol.getDocumentationComment(context.checker); + const docCommentText = ts.displayPartsToString(docCommentArray).trim(); + + const jsDocTagInfoArray = symbol.getJsDocTags(context.checker); + const jsDocTagsTextLines = jsDocTagInfoArray.map(jsDocTagInfo => { + let text = "@" + jsDocTagInfo.name; + if (jsDocTagInfo.text !== undefined) { + const tagDescriptionTextArray = jsDocTagInfo.text + .filter(symbolDisplayPart => symbolDisplayPart.text.trim() !== "") + .map(symbolDisplayPart => symbolDisplayPart.text.trim()); + const tagDescriptionText = tagDescriptionTextArray.join(" "); + text += " " + tagDescriptionText; + } + return text; + }); + const jsDocTagsText = jsDocTagsTextLines.join("\n"); + + const combined = (docCommentText + "\n\n" + jsDocTagsText).trim(); + if (combined === "") { + return undefined; + } + + // By default, TSTL will display comments immediately next to the "--" characters. We can make + // the comments look better if we separate them by a space (similar to what Prettier does in + // JavaScript/TypeScript). + const linesWithoutSpace = combined.split("\n"); + const lines = linesWithoutSpace.map(line => ` ${line}`); + + // We want to JSDoc comments to map on to LDoc comments: + // https://stevedonovan.github.io/ldoc/manual/doc.md.html + // LDoc comments require that the first line starts with three hyphens. + // Thus, need to add a hyphen to the first line. + if (lines.length > 0) { + const firstLine = lines[0]; + if (firstLine.startsWith(" @")) { + lines.unshift("-"); + } else { + lines.shift(); + lines.unshift("-" + firstLine); + } + + return lines; + } +} + export const createNaN = (tsOriginal?: ts.Node) => lua.createBinaryExpression( lua.createNumericLiteral(0), diff --git a/src/transformation/utils/lualib.ts b/src/transformation/utils/lualib.ts index 3c2d0ec1b..ee828d1b9 100644 --- a/src/transformation/utils/lualib.ts +++ b/src/transformation/utils/lualib.ts @@ -1,18 +1,12 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { LuaLibFeature } from "../../LuaLib"; -import { getOrUpdate } from "../../utils"; import { TransformationContext } from "../context"; export { LuaLibFeature }; -const luaLibFeatures = new WeakMap>(); -export function getUsedLuaLibFeatures(context: TransformationContext): Set { - return getOrUpdate(luaLibFeatures, context, () => new Set()); -} - export function importLuaLibFeature(context: TransformationContext, feature: LuaLibFeature): void { - getUsedLuaLibFeatures(context).add(feature); + context.usedLuaLibFeatures.add(feature); } export function transformLuaLibFunction( diff --git a/src/transformation/utils/preceding-statements.ts b/src/transformation/utils/preceding-statements.ts new file mode 100644 index 000000000..16cefac12 --- /dev/null +++ b/src/transformation/utils/preceding-statements.ts @@ -0,0 +1,18 @@ +import * as lua from "../../LuaAST"; +import { TransformationContext } from "../context"; + +export interface WithPrecedingStatements< + T extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[] +> { + precedingStatements: lua.Statement[]; + result: T; +} + +export function transformInPrecedingStatementScope< + TReturn extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[] +>(context: TransformationContext, transformer: () => TReturn): WithPrecedingStatements { + context.pushPrecedingStatements(); + const statementOrStatements = transformer(); + const precedingStatements = context.popPrecedingStatements(); + return { precedingStatements, result: statementOrStatements }; +} diff --git a/src/transformation/utils/safe-names.ts b/src/transformation/utils/safe-names.ts index 877196ba4..0772d71a8 100644 --- a/src/transformation/utils/safe-names.ts +++ b/src/transformation/utils/safe-names.ts @@ -1,12 +1,23 @@ import * as ts from "typescript"; +import { CompilerOptions, LuaTarget } from "../.."; import { TransformationContext } from "../context"; import { invalidAmbientIdentifierName } from "./diagnostics"; import { isSymbolExported } from "./export"; import { isAmbientNode } from "./typescript"; -export const isValidLuaIdentifier = (name: string) => !luaKeywords.has(name) && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name); +export const shouldAllowUnicode = (options: CompilerOptions) => options.luaTarget === LuaTarget.LuaJIT; + +export const isValidLuaIdentifier = (name: string, options: CompilerOptions) => + !luaKeywords.has(name) && + (shouldAllowUnicode(options) + ? /^[a-zA-Z_\u007F-\uFFFD][a-zA-Z0-9_\u007F-\uFFFD]*$/ + : /^[a-zA-Z_][a-zA-Z0-9_]*$/ + ).test(name); + export const luaKeywords: ReadonlySet = new Set([ "and", + "bit", + "bit32", "break", "do", "else", @@ -52,10 +63,11 @@ const luaBuiltins: ReadonlySet = new Set([ "unpack", ]); -export const isUnsafeName = (name: string) => !isValidLuaIdentifier(name) || luaBuiltins.has(name); +export const isUnsafeName = (name: string, options: CompilerOptions) => + !isValidLuaIdentifier(name, options) || luaBuiltins.has(name); function checkName(context: TransformationContext, name: string, node: ts.Node): boolean { - const isInvalid = !isValidLuaIdentifier(name); + const isInvalid = !isValidLuaIdentifier(name, context.options); if (isInvalid) { // Empty identifier is a TypeScript error @@ -80,19 +92,16 @@ export function hasUnsafeSymbolName( } // only unsafe when non-ambient and not exported - return isUnsafeName(symbol.name) && !isAmbient && !isSymbolExported(context, symbol); + return isUnsafeName(symbol.name, context.options) && !isAmbient && !isSymbolExported(context, symbol); } export function hasUnsafeIdentifierName( context: TransformationContext, identifier: ts.Identifier, - checkSymbol = true + symbol: ts.Symbol | undefined ): boolean { - if (checkSymbol) { - const symbol = context.checker.getSymbolAtLocation(identifier); - if (symbol) { - return hasUnsafeSymbolName(context, symbol, identifier); - } + if (symbol) { + return hasUnsafeSymbolName(context, symbol, identifier); } return checkName(context, identifier.text, identifier); diff --git a/src/transformation/utils/scope.ts b/src/transformation/utils/scope.ts index 53169765a..314f1d795 100644 --- a/src/transformation/utils/scope.ts +++ b/src/transformation/utils/scope.ts @@ -14,6 +14,7 @@ export enum ScopeType { Block = 1 << 5, Try = 1 << 6, Catch = 1 << 7, + LoopInitializer = 1 << 8, } interface FunctionDefinitionInfo { @@ -21,25 +22,35 @@ interface FunctionDefinitionInfo { definition?: lua.VariableDeclarationStatement | lua.AssignmentStatement; } +export enum LoopContinued { + WithGoto, + WithRepeatBreak, + WithContinue, +} + export interface Scope { type: ScopeType; id: number; - node?: ts.Node; + node: ts.Node; referencedSymbols?: Map; variableDeclarations?: lua.VariableDeclarationStatement[]; functionDefinitions?: Map; importStatements?: lua.Statement[]; - loopContinued?: boolean; + loopContinued?: LoopContinued; functionReturned?: boolean; + asyncTryHasReturn?: boolean; + asyncTryHasBreak?: boolean; + asyncTryHasContinue?: LoopContinued; } -const scopeStacks = new WeakMap(); -function getScopeStack(context: TransformationContext): Scope[] { - return getOrUpdate(scopeStacks, context, () => []); +export interface HoistingResult { + statements: lua.Statement[]; + hoistedStatements: lua.Statement[]; + hoistedIdentifiers: lua.Identifier[]; } export function* walkScopesUp(context: TransformationContext): IterableIterator { - const scopeStack = getScopeStack(context); + const scopeStack = context.scopeStack; for (let i = scopeStack.length - 1; i >= 0; --i) { const scope = scopeStack[i]; yield scope; @@ -51,10 +62,8 @@ export function markSymbolAsReferencedInCurrentScopes( symbolId: lua.SymbolId, identifier: ts.Identifier ): void { - for (const scope of getScopeStack(context)) { - if (!scope.referencedSymbols) { - scope.referencedSymbols = new Map(); - } + for (const scope of context.scopeStack) { + scope.referencedSymbols ??= new Map(); const references = getOrUpdate(scope.referencedSymbols, symbolId, () => []); references.push(identifier); @@ -62,7 +71,7 @@ export function markSymbolAsReferencedInCurrentScopes( } export function peekScope(context: TransformationContext): Scope { - const scopeStack = getScopeStack(context); + const scopeStack = context.scopeStack; const scope = scopeStack[scopeStack.length - 1]; assert(scope); @@ -70,26 +79,35 @@ export function peekScope(context: TransformationContext): Scope { } export function findScope(context: TransformationContext, scopeTypes: ScopeType): Scope | undefined { - return [...getScopeStack(context)].reverse().find(s => scopeTypes & s.type); + for (let i = context.scopeStack.length - 1; i >= 0; --i) { + const scope = context.scopeStack[i]; + if (scopeTypes & scope.type) { + return scope; + } + } } -const scopeIdCounters = new WeakMap(); -export function pushScope(context: TransformationContext, scopeType: ScopeType): Scope { - const nextScopeId = (scopeIdCounters.get(context) ?? 0) + 1; - scopeIdCounters.set(context, nextScopeId); +export function findAsyncTryScopeInStack(context: TransformationContext): Scope | undefined { + for (const scope of walkScopesUp(context)) { + if (scope.type === ScopeType.Function) return undefined; + if (scope.type === ScopeType.Try || scope.type === ScopeType.Catch) return scope; + } + return undefined; +} - const scopeStack = getScopeStack(context); - const scope: Scope = { type: scopeType, id: nextScopeId }; - scopeStack.push(scope); - return scope; +/** Like findAsyncTryScopeInStack, but also stops at Loop boundaries. */ +export function findAsyncTryScopeBeforeLoop(context: TransformationContext): Scope | undefined { + for (const scope of walkScopesUp(context)) { + if (scope.type === ScopeType.Function || scope.type === ScopeType.Loop) return undefined; + if (scope.type === ScopeType.Try || scope.type === ScopeType.Catch) return scope; + } + return undefined; } -export function popScope(context: TransformationContext): Scope { - const scopeStack = getScopeStack(context); - const scope = scopeStack.pop(); - assert(scope); +export function addScopeVariableDeclaration(scope: Scope, declaration: lua.VariableDeclarationStatement) { + scope.variableDeclarations ??= []; - return scope; + scope.variableDeclarations.push(declaration); } function isHoistableFunctionDeclaredInScope(symbol: ts.Symbol, scopeNode: ts.Node) { @@ -101,7 +119,7 @@ function isHoistableFunctionDeclaredInScope(symbol: ts.Symbol, scopeNode: ts.Nod // Checks for references to local functions which haven't been defined yet, // and thus will be hoisted above the current position. export function hasReferencedUndefinedLocalFunction(context: TransformationContext, scope: Scope) { - if (!scope.referencedSymbols || !scope.node) { + if (!scope.referencedSymbols) { return false; } for (const [symbolId, nodes] of scope.referencedSymbols) { @@ -129,20 +147,47 @@ export function hasReferencedSymbol(context: TransformationContext, scope: Scope return false; } -export function isFunctionScopeWithDefinition(scope: Scope): scope is Scope & { node: ts.SignatureDeclaration } { - return scope.node !== undefined && ts.isFunctionLike(scope.node); +export function separateHoistedStatements(context: TransformationContext, statements: lua.Statement[]): HoistingResult { + const scope = peekScope(context); + const allHoistedStatments: lua.Statement[] = []; + const allHoistedIdentifiers: lua.Identifier[] = []; + + let { unhoistedStatements, hoistedStatements, hoistedIdentifiers } = hoistFunctionDefinitions( + context, + scope, + statements + ); + allHoistedStatments.push(...hoistedStatements); + allHoistedIdentifiers.push(...hoistedIdentifiers); + + ({ unhoistedStatements, hoistedIdentifiers } = hoistVariableDeclarations(context, scope, unhoistedStatements)); + allHoistedIdentifiers.push(...hoistedIdentifiers); + + ({ unhoistedStatements, hoistedStatements } = hoistImportStatements(scope, unhoistedStatements)); + allHoistedStatments.unshift(...hoistedStatements); + + return { + statements: unhoistedStatements, + hoistedStatements: allHoistedStatments, + hoistedIdentifiers: allHoistedIdentifiers, + }; } export function performHoisting(context: TransformationContext, statements: lua.Statement[]): lua.Statement[] { - const scope = peekScope(context); - let result = statements; - result = hoistFunctionDefinitions(context, scope, result); - result = hoistVariableDeclarations(context, scope, result); - result = hoistImportStatements(scope, result); - return result; + const result = separateHoistedStatements(context, statements); + const modifiedStatements = [...result.hoistedStatements, ...result.statements]; + if (result.hoistedIdentifiers.length > 0) { + modifiedStatements.unshift(lua.createVariableDeclarationStatement(result.hoistedIdentifiers)); + } + return modifiedStatements; } function shouldHoistSymbol(context: TransformationContext, symbolId: lua.SymbolId, scope: Scope): boolean { + // Always hoist in top-level of switch statements + if (scope.type === ScopeType.Switch) { + return true; + } + const symbolInfo = getSymbolInfo(context, symbolId); if (!symbolInfo) { return false; @@ -183,65 +228,80 @@ function hoistVariableDeclarations( context: TransformationContext, scope: Scope, statements: lua.Statement[] -): lua.Statement[] { +): { unhoistedStatements: lua.Statement[]; hoistedIdentifiers: lua.Identifier[] } { if (!scope.variableDeclarations) { - return statements; + return { unhoistedStatements: statements, hoistedIdentifiers: [] }; } - const result = [...statements]; - const hoistedLocals: lua.Identifier[] = []; + const unhoistedStatements = [...statements]; + const hoistedIdentifiers: lua.Identifier[] = []; for (const declaration of scope.variableDeclarations) { const symbols = declaration.left.map(i => i.symbolId).filter(isNonNull); if (symbols.some(s => shouldHoistSymbol(context, s, scope))) { - const index = result.indexOf(declaration); - assert(index > -1); + const index = unhoistedStatements.indexOf(declaration); + if (index < 0) { + continue; // statements array may not contain all statements in the scope (switch-case) + } if (declaration.right) { const assignment = lua.createAssignmentStatement(declaration.left, declaration.right); lua.setNodePosition(assignment, declaration); // Preserve position info for sourcemap - result.splice(index, 1, assignment); + unhoistedStatements.splice(index, 1, assignment); } else { - result.splice(index, 1); + unhoistedStatements.splice(index, 1); } - hoistedLocals.push(...declaration.left); - } else if (scope.type === ScopeType.Switch) { - assert(!declaration.right); - hoistedLocals.push(...declaration.left); + hoistedIdentifiers.push(...declaration.left); } } - if (hoistedLocals.length > 0) { - result.unshift(lua.createVariableDeclarationStatement(hoistedLocals)); - } - - return result; + return { unhoistedStatements, hoistedIdentifiers }; } function hoistFunctionDefinitions( context: TransformationContext, scope: Scope, statements: lua.Statement[] -): lua.Statement[] { +): { unhoistedStatements: lua.Statement[]; hoistedStatements: lua.Statement[]; hoistedIdentifiers: lua.Identifier[] } { if (!scope.functionDefinitions) { - return statements; + return { unhoistedStatements: statements, hoistedStatements: [], hoistedIdentifiers: [] }; } - const result = [...statements]; - const hoistedFunctions: Array = []; + const unhoistedStatements = [...statements]; + const hoistedStatements: lua.Statement[] = []; + const hoistedIdentifiers: lua.Identifier[] = []; for (const [functionSymbolId, functionDefinition] of scope.functionDefinitions) { assert(functionDefinition.definition); if (shouldHoistSymbol(context, functionSymbolId, scope)) { - const index = result.indexOf(functionDefinition.definition); - result.splice(index, 1); - hoistedFunctions.push(functionDefinition.definition); + const index = unhoistedStatements.indexOf(functionDefinition.definition); + if (index < 0) { + continue; // statements array may not contain all statements in the scope (switch-case) + } + unhoistedStatements.splice(index, 1); + + if (lua.isVariableDeclarationStatement(functionDefinition.definition)) { + // Separate function definition and variable declaration + assert(functionDefinition.definition.right); + hoistedIdentifiers.push(...functionDefinition.definition.left); + hoistedStatements.push( + lua.createAssignmentStatement( + functionDefinition.definition.left, + functionDefinition.definition.right + ) + ); + } else { + hoistedStatements.push(functionDefinition.definition); + } } } - return [...hoistedFunctions, ...result]; + return { unhoistedStatements, hoistedStatements, hoistedIdentifiers }; } -function hoistImportStatements(scope: Scope, statements: lua.Statement[]): lua.Statement[] { - return scope.importStatements ? [...scope.importStatements, ...statements] : statements; +function hoistImportStatements( + scope: Scope, + statements: lua.Statement[] +): { unhoistedStatements: lua.Statement[]; hoistedStatements: lua.Statement[] } { + return { unhoistedStatements: statements, hoistedStatements: scope.importStatements ?? [] }; } diff --git a/src/transformation/utils/symbols.ts b/src/transformation/utils/symbols.ts index f800eea86..d79b68da8 100644 --- a/src/transformation/utils/symbols.ts +++ b/src/transformation/utils/symbols.ts @@ -1,31 +1,20 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; -import { getOrUpdate } from "../../utils"; import { TransformationContext } from "../context"; import { isOptimizedVarArgSpread } from "../visitors/spread"; import { markSymbolAsReferencedInCurrentScopes } from "./scope"; -const symbolIdCounters = new WeakMap(); -function nextSymbolId(context: TransformationContext): lua.SymbolId { - const symbolId = (symbolIdCounters.get(context) ?? 0) + 1; - symbolIdCounters.set(context, symbolId); - return symbolId as lua.SymbolId; -} - export interface SymbolInfo { symbol: ts.Symbol; firstSeenAtPos: number; } -const symbolInfoMap = new WeakMap>(); -const symbolIdMaps = new WeakMap>(); - export function getSymbolInfo(context: TransformationContext, symbolId: lua.SymbolId): SymbolInfo | undefined { - return getOrUpdate(symbolInfoMap, context, () => new Map()).get(symbolId); + return context.symbolInfoMap.get(symbolId); } export function getSymbolIdOfSymbol(context: TransformationContext, symbol: ts.Symbol): lua.SymbolId | undefined { - return getOrUpdate(symbolIdMaps, context, () => new Map()).get(symbol); + return context.symbolIdMaps.get(symbol); } export function trackSymbolReference( @@ -33,16 +22,13 @@ export function trackSymbolReference( symbol: ts.Symbol, identifier: ts.Identifier ): lua.SymbolId | undefined { - const symbolIds = getOrUpdate(symbolIdMaps, context, () => new Map()); - // Track first time symbols are seen - let symbolId = symbolIds.get(symbol); + let symbolId = context.symbolIdMaps.get(symbol); if (symbolId === undefined) { - symbolId = nextSymbolId(context); + symbolId = context.nextSymbolId(); - symbolIds.set(symbol, symbolId); - const symbolInfo = getOrUpdate(symbolInfoMap, context, () => new Map()); - symbolInfo.set(symbolId, { symbol, firstSeenAtPos: identifier.pos }); + context.symbolIdMaps.set(symbol, symbolId); + context.symbolInfoMap.set(symbolId, { symbol, firstSeenAtPos: identifier.pos }); } // If isOptimizedVarArgSpread returns true, the identifier will not appear in the resulting Lua. @@ -56,9 +42,9 @@ export function trackSymbolReference( export function getIdentifierSymbolId( context: TransformationContext, - identifier: ts.Identifier + identifier: ts.Identifier, + symbol: ts.Symbol | undefined ): lua.SymbolId | undefined { - const symbol = context.checker.getSymbolAtLocation(identifier); if (symbol) { return trackSymbolReference(context, symbol, identifier); } diff --git a/src/transformation/utils/transform.ts b/src/transformation/utils/transform.ts deleted file mode 100644 index 215a018d5..000000000 --- a/src/transformation/utils/transform.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as ts from "typescript"; -import * as lua from "../../LuaAST"; -import { castArray } from "../../utils"; -import { TransformationContext } from "../context"; -import { createImmediatelyInvokedFunctionExpression } from "./lua-ast"; -import { ScopeType, pushScope, popScope } from "./scope"; - -export interface ImmediatelyInvokedFunctionParameters { - statements: lua.Statement | lua.Statement[]; - result: lua.Expression | lua.Expression[]; -} - -export function transformToImmediatelyInvokedFunctionExpression( - context: TransformationContext, - transformFunction: () => ImmediatelyInvokedFunctionParameters, - tsOriginal?: ts.Node -): lua.CallExpression { - pushScope(context, ScopeType.Function); - const { statements, result } = transformFunction(); - popScope(context); - return createImmediatelyInvokedFunctionExpression(castArray(statements), result, tsOriginal); -} diff --git a/src/transformation/utils/typescript/index.ts b/src/transformation/utils/typescript/index.ts index 6d7bfa68c..f12bf4721 100644 --- a/src/transformation/utils/typescript/index.ts +++ b/src/transformation/utils/typescript/index.ts @@ -14,16 +14,30 @@ export function hasExportEquals(sourceFile: ts.SourceFile): boolean { * Search up until finding a node satisfying the callback */ export function findFirstNodeAbove(node: ts.Node, callback: (n: ts.Node) => n is T): T | undefined { - let current = node; + // Synthetic nodes (created by pre-transformers like usingTransformer) may have an unset .parent. + // Fall back to ts.getOriginalNode so we can still walk the source-parsed parent chain. + let current = ts.getOriginalNode(node); while (current.parent) { if (callback(current.parent)) { return current.parent; } else { - current = current.parent; + current = ts.getOriginalNode(current.parent); } } } +export function findFirstNonOuterParent(node: ts.Node): ts.Node { + let current = ts.getOriginalNode(node).parent; + while (ts.isOuterExpression(current)) { + current = ts.getOriginalNode(current).parent; + } + return current; +} + +export function expressionResultIsUsed(node: ts.Expression): boolean { + return !ts.isExpressionStatement(findFirstNonOuterParent(node)); +} + export function getFirstDeclarationInFile(symbol: ts.Symbol, sourceFile: ts.SourceFile): ts.Declaration | undefined { const originalSourceFile = ts.getParseTreeNode(sourceFile) ?? sourceFile; const declarations = (symbol.getDeclarations() ?? []).filter(d => d.getSourceFile() === originalSourceFile); @@ -31,7 +45,7 @@ export function getFirstDeclarationInFile(symbol: ts.Symbol, sourceFile: ts.Sour return declarations.length > 0 ? declarations.reduce((p, c) => (p.pos < c.pos ? p : c)) : undefined; } -function isStandardLibraryDeclaration(context: TransformationContext, declaration: ts.Declaration): boolean { +export function isStandardLibraryDeclaration(context: TransformationContext, declaration: ts.Declaration): boolean { const parseTreeNode = ts.getParseTreeNode(declaration) ?? declaration; const sourceFile = parseTreeNode.getSourceFile(); if (!sourceFile) { @@ -83,7 +97,7 @@ export function isExpressionWithEvaluationEffect(node: ts.Expression): boolean { export function getFunctionTypeForCall(context: TransformationContext, node: ts.CallExpression) { const signature = context.checker.getResolvedSignature(node); - if (!signature || !signature.declaration) { + if (!signature?.declaration) { return; } const typeDeclaration = findFirstNodeAbove(signature.declaration, ts.isTypeAliasDeclaration); @@ -92,3 +106,20 @@ export function getFunctionTypeForCall(context: TransformationContext, node: ts. } return context.checker.getTypeFromTypeNode(typeDeclaration.type); } + +export function isConstIdentifier(context: TransformationContext, node: ts.Node) { + let identifier = node; + if (ts.isComputedPropertyName(identifier)) { + identifier = identifier.expression; + } + if (!ts.isIdentifier(identifier)) { + return false; + } + const symbol = context.checker.getSymbolAtLocation(identifier); + if (!symbol?.declarations) { + return false; + } + return symbol.declarations.some( + d => ts.isVariableDeclarationList(d.parent) && (d.parent.flags & ts.NodeFlags.Const) !== 0 + ); +} diff --git a/src/transformation/utils/typescript/nodes.ts b/src/transformation/utils/typescript/nodes.ts index 3007c4d7d..09e2791c7 100644 --- a/src/transformation/utils/typescript/nodes.ts +++ b/src/transformation/utils/typescript/nodes.ts @@ -1,4 +1,5 @@ import * as ts from "typescript"; +import { findFirstNodeAbove } from "."; import { TransformationContext } from "../../context"; export function isAssignmentPattern(node: ts.Node): node is ts.AssignmentPattern { @@ -25,6 +26,30 @@ export function isInDestructingAssignment(node: ts.Node): boolean { ); } +export function isInAsyncFunction(node: ts.Node): boolean { + // Check if node is in function declaration with `async` + const declaration = findFirstNodeAbove(node, ts.isFunctionLike); + if (!declaration) { + return false; + } + + if (ts.canHaveModifiers(declaration)) { + return ts.getModifiers(declaration)?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false; + } else { + return false; + } +} + +export function isInGeneratorFunction(node: ts.Node): boolean { + // Check if node is in function declaration with `async` + const declaration = findFirstNodeAbove(node, ts.isFunctionDeclaration); + if (!declaration) { + return false; + } + + return declaration.asteriskToken !== undefined; +} + /** * Quite hacky, avoid unless absolutely necessary! */ diff --git a/src/transformation/utils/typescript/types.ts b/src/transformation/utils/typescript/types.ts index 2c6e69dcb..4a356b972 100644 --- a/src/transformation/utils/typescript/types.ts +++ b/src/transformation/utils/typescript/types.ts @@ -1,69 +1,75 @@ import * as ts from "typescript"; import { TransformationContext } from "../../context"; -export function isTypeWithFlags(context: TransformationContext, type: ts.Type, flags: ts.TypeFlags): boolean { - const predicate = (type: ts.Type) => { - if (type.symbol) { - const baseConstraint = context.checker.getBaseConstraintOfType(type); - if (baseConstraint && baseConstraint !== type) { - return isTypeWithFlags(context, baseConstraint, flags); - } - } - return (type.flags & flags) !== 0; - }; - - return typeAlwaysSatisfies(context, type, predicate); -} +export function typeAlwaysHasSomeOfFlags(context: TransformationContext, type: ts.Type, flags: ts.TypeFlags): boolean { + const baseConstraint = context.checker.getBaseConstraintOfType(type); + if (baseConstraint) { + type = baseConstraint; + } -export function typeAlwaysSatisfies( - context: TransformationContext, - type: ts.Type, - predicate: (type: ts.Type) => boolean -): boolean { - if (predicate(type)) { + if (type.flags & flags) { return true; } if (type.isUnion()) { - return type.types.every(t => typeAlwaysSatisfies(context, t, predicate)); + return type.types.every(t => typeAlwaysHasSomeOfFlags(context, t, flags)); } if (type.isIntersection()) { - return type.types.some(t => typeAlwaysSatisfies(context, t, predicate)); + return type.types.some(t => typeAlwaysHasSomeOfFlags(context, t, flags)); } return false; } -export function typeCanSatisfy( - context: TransformationContext, - type: ts.Type, - predicate: (type: ts.Type) => boolean -): boolean { - if (predicate(type)) { +export function typeCanHaveSomeOfFlags(context: TransformationContext, type: ts.Type, flags: ts.TypeFlags): boolean { + const baseConstraint = context.checker.getBaseConstraintOfType(type); + if (!baseConstraint) { + // type parameter with no constraint can be anything, assume it might satisfy predicate + if (type.isTypeParameter()) return true; + } else { + type = baseConstraint; + } + + if (type.flags & flags) { return true; } if (type.isUnion()) { - return type.types.some(t => typeCanSatisfy(context, t, predicate)); + return type.types.some(t => typeCanHaveSomeOfFlags(context, t, flags)); } if (type.isIntersection()) { - return type.types.some(t => typeCanSatisfy(context, t, predicate)); + return type.types.some(t => typeCanHaveSomeOfFlags(context, t, flags)); } return false; } export function isStringType(context: TransformationContext, type: ts.Type): boolean { - return isTypeWithFlags(context, type, ts.TypeFlags.String | ts.TypeFlags.StringLike | ts.TypeFlags.StringLiteral); + return typeAlwaysHasSomeOfFlags(context, type, ts.TypeFlags.StringLike); } export function isNumberType(context: TransformationContext, type: ts.Type): boolean { - return isTypeWithFlags(context, type, ts.TypeFlags.Number | ts.TypeFlags.NumberLike | ts.TypeFlags.NumberLiteral); + return typeAlwaysHasSomeOfFlags(context, type, ts.TypeFlags.NumberLike); } function isExplicitArrayType(context: TransformationContext, type: ts.Type): boolean { + if (context.checker.isArrayType(type) || context.checker.isTupleType(type)) return true; + + if (type.isUnionOrIntersection()) { + if (type.types.some(t => isExplicitArrayType(context, t))) { + return true; + } + } + + const baseTypes = type.getBaseTypes(); + if (baseTypes) { + if (baseTypes.some(t => isExplicitArrayType(context, t))) { + return true; + } + } + if (type.symbol) { const baseConstraint = context.checker.getBaseConstraintOfType(type); if (baseConstraint && baseConstraint !== type) { @@ -71,17 +77,23 @@ function isExplicitArrayType(context: TransformationContext, type: ts.Type): boo } } - if (type.isUnionOrIntersection()) { - return type.types.some(t => isExplicitArrayType(context, t)); + return false; +} + +function isAlwaysExplicitArrayType(context: TransformationContext, type: ts.Type): boolean { + if (context.checker.isArrayType(type) || context.checker.isTupleType(type)) return true; + if (type.symbol) { + const baseConstraint = context.checker.getBaseConstraintOfType(type); + if (baseConstraint && baseConstraint !== type) { + return isAlwaysExplicitArrayType(context, baseConstraint); + } } - const flags = ts.NodeBuilderFlags.InTypeAlias | ts.NodeBuilderFlags.AllowEmptyTuple; - let typeNode = context.checker.typeToTypeNode(type, undefined, flags); - if (typeNode && ts.isTypeOperatorNode(typeNode) && typeNode.operator === ts.SyntaxKind.ReadonlyKeyword) { - typeNode = typeNode.type; + if (type.isUnionOrIntersection()) { + return type.types.every(t => isAlwaysExplicitArrayType(context, t)); } - return typeNode !== undefined && (ts.isArrayTypeNode(typeNode) || ts.isTupleTypeNode(typeNode)); + return false; } /** @@ -100,14 +112,45 @@ export function forTypeOrAnySupertype( type = context.checker.getDeclaredTypeOfSymbol(type.symbol); } - return (type.getBaseTypes() ?? []).some(superType => forTypeOrAnySupertype(context, superType, predicate)); + const baseTypes = type.getBaseTypes(); + if (!baseTypes) return false; + return baseTypes.some(superType => forTypeOrAnySupertype(context, superType, predicate)); } export function isArrayType(context: TransformationContext, type: ts.Type): boolean { return forTypeOrAnySupertype(context, type, t => isExplicitArrayType(context, t)); } -export function isFunctionType(context: TransformationContext, type: ts.Type): boolean { - const typeNode = context.checker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.InTypeAlias); - return typeNode !== undefined && ts.isFunctionTypeNode(typeNode); +export function isAlwaysArrayType(context: TransformationContext, type: ts.Type): boolean { + return forTypeOrAnySupertype(context, type, t => isAlwaysExplicitArrayType(context, t)); +} + +export function isFunctionType(type: ts.Type): boolean { + return type.getCallSignatures().length > 0; +} + +export function canBeFalsy(context: TransformationContext, type: ts.Type): boolean { + const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true; + if (!strictNullChecks && !type.isLiteral()) return true; + const falsyFlags = + ts.TypeFlags.Boolean | + ts.TypeFlags.BooleanLiteral | + ts.TypeFlags.Never | + ts.TypeFlags.Void | + ts.TypeFlags.Unknown | + ts.TypeFlags.Any | + ts.TypeFlags.Undefined | + ts.TypeFlags.Null; + return typeCanHaveSomeOfFlags(context, type, falsyFlags); +} + +export function canBeFalsyWhenNotNull(context: TransformationContext, type: ts.Type): boolean { + const falsyFlags = + ts.TypeFlags.Boolean | + ts.TypeFlags.BooleanLiteral | + ts.TypeFlags.Never | + ts.TypeFlags.Void | + ts.TypeFlags.Unknown | + ts.TypeFlags.Any; + return typeCanHaveSomeOfFlags(context, type, falsyFlags); } diff --git a/src/transformation/visitors/access.ts b/src/transformation/visitors/access.ts index 8b795426b..7c96bdcd8 100644 --- a/src/transformation/visitors/access.ts +++ b/src/transformation/visitors/access.ts @@ -3,118 +3,216 @@ import * as lua from "../../LuaAST"; import { transformBuiltinPropertyAccessExpression } from "../builtins"; import { FunctionVisitor, TransformationContext } from "../context"; import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; -import { annotationRemoved, invalidMultiReturnAccess } from "../utils/diagnostics"; -import { addToNumericExpression } from "../utils/lua-ast"; +import { + invalidCallExtensionUse, + invalidMultiReturnAccess, + unsupportedOptionalCompileMembersOnly, +} from "../utils/diagnostics"; +import { getExtensionKindForNode } from "../utils/language-extensions"; +import { addToNumericExpression, createExportsIdentifier } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; import { isArrayType, isNumberType, isStringType } from "../utils/typescript"; import { tryGetConstEnumValue } from "./enum"; -import { returnsMultiType } from "./language-extensions/multi"; - -export function transformElementAccessArgument( +import { transformOrderedExpressions } from "./expression-list"; +import { callExtensions } from "./language-extensions/call-extension"; +import { isMultiReturnCall, returnsMultiType } from "./language-extensions/multi"; +import { + transformOptionalChainWithCapture, + ExpressionWithThisValue, + isOptionalContinuation, + captureThisValue, +} from "./optional-chaining"; +import { SyntaxKind } from "typescript"; +import { getCustomNameFromSymbol } from "./identifier"; +import { getSymbolExportScope, isSymbolExported } from "../utils/export"; + +function addOneToArrayAccessArgument( context: TransformationContext, - node: ts.ElementAccessExpression + node: ts.ElementAccessExpression, + index: lua.Expression ): lua.Expression { - const index = context.transformExpression(node.argumentExpression); - const type = context.checker.getTypeAtLocation(node.expression); const argumentType = context.checker.getTypeAtLocation(node.argumentExpression); if (isArrayType(context, type) && isNumberType(context, argumentType)) { return addToNumericExpression(index, 1); } - return index; } -export const transformElementAccessExpression: FunctionVisitor = (node, context) => { +export function transformElementAccessArgument( + context: TransformationContext, + node: ts.ElementAccessExpression +): lua.Expression { + const index = context.transformExpression(node.argumentExpression); + return addOneToArrayAccessArgument(context, node, index); +} + +export const transformElementAccessExpression: FunctionVisitor = (node, context) => + transformElementAccessExpressionWithCapture(context, node, undefined).expression; +export function transformElementAccessExpressionWithCapture( + context: TransformationContext, + node: ts.ElementAccessExpression, + thisValueCapture: lua.Identifier | undefined +): ExpressionWithThisValue { const constEnumValue = tryGetConstEnumValue(context, node); if (constEnumValue) { - return constEnumValue; + return { expression: constEnumValue }; } - const table = context.transformExpression(node.expression); + if (ts.isOptionalChain(node)) { + return transformOptionalChainWithCapture(context, node, thisValueCapture); + } + + const [table, accessExpression] = transformOrderedExpressions(context, [node.expression, node.argumentExpression]); const type = context.checker.getTypeAtLocation(node.expression); const argumentType = context.checker.getTypeAtLocation(node.argumentExpression); if (isStringType(context, type) && isNumberType(context, argumentType)) { - const index = context.transformExpression(node.argumentExpression); - return transformLuaLibFunction(context, LuaLibFeature.StringAccess, node, table, index); + // strings are not callable, so ignore thisValueCapture + return { + expression: transformLuaLibFunction(context, LuaLibFeature.StringAccess, node, table, accessExpression), + }; } - const accessExpression = transformElementAccessArgument(context, node); + const updatedAccessExpression = addOneToArrayAccessArgument(context, node, accessExpression); - if (ts.isCallExpression(node.expression) && returnsMultiType(context, node.expression)) { + if (isMultiReturnCall(context, node.expression)) { const accessType = context.checker.getTypeAtLocation(node.argumentExpression); if (!isNumberType(context, accessType)) { context.diagnostics.push(invalidMultiReturnAccess(node)); } + const canOmitSelect = ts.isNumericLiteral(node.argumentExpression) && node.argumentExpression.text === "0"; + if (canOmitSelect) { + // wrapping in parenthesis ensures only the first return value is used + // https://www.lua.org/manual/5.1/manual.html#2.5 + return { expression: lua.createParenthesizedExpression(table) }; + } + const selectIdentifier = lua.createIdentifier("select"); - const selectCall = lua.createCallExpression(selectIdentifier, [accessExpression, table]); - return selectCall; + return { expression: lua.createCallExpression(selectIdentifier, [updatedAccessExpression, table]) }; } - if (ts.isOptionalChain(node)) { - return transformLuaLibFunction(context, LuaLibFeature.OptionalChainAccess, node, table, accessExpression); + if (thisValueCapture) { + const thisValue = captureThisValue(context, table, thisValueCapture, node.expression); + return { + expression: lua.createTableIndexExpression(thisValue, updatedAccessExpression, node), + thisValue, + }; } + return { expression: lua.createTableIndexExpression(table, updatedAccessExpression, node) }; +} - return lua.createTableIndexExpression(table, accessExpression, node); -}; - -export const transformPropertyAccessExpression: FunctionVisitor = (node, context) => { - const property = node.name.text; +export const transformPropertyAccessExpression: FunctionVisitor = (node, context) => + transformPropertyAccessExpressionWithCapture(context, node, undefined).expression; +export function transformPropertyAccessExpressionWithCapture( + context: TransformationContext, + node: ts.PropertyAccessExpression, + thisValueCapture: lua.Identifier | undefined +): ExpressionWithThisValue { const type = context.checker.getTypeAtLocation(node.expression); + const isOptionalLeft = isOptionalContinuation(node.expression); - const annotations = getTypeAnnotations(type); - - if (annotations.has(AnnotationKind.LuaTable)) { - context.diagnostics.push(annotationRemoved(node, AnnotationKind.LuaTable)); + let property = node.name.text; + const symbol = context.checker.getSymbolAtLocation(node.name); + const customName = getCustomNameFromSymbol(context, symbol); + if (customName) { + property = customName; } const constEnumValue = tryGetConstEnumValue(context, node); if (constEnumValue) { - return constEnumValue; - } - - const builtinResult = transformBuiltinPropertyAccessExpression(context, node); - if (builtinResult) { - return builtinResult; + return { expression: constEnumValue }; } if (ts.isCallExpression(node.expression) && returnsMultiType(context, node.expression)) { context.diagnostics.push(invalidMultiReturnAccess(node)); } + if (ts.isOptionalChain(node)) { + return transformOptionalChainWithCapture(context, node, thisValueCapture); + } + // Do not output path for member only enums + const annotations = getTypeAnnotations(type); if (annotations.has(AnnotationKind.CompileMembersOnly)) { + if (isOptionalLeft) { + context.diagnostics.push(unsupportedOptionalCompileMembersOnly(node)); + } + if (ts.isPropertyAccessExpression(node.expression)) { // in case of ...x.enum.y transform to ...x.y - return lua.createTableIndexExpression( + const expression = lua.createTableIndexExpression( context.transformExpression(node.expression.expression), lua.createStringLiteral(property), node ); + return { expression }; } else { - return lua.createIdentifier(property, node); + // Check if we need to account for enum being exported int his file + if ( + isSymbolExported(context, type.symbol) && + getSymbolExportScope(context, type.symbol) === node.expression.getSourceFile() + ) { + return { + expression: lua.createTableIndexExpression( + createExportsIdentifier(), + lua.createStringLiteral(property), + node + ), + }; + } else { + return { expression: lua.createIdentifier(property, node) }; + } } } - if (ts.isOptionalChain(node)) { - // Only handle full optional chains separately, not partial ones - return transformOptionalChain(context, node); + const builtinResult = transformBuiltinPropertyAccessExpression(context, node); + if (builtinResult) { + // Ignore thisValueCapture. + // This assumes that nothing returned by builtin property accesses are callable. + // If this assumption is no longer true, this may need to be updated. + return { expression: builtinResult }; } - const callPath = context.transformExpression(node.expression); - return lua.createTableIndexExpression(callPath, lua.createStringLiteral(property), node); -}; + if ( + ts.isIdentifier(node.expression) && + node.parent && + (!ts.isCallExpression(node.parent) || node.parent.expression !== node) + ) { + // Check if this is a method call extension that is not used as a call + const extensionType = getExtensionKindForNode(context, node); + if (extensionType && callExtensions.has(extensionType)) { + context.diagnostics.push(invalidCallExtensionUse(node)); + } + } -function transformOptionalChain( - context: TransformationContext, - node: ts.OptionalChain & ts.PropertyAccessExpression -): lua.CallExpression { - const left = context.transformExpression(node.expression); - const right = lua.createStringLiteral(node.name.text, node.name); + const table = context.transformExpression(node.expression); - return transformLuaLibFunction(context, LuaLibFeature.OptionalChainAccess, node, left, right); + if (thisValueCapture) { + const thisValue = captureThisValue(context, table, thisValueCapture, node.expression); + const expression = lua.createTableIndexExpression(thisValue, lua.createStringLiteral(property), node); + return { + expression, + thisValue, + }; + } + if (node.expression.kind === SyntaxKind.SuperKeyword) { + const symbol = context.checker.getSymbolAtLocation(node); + if (symbol && symbol.flags & ts.SymbolFlags.GetAccessor) { + return { + expression: transformLuaLibFunction( + context, + LuaLibFeature.DescriptorGet, + node, + lua.createIdentifier("self"), + table, + lua.createStringLiteral(property) + ), + }; + } + } + return { expression: lua.createTableIndexExpression(table, lua.createStringLiteral(property), node) }; } export const transformQualifiedName: FunctionVisitor = (node, context) => { diff --git a/src/transformation/visitors/async-await.ts b/src/transformation/visitors/async-await.ts new file mode 100644 index 000000000..8063312c0 --- /dev/null +++ b/src/transformation/visitors/async-await.ts @@ -0,0 +1,34 @@ +import * as ts from "typescript"; +import * as lua from "../../LuaAST"; +import { FunctionVisitor, TransformationContext } from "../context"; +import { awaitMustBeInAsyncFunction } from "../utils/diagnostics"; +import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; +import { isInAsyncFunction } from "../utils/typescript"; + +export const transformAwaitExpression: FunctionVisitor = (node, context) => { + // Check if await is inside an async function, it is not allowed at top level or in non-async functions + if (!isInAsyncFunction(node)) { + context.diagnostics.push(awaitMustBeInAsyncFunction(node)); + } + + const expression = context.transformExpression(node.expression); + return transformLuaLibFunction(context, LuaLibFeature.Await, node, expression); +}; + +export function isAsyncFunction(declaration: ts.FunctionLikeDeclaration): boolean { + return declaration.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false; +} + +export function wrapInAsyncAwaiter( + context: TransformationContext, + statements: lua.Statement[], + includeResolveParameter = true +): lua.CallExpression { + importLuaLibFeature(context, LuaLibFeature.Await); + + const parameters = includeResolveParameter ? [lua.createIdentifier("____awaiter_resolve")] : []; + + return lua.createCallExpression(lua.createIdentifier("__TS__AsyncAwaiter"), [ + lua.createFunctionExpression(lua.createBlock(statements), parameters), + ]); +} diff --git a/src/transformation/visitors/binary-expression/assignments.ts b/src/transformation/visitors/binary-expression/assignments.ts index c8a1cd907..73e6d9dd1 100644 --- a/src/transformation/visitors/binary-expression/assignments.ts +++ b/src/transformation/visitors/binary-expression/assignments.ts @@ -1,32 +1,52 @@ import * as ts from "typescript"; +import { SyntaxKind } from "typescript"; import * as lua from "../../../LuaAST"; -import { cast } from "../../../utils"; import { TransformationContext } from "../../context"; -import { isTupleReturnCall } from "../../utils/annotations"; import { validateAssignment } from "../../utils/assignment-validation"; import { createExportedIdentifier, getDependenciesOfSymbol, isSymbolExported } from "../../utils/export"; -import { createUnpackCall, wrapInTable } from "../../utils/lua-ast"; +import { createBoundedUnpackCall, wrapInTable } from "../../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { isArrayType, isDestructuringAssignment } from "../../utils/typescript"; -import { transformElementAccessArgument } from "../access"; import { isArrayLength, transformDestructuringAssignment } from "./destructuring-assignments"; import { isMultiReturnCall } from "../language-extensions/multi"; -import { popScope, pushScope, ScopeType } from "../../utils/scope"; -import { - ImmediatelyInvokedFunctionParameters, - transformToImmediatelyInvokedFunctionExpression, -} from "../../utils/transform"; +import { cannotAssignToNodeOfKind, notAllowedOptionalAssignment } from "../../utils/diagnostics"; +import { transformElementAccessArgument } from "../access"; +import { moveToPrecedingTemp, transformExpressionList } from "../expression-list"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; export function transformAssignmentLeftHandSideExpression( context: TransformationContext, - node: ts.Expression + node: ts.Expression, + rightHasPrecedingStatements?: boolean ): lua.AssignmentLeftHandSideExpression { + // Access expressions need the components of the left side cached in temps before the right side's preceding statements + if (rightHasPrecedingStatements && (ts.isElementAccessExpression(node) || ts.isPropertyAccessExpression(node))) { + let table = context.transformExpression(node.expression); + table = moveToPrecedingTemp(context, table, node.expression); + + let index: lua.Expression; + if (ts.isElementAccessExpression(node)) { + index = transformElementAccessArgument(context, node); + index = moveToPrecedingTemp(context, index, node.argumentExpression); + } else { + index = lua.createStringLiteral(node.name.text, node.name); + } + return lua.createTableIndexExpression(table, index, node); + } + const symbol = context.checker.getSymbolAtLocation(node); const left = context.transformExpression(node); - return lua.isIdentifier(left) && symbol && isSymbolExported(context, symbol) - ? createExportedIdentifier(context, left) - : cast(left, lua.isAssignmentLeftHandSideExpression); + if (lua.isIdentifier(left) && symbol && isSymbolExported(context, symbol)) { + return createExportedIdentifier(context, left); + } + + if (lua.isAssignmentLeftHandSideExpression(left)) { + return left; + } else { + context.diagnostics.push(cannotAssignToNodeOfKind(node, left.kind)); + return lua.createAnonymousIdentifier(); + } } export function transformAssignment( @@ -34,8 +54,14 @@ export function transformAssignment( // TODO: Change type to ts.LeftHandSideExpression? lhs: ts.Expression, right: lua.Expression, + rightHasPrecedingStatements?: boolean, parent?: ts.Expression ): lua.Statement[] { + if (ts.isOptionalChain(lhs)) { + context.diagnostics.push(notAllowedOptionalAssignment(lhs)); + return []; + } + if (isArrayLength(context, lhs)) { const arrayLengthAssignment = lua.createExpressionStatement( transformLuaLibFunction( @@ -50,13 +76,37 @@ export function transformAssignment( return [arrayLengthAssignment]; } - const symbol = ts.isShorthandPropertyAssignment(lhs.parent) - ? context.checker.getShorthandAssignmentValueSymbol(lhs.parent) - : context.checker.getSymbolAtLocation(lhs); + if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) { + if (lhs.expression.kind === SyntaxKind.SuperKeyword) { + const symbol = context.checker.getSymbolAtLocation(lhs); + if (symbol && symbol.flags & ts.SymbolFlags.SetAccessor) { + return [ + lua.createExpressionStatement( + transformLuaLibFunction( + context, + LuaLibFeature.DescriptorSet, + parent, + lua.createIdentifier("self"), + context.transformExpression(lhs.expression), + ts.isPropertyAccessExpression(lhs) + ? lua.createStringLiteral(lhs.name.text) + : context.transformExpression(lhs.argumentExpression), + right + ) + ), + ]; + } + } + } + + const symbol = + lhs.parent && ts.isShorthandPropertyAssignment(lhs.parent) + ? context.checker.getShorthandAssignmentValueSymbol(lhs.parent) + : context.checker.getSymbolAtLocation(lhs); const dependentSymbols = symbol ? getDependenciesOfSymbol(context, symbol) : []; - const left = transformAssignmentLeftHandSideExpression(context, lhs); + const left = transformAssignmentLeftHandSideExpression(context, lhs, rightHasPrecedingStatements); const rootAssignment = lua.createAssignmentStatement(left, right, lhs.parent); @@ -70,23 +120,41 @@ export function transformAssignment( ]; } +export function transformAssignmentWithRightPrecedingStatements( + context: TransformationContext, + lhs: ts.Expression, + right: lua.Expression, + rightPrecedingStatements: lua.Statement[], + parent?: ts.Expression +): lua.Statement[] { + return [ + ...rightPrecedingStatements, + ...transformAssignment(context, lhs, right, rightPrecedingStatements.length > 0, parent), + ]; +} + function transformDestructuredAssignmentExpression( context: TransformationContext, expression: ts.DestructuringAssignment -): ImmediatelyInvokedFunctionParameters { - const rootIdentifier = lua.createAnonymousIdentifier(expression.left); - - let right = context.transformExpression(expression.right); - if (isTupleReturnCall(context, expression.right) || isMultiReturnCall(context, expression.right)) { +) { + let { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(expression.right) + ); + context.addPrecedingStatements(rightPrecedingStatements); + if (isMultiReturnCall(context, expression.right)) { right = wrapInTable(right); } - const statements = [ - lua.createVariableDeclarationStatement(rootIdentifier, right), - ...transformDestructuringAssignment(context, expression, rootIdentifier), - ]; + const rightExpr = moveToPrecedingTemp(context, right, expression.right); + const statements = transformDestructuringAssignment( + context, + expression, + rightExpr, + rightPrecedingStatements.length > 0 + ); - return { statements, result: rootIdentifier }; + return { statements, result: rightExpr }; } export function transformAssignmentExpression( @@ -110,56 +178,33 @@ export function transformAssignmentExpression( } if (isDestructuringAssignment(expression)) { - return transformToImmediatelyInvokedFunctionExpression( - context, - () => transformDestructuredAssignmentExpression(context, expression), - expression - ); + const { statements, result } = transformDestructuredAssignmentExpression(context, expression); + context.addPrecedingStatements(statements); + return result; } if (ts.isPropertyAccessExpression(expression.left) || ts.isElementAccessExpression(expression.left)) { - // Left is property/element access: cache result while maintaining order of evaluation - // (function(o, i, v) o[i] = v; return v end)(${objExpression}, ${indexExpression}, ${right}) - const objParameter = lua.createIdentifier("o"); - const indexParameter = lua.createIdentifier("i"); - const valueParameter = lua.createIdentifier("v"); - const indexStatement = lua.createTableIndexExpression(objParameter, indexParameter); - const statements: lua.Statement[] = [ - lua.createAssignmentStatement(indexStatement, valueParameter), - lua.createReturnStatement([valueParameter]), - ]; - const iife = lua.createFunctionExpression(lua.createBlock(statements), [ - objParameter, - indexParameter, - valueParameter, - ]); - pushScope(context, ScopeType.Function); - const objExpression = context.transformExpression(expression.left.expression); - let indexExpression: lua.Expression; - if (ts.isPropertyAccessExpression(expression.left)) { - // Property access - indexExpression = lua.createStringLiteral(expression.left.name.text); - } else { - // Element access - indexExpression = transformElementAccessArgument(context, expression.left); - } + const { precedingStatements, result: right } = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression.right) + ); - const args = [objExpression, indexExpression, context.transformExpression(expression.right)]; - popScope(context); - return lua.createCallExpression(iife, args, expression); - } else { - return transformToImmediatelyInvokedFunctionExpression( + const left = transformAssignmentLeftHandSideExpression( context, - () => { - // Simple assignment - // (function() ${left} = ${right}; return ${left} end)() - const left = context.transformExpression(expression.left); - const right = context.transformExpression(expression.right); - const statements = transformAssignment(context, expression.left, right); - return { statements, result: left }; - }, - expression + expression.left, + precedingStatements.length > 0 ); + + context.addPrecedingStatements(precedingStatements); + const rightExpr = moveToPrecedingTemp(context, right, expression.right); + context.addPrecedingStatements(lua.createAssignmentStatement(left, rightExpr, expression.left)); + return rightExpr; + } else { + // Simple assignment + // ${left} = ${right}; return ${left} + const left = context.transformExpression(expression.left); + const right = context.transformExpression(expression.right); + context.addPrecedingStatements(transformAssignment(context, expression.left, right)); + return left; } } @@ -174,7 +219,9 @@ const canBeTransformedToLuaAssignmentStatement = ( } if (ts.isPropertyAccessExpression(element) || ts.isElementAccessExpression(element)) { - return true; + // Lua's execution order for multi-assignments is not the same as JS's, so we should always + // break these down when the left side may have side effects. + return false; } if (ts.isIdentifier(element)) { @@ -198,13 +245,15 @@ export function transformAssignmentStatement( if (isDestructuringAssignment(expression)) { if (canBeTransformedToLuaAssignmentStatement(context, expression)) { const rightType = context.checker.getTypeAtLocation(expression.right); - let right = context.transformExpression(expression.right); + let right: lua.Expression | lua.Expression[]; - if ( - !(isTupleReturnCall(context, expression.right) || isMultiReturnCall(context, expression.right)) && - isArrayType(context, rightType) - ) { - right = createUnpackCall(context, right, expression.right); + if (ts.isArrayLiteralExpression(expression.right)) { + right = transformExpressionList(context, expression.right.elements); + } else { + right = context.transformExpression(expression.right); + if (!isMultiReturnCall(context, expression.right) && isArrayType(context, rightType)) { + right = createBoundedUnpackCall(context, right, expression.left.elements.length, expression.right); + } } const left = expression.left.elements.map(e => transformAssignmentLeftHandSideExpression(context, e)); @@ -212,17 +261,12 @@ export function transformAssignmentStatement( return [lua.createAssignmentStatement(left, right, expression)]; } - let right = context.transformExpression(expression.right); - if (isTupleReturnCall(context, expression.right) || isMultiReturnCall(context, expression.right)) { - right = wrapInTable(right); - } - - const rootIdentifier = lua.createAnonymousIdentifier(expression.left); - return [ - lua.createVariableDeclarationStatement(rootIdentifier, right), - ...transformDestructuringAssignment(context, expression, rootIdentifier), - ]; + const { statements } = transformDestructuredAssignmentExpression(context, expression); + return statements; } else { - return transformAssignment(context, expression.left, context.transformExpression(expression.right)); + const { precedingStatements, result: right } = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression.right) + ); + return transformAssignmentWithRightPrecedingStatements(context, expression.left, right, precedingStatements); } } diff --git a/src/transformation/visitors/binary-expression/bit.ts b/src/transformation/visitors/binary-expression/bit.ts index e284b2ea0..5ae876630 100644 --- a/src/transformation/visitors/binary-expression/bit.ts +++ b/src/transformation/visitors/binary-expression/bit.ts @@ -49,6 +49,7 @@ function transformBitOperatorToLuaOperator( return lua.SyntaxKind.BitwiseLeftShiftOperator; case ts.SyntaxKind.GreaterThanGreaterThanToken: context.diagnostics.push(unsupportedRightShiftOperator(node)); + return lua.SyntaxKind.BitwiseRightShiftOperator; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return lua.SyntaxKind.BitwiseRightShiftOperator; } @@ -63,8 +64,10 @@ export function transformBinaryBitOperation( ): lua.Expression { switch (context.luaTarget) { case LuaTarget.Universal: + case LuaTarget.Lua50: case LuaTarget.Lua51: - context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", LuaTarget.Lua51)); + context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", context.luaTarget)); + return transformBinaryBitLibOperation(node, left, right, operator, "bit"); case LuaTarget.LuaJIT: return transformBinaryBitLibOperation(node, left, right, operator, "bit"); @@ -72,6 +75,22 @@ export function transformBinaryBitOperation( case LuaTarget.Lua52: return transformBinaryBitLibOperation(node, left, right, operator, "bit32"); default: + // Lua 5.3+ `>>` is arithmetic (sign-extending), but TS `>>>` is logical (zero-fill). + // Emit `(left & 0xFFFFFFFF) >> right` to convert to unsigned 32-bit first. + if (operator === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) { + const mask = lua.createBinaryExpression( + left, + lua.createNumericLiteral(0xffffffff, node), + lua.SyntaxKind.BitwiseAndOperator, + node + ); + return lua.createBinaryExpression( + lua.createParenthesizedExpression(mask, node), + right, + lua.SyntaxKind.BitwiseRightShiftOperator, + node + ); + } const luaOperator = transformBitOperatorToLuaOperator(context, node, operator); return lua.createBinaryExpression(left, right, luaOperator, node); } @@ -107,8 +126,10 @@ export function transformUnaryBitOperation( ): lua.Expression { switch (context.luaTarget) { case LuaTarget.Universal: + case LuaTarget.Lua50: case LuaTarget.Lua51: - context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", LuaTarget.Lua51)); + context.diagnostics.push(unsupportedForTarget(node, "Bitwise operations", context.luaTarget)); + return transformUnaryBitLibOperation(node, expression, operator, "bit"); case LuaTarget.LuaJIT: return transformUnaryBitLibOperation(node, expression, operator, "bit"); diff --git a/src/transformation/visitors/binary-expression/compound.ts b/src/transformation/visitors/binary-expression/compound.ts index febd7681e..4532fe56c 100644 --- a/src/transformation/visitors/binary-expression/compound.ts +++ b/src/transformation/visitors/binary-expression/compound.ts @@ -1,39 +1,27 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; -import { cast, assertNever } from "../../../utils"; +import { assertNever } from "../../../utils"; import { TransformationContext } from "../../context"; -import { - ImmediatelyInvokedFunctionParameters, - transformToImmediatelyInvokedFunctionExpression, -} from "../../utils/transform"; -import { isArrayType, isExpressionWithEvaluationEffect } from "../../utils/typescript"; -import { transformBinaryOperation } from "../binary-expression"; -import { transformAssignment } from "./assignments"; - -// If expression is property/element access with possible effects from being evaluated, returns separated object and index expressions. -export function parseAccessExpressionWithEvaluationEffects( - context: TransformationContext, - node: ts.Expression -): [ts.Expression, ts.Expression] | [] { - if ( - ts.isElementAccessExpression(node) && - (isExpressionWithEvaluationEffect(node.expression) || isExpressionWithEvaluationEffect(node.argumentExpression)) - ) { - const type = context.checker.getTypeAtLocation(node.expression); - if (isArrayType(context, type)) { - // Offset arrays by one - const oneLit = ts.factory.createNumericLiteral("1"); - const exp = ts.factory.createParenthesizedExpression(node.argumentExpression); - const addExp = ts.factory.createBinaryExpression(exp, ts.SyntaxKind.PlusToken, oneLit); - return [node.expression, addExp]; - } else { - return [node.expression, node.argumentExpression]; - } - } else if (ts.isPropertyAccessExpression(node) && isExpressionWithEvaluationEffect(node.expression)) { - return [node.expression, ts.factory.createStringLiteral(node.name.text)]; - } +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../../utils/preceding-statements"; +import { transformBinaryOperation } from "./index"; +import { transformAssignmentWithRightPrecedingStatements } from "./assignments"; +import { isArrayLength } from "./destructuring-assignments"; +import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; +import { cannotAssignToNodeOfKind } from "../../utils/diagnostics"; - return []; +function isLuaExpressionWithSideEffect(expression: lua.Expression) { + return !(lua.isLiteral(expression) || lua.isIdentifier(expression)); +} + +function shouldCacheTableIndexExpressions( + expression: lua.TableIndexExpression, + rightPrecedingStatements: lua.Statement[] +) { + return ( + isLuaExpressionWithSideEffect(expression.table) || + isLuaExpressionWithSideEffect(expression.index) || + rightPrecedingStatements.length > 0 + ); } // TODO: `as const` doesn't work on enum members @@ -78,82 +66,153 @@ export const isCompoundAssignmentToken = (token: ts.BinaryOperator): token is ts export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator): CompoundAssignmentToken => compoundToAssignmentTokens[token]; -export function transformCompoundAssignment( +function transformCompoundAssignment( context: TransformationContext, expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean -): ImmediatelyInvokedFunctionParameters { - const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); - const right = context.transformExpression(rhs); +): WithPrecedingStatements { + if (isArrayLength(context, lhs)) { + const { precedingStatements, result: lengthSetterStatement } = transformCompoundLengthSetter( + context, + expression, + lhs, + rhs, + operator + ); + + return { precedingStatements, result: lengthSetterStatement.expression }; + } + + const left = context.transformExpression(lhs); + if (!lua.isAssignmentLeftHandSideExpression(left)) { + context.diagnostics.push(cannotAssignToNodeOfKind(expression, left.kind)); + return { precedingStatements: [], result: left }; + } + + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) + ); - const [objExpression, indexExpression] = parseAccessExpressionWithEvaluationEffects(context, lhs); - if (objExpression && indexExpression) { + if (lua.isTableIndexExpression(left)) { // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects // local __obj, __index = ${objExpression}, ${indexExpression}; - const obj = lua.createIdentifier("____obj"); - const index = lua.createIdentifier("____index"); - const objAndIndexDeclaration = lua.createVariableDeclarationStatement( - [obj, index], - [context.transformExpression(objExpression), context.transformExpression(indexExpression)] - ); + const obj = context.createTempNameForLuaExpression(left.table); + const index = context.createTempNameForLuaExpression(left.index); + + const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [left.table, left.index]); const accessExpression = lua.createTableIndexExpression(obj, index); - const tmp = lua.createIdentifier("____tmp"); - let tmpDeclaration: lua.VariableDeclarationStatement; - let assignStatement: lua.AssignmentStatement; + const tmp = context.createTempNameForLuaExpression(left); if (isPostfix) { // local ____tmp = ____obj[____index]; // ____obj[____index] = ____tmp ${replacementOperator} ${right}; - tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression); - const operatorExpression = transformBinaryOperation(context, tmp, right, operator, expression); - assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); + // return ____tmp + const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression); + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( + context, + tmp, + right, + rightPrecedingStatements, + operator, + expression + ); + const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); + return { + precedingStatements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement], + result: tmp, + }; } else { + if (isSetterSkippingCompoundAssignmentOperator(operator)) { + return { + precedingStatements: [ + objAndIndexDeclaration, + ...transformSetterSkippingCompoundAssignment( + accessExpression, + operator, + right, + rightPrecedingStatements + ), + ], + result: left, + }; + } // local ____tmp = ____obj[____index] ${replacementOperator} ${right}; // ____obj[____index] = ____tmp; - const operatorExpression = transformBinaryOperation(context, accessExpression, right, operator, expression); - tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression); - assignStatement = lua.createAssignmentStatement(accessExpression, tmp); + // return ____tmp + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( + context, + accessExpression, + right, + rightPrecedingStatements, + operator, + expression + ); + const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression); + const assignStatement = lua.createAssignmentStatement(accessExpression, tmp); + return { + precedingStatements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement], + result: tmp, + }; } - // return ____tmp - return { statements: [objAndIndexDeclaration, tmpDeclaration, assignStatement], result: tmp }; } else if (isPostfix) { // Postfix expressions need to cache original value in temp // local ____tmp = ${left}; // ${left} = ____tmp ${replacementOperator} ${right}; // return ____tmp - const tmpIdentifier = lua.createIdentifier("____tmp"); + const tmpIdentifier = context.createTempNameForLuaExpression(left); const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, left); - const operatorExpression = transformBinaryOperation(context, tmpIdentifier, right, operator, expression); - const assignStatements = transformAssignment(context, lhs, operatorExpression); - return { statements: [tmpDeclaration, ...assignStatements], result: tmpIdentifier }; - } else if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) { - // Simple property/element access expressions need to cache in temp to avoid double-evaluation - // local ____tmp = ${left} ${replacementOperator} ${right}; - // ${left} = ____tmp; - // return ____tmp - const tmpIdentifier = lua.createIdentifier("____tmp"); - const operatorExpression = transformBinaryOperation(context, left, right, operator, expression); - const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, operatorExpression); - const assignStatements = transformAssignment(context, lhs, tmpIdentifier); - - if (isSetterSkippingCompoundAssignmentOperator(operator)) { - const statements = [ - tmpDeclaration, - ...transformSetterSkippingCompoundAssignment(context, tmpIdentifier, operator, rhs), - ]; - return { statements, result: tmpIdentifier }; + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( + context, + tmpIdentifier, + right, + rightPrecedingStatements, + operator, + expression + ); + const assignStatements = transformAssignmentWithRightPrecedingStatements( + context, + lhs, + operatorExpression, + rightPrecedingStatements + ); + return { + precedingStatements: [tmpDeclaration, ...precedingStatements, ...assignStatements], + result: tmpIdentifier, + }; + } else { + if (rightPrecedingStatements.length > 0 && isSetterSkippingCompoundAssignmentOperator(operator)) { + return { + precedingStatements: transformSetterSkippingCompoundAssignment( + left, + operator, + right, + rightPrecedingStatements + ), + result: left, + }; } - return { statements: [tmpDeclaration, ...assignStatements], result: tmpIdentifier }; - } else { // Simple expressions - // ${left} = ${right}; return ${right} - const operatorExpression = transformBinaryOperation(context, left, right, operator, expression); - const statements = transformAssignment(context, lhs, operatorExpression); - return { statements, result: left }; + // ${left} = ${left} ${operator} ${right} + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( + context, + left, + right, + rightPrecedingStatements, + operator, + expression + ); + const statements = transformAssignmentWithRightPrecedingStatements( + context, + lhs, + operatorExpression, + precedingStatements + ); + return { precedingStatements: statements, result: left }; } } @@ -165,12 +224,17 @@ export function transformCompoundAssignmentExpression( rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean -): lua.CallExpression { - return transformToImmediatelyInvokedFunctionExpression( +): lua.Expression { + const { precedingStatements, result } = transformCompoundAssignment( context, - () => transformCompoundAssignment(context, expression, lhs, rhs, operator, isPostfix), - expression + expression, + lhs, + rhs, + operator, + isPostfix ); + context.addPrecedingStatements(precedingStatements); + return result; } export function transformCompoundAssignmentStatement( @@ -180,42 +244,83 @@ export function transformCompoundAssignmentStatement( rhs: ts.Expression, operator: CompoundAssignmentToken ): lua.Statement[] { - const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); - const right = context.transformExpression(rhs); + if (isArrayLength(context, lhs)) { + const { precedingStatements, result: lengthSetterStatement } = transformCompoundLengthSetter( + context, + node, + lhs, + rhs, + operator + ); - const [objExpression, indexExpression] = parseAccessExpressionWithEvaluationEffects(context, lhs); - if (objExpression && indexExpression) { + return [...precedingStatements, lengthSetterStatement]; + } + + const left = context.transformExpression(lhs); + if (!lua.isAssignmentLeftHandSideExpression(left)) { + context.diagnostics.push(cannotAssignToNodeOfKind(node, left.kind)); + return []; + } + + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) + ); + + if (lua.isTableIndexExpression(left) && shouldCacheTableIndexExpressions(left, rightPrecedingStatements)) { // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects // local __obj, __index = ${objExpression}, ${indexExpression}; // ____obj[____index] = ____obj[____index] ${replacementOperator} ${right}; - const obj = lua.createIdentifier("____obj"); - const index = lua.createIdentifier("____index"); - const objAndIndexDeclaration = lua.createVariableDeclarationStatement( - [obj, index], - [context.transformExpression(objExpression), context.transformExpression(indexExpression)] - ); + const obj = context.createTempNameForLuaExpression(left.table); + const index = context.createTempNameForLuaExpression(left.index); + + const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [left.table, left.index]); const accessExpression = lua.createTableIndexExpression(obj, index); if (isSetterSkippingCompoundAssignmentOperator(operator)) { return [ objAndIndexDeclaration, - ...transformSetterSkippingCompoundAssignment(context, accessExpression, operator, rhs, node), + ...transformSetterSkippingCompoundAssignment( + accessExpression, + operator, + right, + rightPrecedingStatements, + node + ), ]; } - const operatorExpression = transformBinaryOperation(context, accessExpression, right, operator, node); + const { precedingStatements: rightPrecedingStatements2, result: operatorExpression } = transformBinaryOperation( + context, + accessExpression, + right, + rightPrecedingStatements, + operator, + node + ); const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); - return [objAndIndexDeclaration, assignStatement]; + return [objAndIndexDeclaration, ...rightPrecedingStatements2, assignStatement]; } else { if (isSetterSkippingCompoundAssignmentOperator(operator)) { - const luaLhs = context.transformExpression(lhs) as lua.AssignmentLeftHandSideExpression; - return transformSetterSkippingCompoundAssignment(context, luaLhs, operator, rhs, node); + return transformSetterSkippingCompoundAssignment(left, operator, right, rightPrecedingStatements, node); } // Simple statements // ${left} = ${left} ${replacementOperator} ${right} - const operatorExpression = transformBinaryOperation(context, left, right, operator, node); - return transformAssignment(context, lhs, operatorExpression); + const { precedingStatements: rightPrecedingStatements2, result: operatorExpression } = transformBinaryOperation( + context, + left, + right, + rightPrecedingStatements, + operator, + node + ); + return transformAssignmentWithRightPrecedingStatements( + context, + lhs, + operatorExpression, + rightPrecedingStatements2 + ); } } @@ -237,10 +342,10 @@ function isSetterSkippingCompoundAssignmentOperator( } function transformSetterSkippingCompoundAssignment( - context: TransformationContext, lhs: lua.AssignmentLeftHandSideExpression, operator: SetterSkippingCompoundAssignmentOperator, - rhs: ts.Expression, + right: lua.Expression, + rightPrecedingStatements: lua.Statement[], node?: ts.Node ): lua.Statement[] { // These assignments have the form 'if x then y = z', figure out what condition x is first. @@ -260,9 +365,38 @@ function transformSetterSkippingCompoundAssignment( return [ lua.createIfStatement( condition, - lua.createBlock([lua.createAssignmentStatement(lhs, context.transformExpression(rhs))]), + lua.createBlock([...rightPrecedingStatements, lua.createAssignmentStatement(lhs, right, node)]), undefined, node ), ]; } + +function transformCompoundLengthSetter( + context: TransformationContext, + node: ts.Node, + lhs: ts.PropertyAccessExpression | ts.ElementAccessExpression, + rhs: ts.Expression, + operator: CompoundAssignmentToken +): WithPrecedingStatements { + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) + ); + const table = context.transformExpression(lhs.expression); + const lengthExpression = lua.createUnaryExpression(table, lua.SyntaxKind.LengthOperator, lhs); + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( + context, + lengthExpression, + right, + rightPrecedingStatements, + operator, + node + ); + + const arrayLengthAssignment = lua.createExpressionStatement( + transformLuaLibFunction(context, LuaLibFeature.ArraySetLength, node, table, operatorExpression) + ); + + return { precedingStatements, result: arrayLengthAssignment }; +} diff --git a/src/transformation/visitors/binary-expression/destructuring-assignments.ts b/src/transformation/visitors/binary-expression/destructuring-assignments.ts index 567de4e6f..aa7042727 100644 --- a/src/transformation/visitors/binary-expression/destructuring-assignments.ts +++ b/src/transformation/visitors/binary-expression/destructuring-assignments.ts @@ -1,9 +1,12 @@ import * as ts from "typescript"; +import { transformBinaryOperation } from "."; import * as lua from "../../../LuaAST"; -import { assertNever } from "../../../utils"; +import { assertNever, cast } from "../../../utils"; import { TransformationContext } from "../../context"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; import { isArrayType, isAssignmentPattern } from "../../utils/typescript"; +import { moveToPrecedingTemp } from "../expression-list"; import { transformPropertyName } from "../literal"; import { transformAssignment, @@ -36,28 +39,31 @@ export function isArrayLength( export function transformDestructuringAssignment( context: TransformationContext, node: ts.DestructuringAssignment, - root: lua.Expression + root: lua.Expression, + rightHasPrecedingStatements: boolean ): lua.Statement[] { - return transformAssignmentPattern(context, node.left, root); + return transformAssignmentPattern(context, node.left, root, rightHasPrecedingStatements); } export function transformAssignmentPattern( context: TransformationContext, node: ts.AssignmentPattern, - root: lua.Expression + root: lua.Expression, + rightHasPrecedingStatements: boolean ): lua.Statement[] { switch (node.kind) { case ts.SyntaxKind.ObjectLiteralExpression: - return transformObjectLiteralAssignmentPattern(context, node, root); + return transformObjectLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements); case ts.SyntaxKind.ArrayLiteralExpression: - return transformArrayLiteralAssignmentPattern(context, node, root); + return transformArrayLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements); } } function transformArrayLiteralAssignmentPattern( context: TransformationContext, node: ts.ArrayLiteralExpression, - root: lua.Expression + root: lua.Expression, + rightHasPrecedingStatements: boolean ): lua.Statement[] { return node.elements.flatMap((element, index) => { const indexedRoot = lua.createTableIndexExpression(root, lua.createNumericLiteral(index + 1), element); @@ -67,16 +73,18 @@ function transformArrayLiteralAssignmentPattern( return transformObjectLiteralAssignmentPattern( context, element as ts.ObjectLiteralExpression, - indexedRoot + indexedRoot, + rightHasPrecedingStatements ); case ts.SyntaxKind.ArrayLiteralExpression: return transformArrayLiteralAssignmentPattern( context, element as ts.ArrayLiteralExpression, - indexedRoot + indexedRoot, + rightHasPrecedingStatements ); case ts.SyntaxKind.BinaryExpression: - const assignedVariable = lua.createIdentifier("____bindingAssignmentValue"); + const assignedVariable = context.createTempNameForLuaExpression(indexedRoot); const assignedVariableDeclaration = lua.createVariableDeclarationStatement( assignedVariable, @@ -89,11 +97,17 @@ function transformArrayLiteralAssignmentPattern( lua.SyntaxKind.EqualityOperator ); - const defaultAssignmentStatements = transformAssignment( - context, - (element as ts.BinaryExpression).left, - context.transformExpression((element as ts.BinaryExpression).right) - ); + const { precedingStatements: defaultPrecedingStatements, result: defaultAssignmentStatements } = + transformInPrecedingStatementScope(context, () => + transformAssignment( + context, + (element as ts.BinaryExpression).left, + context.transformExpression((element as ts.BinaryExpression).right) + ) + ); + + // Keep preceding statements inside if block + defaultAssignmentStatements.unshift(...defaultPrecedingStatements); const elseAssignmentStatements = transformAssignment( context, @@ -111,7 +125,10 @@ function transformArrayLiteralAssignmentPattern( case ts.SyntaxKind.Identifier: case ts.SyntaxKind.PropertyAccessExpression: case ts.SyntaxKind.ElementAccessExpression: - return transformAssignment(context, element, indexedRoot); + const { precedingStatements, result: statements } = transformInPrecedingStatementScope(context, () => + transformAssignment(context, element, indexedRoot, rightHasPrecedingStatements) + ); + return [...precedingStatements, ...statements]; // Keep preceding statements in order case ts.SyntaxKind.SpreadElement: if (index !== node.elements.length - 1) { // TypeScript error @@ -126,7 +143,16 @@ function transformArrayLiteralAssignmentPattern( lua.createNumericLiteral(index) ); - return transformAssignment(context, (element as ts.SpreadElement).expression, restElements); + const { precedingStatements: spreadPrecedingStatements, result: spreadStatements } = + transformInPrecedingStatementScope(context, () => + transformAssignment( + context, + (element as ts.SpreadElement).expression, + restElements, + rightHasPrecedingStatements + ) + ); + return [...spreadPrecedingStatements, ...spreadStatements]; // Keep preceding statements in order case ts.SyntaxKind.OmittedExpression: return []; default: @@ -139,7 +165,8 @@ function transformArrayLiteralAssignmentPattern( function transformObjectLiteralAssignmentPattern( context: TransformationContext, node: ts.ObjectLiteralExpression, - root: lua.Expression + root: lua.Expression, + rightHasPrecedingStatements: boolean ): lua.Statement[] { const result: lua.Statement[] = []; @@ -149,7 +176,7 @@ function transformObjectLiteralAssignmentPattern( result.push(...transformShorthandPropertyAssignment(context, property, root)); break; case ts.SyntaxKind.PropertyAssignment: - result.push(...transformPropertyAssignment(context, property, root)); + result.push(...transformPropertyAssignment(context, property, root, rightHasPrecedingStatements)); break; case ts.SyntaxKind.SpreadAssignment: result.push(...transformSpreadAssignment(context, property, root, node.properties)); @@ -207,7 +234,8 @@ function transformShorthandPropertyAssignment( function transformPropertyAssignment( context: TransformationContext, node: ts.PropertyAssignment, - root: lua.Expression + root: lua.Expression, + rightHasPrecedingStatements: boolean ): lua.Statement[] { const result: lua.Statement[] = []; @@ -216,38 +244,94 @@ function transformPropertyAssignment( const newRootAccess = lua.createTableIndexExpression(root, propertyAccessString); if (ts.isObjectLiteralExpression(node.initializer)) { - return transformObjectLiteralAssignmentPattern(context, node.initializer, newRootAccess); + return transformObjectLiteralAssignmentPattern( + context, + node.initializer, + newRootAccess, + rightHasPrecedingStatements + ); } if (ts.isArrayLiteralExpression(node.initializer)) { - return transformArrayLiteralAssignmentPattern(context, node.initializer, newRootAccess); + return transformArrayLiteralAssignmentPattern( + context, + node.initializer, + newRootAccess, + rightHasPrecedingStatements + ); } } - const leftExpression = ts.isBinaryExpression(node.initializer) ? node.initializer.left : node.initializer; - const variableToExtract = transformPropertyName(context, node.name); - const extractingExpression = lua.createTableIndexExpression(root, variableToExtract); - - const destructureAssignmentStatements = transformAssignment(context, leftExpression, extractingExpression); + context.pushPrecedingStatements(); - result.push(...destructureAssignmentStatements); + let variableToExtract = transformPropertyName(context, node.name); + // Must be evaluated before left's preceding statements + variableToExtract = moveToPrecedingTemp(context, variableToExtract, node.name); + const extractingExpression = lua.createTableIndexExpression(root, variableToExtract); + let destructureAssignmentStatements: lua.Statement[]; if (ts.isBinaryExpression(node.initializer)) { - const assignmentLeftHandSide = context.transformExpression(node.initializer.left); - - const nilCondition = lua.createBinaryExpression( - assignmentLeftHandSide, - lua.createNilLiteral(), - lua.SyntaxKind.EqualityOperator - ); - - const ifBlock = lua.createBlock( - transformAssignmentStatement(context, node.initializer as ts.AssignmentExpression) + if ( + ts.isPropertyAccessExpression(node.initializer.left) || + ts.isElementAccessExpression(node.initializer.left) + ) { + // Access expressions need their table and index expressions cached to preserve execution order + const left = cast(context.transformExpression(node.initializer.left), lua.isTableIndexExpression); + + const rightExpression = node.initializer.right; + const { precedingStatements: defaultPrecedingStatements, result: defaultExpression } = + transformInPrecedingStatementScope(context, () => context.transformExpression(rightExpression)); + + const tableTemp = context.createTempNameForLuaExpression(left.table); + const indexTemp = context.createTempNameForLuaExpression(left.index); + + const tempsDeclaration = lua.createVariableDeclarationStatement( + [tableTemp, indexTemp], + [left.table, left.index] + ); + + // obj[index] = extractingExpression ?? defaultExpression + const { precedingStatements: rightPrecedingStatements, result: rhs } = transformBinaryOperation( + context, + extractingExpression, + defaultExpression, + defaultPrecedingStatements, + ts.SyntaxKind.QuestionQuestionToken, + node.initializer + ); + const assignStatement = lua.createAssignmentStatement( + lua.createTableIndexExpression(tableTemp, indexTemp), + rhs + ); + + destructureAssignmentStatements = [tempsDeclaration, ...rightPrecedingStatements, assignStatement]; + } else { + const assignmentLeftHandSide = context.transformExpression(node.initializer.left); + + const nilCondition = lua.createBinaryExpression( + assignmentLeftHandSide, + lua.createNilLiteral(), + lua.SyntaxKind.EqualityOperator + ); + + const ifBlock = lua.createBlock( + transformAssignmentStatement(context, node.initializer as ts.AssignmentExpression) + ); + + destructureAssignmentStatements = [lua.createIfStatement(nilCondition, ifBlock, undefined, node)]; + } + } else { + destructureAssignmentStatements = transformAssignment( + context, + node.initializer, + extractingExpression, + rightHasPrecedingStatements ); - - result.push(lua.createIfStatement(nilCondition, ifBlock, undefined, node)); } + result.push(...context.popPrecedingStatements()); + result.push(...destructureAssignmentStatements); + return result; } diff --git a/src/transformation/visitors/binary-expression/index.ts b/src/transformation/visitors/binary-expression/index.ts index ce73a7a70..f2b0acb16 100644 --- a/src/transformation/visitors/binary-expression/index.ts +++ b/src/transformation/visitors/binary-expression/index.ts @@ -1,9 +1,10 @@ import * as ts from "typescript"; +import { LuaTarget } from "../../../CompilerOptions"; import * as lua from "../../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../../context"; import { wrapInToStringForConcat } from "../../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; -import { isStandardLibraryType, isStringType, typeCanSatisfy } from "../../utils/typescript"; +import { canBeFalsyWhenNotNull, isStandardLibraryType, isStringType } from "../../utils/typescript"; import { transformTypeOfBinaryExpression } from "../typeof"; import { transformAssignmentExpression, transformAssignmentStatement } from "./assignments"; import { BitOperator, isBitOperator, transformBinaryBitOperation } from "./bit"; @@ -14,7 +15,18 @@ import { unwrapCompoundAssignmentToken, } from "./compound"; import { assert } from "../../../utils"; -import { transformToImmediatelyInvokedFunctionExpression } from "../../utils/transform"; +import { transformOrderedExpressions } from "../expression-list"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../../utils/preceding-statements"; + +type ShortCircuitOperator = + | ts.SyntaxKind.AmpersandAmpersandToken + | ts.SyntaxKind.BarBarToken + | ts.SyntaxKind.QuestionQuestionToken; + +const isShortCircuitOperator = (value: unknown): value is ShortCircuitOperator => + value === ts.SyntaxKind.AmpersandAmpersandToken || + value === ts.SyntaxKind.BarBarToken || + value === ts.SyntaxKind.QuestionQuestionToken; type SimpleOperator = | ts.AdditiveOperatorOrHigher @@ -41,7 +53,7 @@ const simpleOperatorsToLua: Record = { [ts.SyntaxKind.ExclamationEqualsEqualsToken]: lua.SyntaxKind.InequalityOperator, }; -export function transformBinaryOperation( +function transformBinaryOperationWithNoPrecedingStatements( context: TransformationContext, left: lua.Expression, right: lua.Expression, @@ -54,7 +66,12 @@ export function transformBinaryOperation( if (operator === ts.SyntaxKind.QuestionQuestionToken) { assert(ts.isBinaryExpression(node)); - return transformNullishCoalescingExpression(context, node, left, right); + return transformNullishCoalescingOperationNoPrecedingStatements(context, node, left, right); + } + + if (operator === ts.SyntaxKind.PercentToken && context.luaTarget === LuaTarget.Lua50) { + const mathMod = lua.createTableIndexExpression(lua.createIdentifier("math"), lua.createStringLiteral("mod")); + return lua.createCallExpression(mathMod, [left, right], node); } let luaOperator = simpleOperatorsToLua[operator]; @@ -63,9 +80,12 @@ export function transformBinaryOperation( if (operator === ts.SyntaxKind.PlusToken && ts.isBinaryExpression(node)) { const typeLeft = context.checker.getTypeAtLocation(node.left); const typeRight = context.checker.getTypeAtLocation(node.right); - if (isStringType(context, typeLeft) || isStringType(context, typeRight)) { - left = wrapInToStringForConcat(left); - right = wrapInToStringForConcat(right); + + const isLeftString = isStringType(context, typeLeft); + const isRightString = isStringType(context, typeRight); + if (isLeftString || isRightString) { + left = isLeftString ? left : wrapInToStringForConcat(left); + right = isRightString ? right : wrapInToStringForConcat(right); luaOperator = lua.SyntaxKind.ConcatOperator; } } @@ -73,6 +93,86 @@ export function transformBinaryOperation( return lua.createBinaryExpression(left, right, luaOperator, node); } +export function createShortCircuitBinaryExpressionPrecedingStatements( + context: TransformationContext, + lhs: lua.Expression, + rhs: lua.Expression, + rightPrecedingStatements: lua.Statement[], + operator: ShortCircuitOperator, + node?: ts.BinaryExpression +): WithPrecedingStatements { + const conditionIdentifier = context.createTempNameForLuaExpression(lhs); + const assignmentStatement = lua.createVariableDeclarationStatement(conditionIdentifier, lhs, node?.left); + + let condition: lua.Expression; + switch (operator) { + case ts.SyntaxKind.BarBarToken: + condition = lua.createUnaryExpression( + lua.cloneIdentifier(conditionIdentifier), + lua.SyntaxKind.NotOperator, + node + ); + break; + case ts.SyntaxKind.AmpersandAmpersandToken: + condition = lua.cloneIdentifier(conditionIdentifier); + break; + case ts.SyntaxKind.QuestionQuestionToken: + condition = lua.createBinaryExpression( + lua.cloneIdentifier(conditionIdentifier), + lua.createNilLiteral(), + lua.SyntaxKind.EqualityOperator, + node + ); + break; + } + + const ifStatement = lua.createIfStatement( + condition, + lua.createBlock([...rightPrecedingStatements, lua.createAssignmentStatement(conditionIdentifier, rhs)]), + undefined, + node?.left + ); + return { precedingStatements: [assignmentStatement, ifStatement], result: conditionIdentifier }; +} + +function transformShortCircuitBinaryExpression( + context: TransformationContext, + node: ts.BinaryExpression, + operator: ShortCircuitOperator +): WithPrecedingStatements { + const lhs = context.transformExpression(node.left); + const { precedingStatements, result } = transformInPrecedingStatementScope(context, () => + context.transformExpression(node.right) + ); + return transformBinaryOperation(context, lhs, result, precedingStatements, operator, node); +} + +export function transformBinaryOperation( + context: TransformationContext, + left: lua.Expression, + right: lua.Expression, + rightPrecedingStatements: lua.Statement[], + operator: BitOperator | SimpleOperator | ts.SyntaxKind.QuestionQuestionToken, + node: ts.Node +): WithPrecedingStatements { + if (rightPrecedingStatements.length > 0 && isShortCircuitOperator(operator)) { + assert(ts.isBinaryExpression(node)); + return createShortCircuitBinaryExpressionPrecedingStatements( + context, + left, + right, + rightPrecedingStatements, + operator, + node + ); + } + + return { + precedingStatements: rightPrecedingStatements, + result: transformBinaryOperationWithNoPrecedingStatements(context, left, right, operator, node), + }; +} + export const transformBinaryExpression: FunctionVisitor = (node, context) => { const operator = node.operatorToken.kind; @@ -115,25 +215,41 @@ export const transformBinaryExpression: FunctionVisitor = ( } case ts.SyntaxKind.CommaToken: { - return transformToImmediatelyInvokedFunctionExpression( - context, - () => ({ - statements: context.transformStatements(ts.factory.createExpressionStatement(node.left)), - result: context.transformExpression(node.right), - }), - node + const statements = context.transformStatements(ts.factory.createExpressionStatement(node.left)); + const { precedingStatements, result } = transformInPrecedingStatementScope(context, () => + context.transformExpression(node.right) ); + statements.push(...precedingStatements); + context.addPrecedingStatements(statements); + return result; } - default: - return transformBinaryOperation( - context, - context.transformExpression(node.left), - context.transformExpression(node.right), - operator, - node - ); + case ts.SyntaxKind.QuestionQuestionToken: + case ts.SyntaxKind.AmpersandAmpersandToken: + case ts.SyntaxKind.BarBarToken: { + const { precedingStatements, result } = transformShortCircuitBinaryExpression(context, node, operator); + context.addPrecedingStatements(precedingStatements); + return result; + } } + + const { + precedingStatements: orderedExpressionPrecedingStatements, + result: [lhs, rhs], + } = transformInPrecedingStatementScope(context, () => + transformOrderedExpressions(context, [node.left, node.right]) + ); + + const { precedingStatements, result } = transformBinaryOperation( + context, + lhs, + rhs, + orderedExpressionPrecedingStatements, + operator, + node + ); + context.addPrecedingStatements(precedingStatements); + return result; }; export function transformBinaryExpressionStatement( @@ -160,7 +276,7 @@ export function transformBinaryExpressionStatement( } } -function transformNullishCoalescingExpression( +function transformNullishCoalescingOperationNoPrecedingStatements( context: TransformationContext, node: ts.BinaryExpression, transformedLeft: lua.Expression, @@ -169,27 +285,18 @@ function transformNullishCoalescingExpression( const lhsType = context.checker.getTypeAtLocation(node.left); // Check if we can take a shortcut to 'lhs or rhs' if the left-hand side cannot be 'false'. - const typeCanBeFalse = (type: ts.Type) => - (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Boolean)) !== 0 || - (type.flags & ts.TypeFlags.BooleanLiteral & ts.TypeFlags.PossiblyFalsy) !== 0; - if (typeCanSatisfy(context, lhsType, typeCanBeFalse)) { - // lhs can be false, transform to IIFE - const lhsIdentifier = lua.createIdentifier("____lhs"); - const nilComparison = lua.createBinaryExpression( - lua.cloneIdentifier(lhsIdentifier), - lua.createNilLiteral(), - lua.SyntaxKind.EqualityOperator - ); - // if ____ == nil then return rhs else return ____ end - const ifStatement = lua.createIfStatement( - nilComparison, - lua.createBlock([lua.createReturnStatement([transformedRight])]), - lua.createBlock([lua.createReturnStatement([lua.cloneIdentifier(lhsIdentifier)])]) - ); - // (function(lhs') if lhs' == nil then return rhs else return lhs' end)(lhs) - return lua.createCallExpression(lua.createFunctionExpression(lua.createBlock([ifStatement]), [lhsIdentifier]), [ + if (canBeFalsyWhenNotNull(context, lhsType)) { + // reuse logic from case with preceding statements + const { precedingStatements, result } = createShortCircuitBinaryExpressionPrecedingStatements( + context, transformedLeft, - ]); + transformedRight, + [], + ts.SyntaxKind.QuestionQuestionToken, + node + ); + context.addPrecedingStatements(precedingStatements); + return result; } else { // lhs or rhs return lua.createBinaryExpression(transformedLeft, transformedRight, lua.SyntaxKind.OrOperator, node); diff --git a/src/transformation/visitors/block.ts b/src/transformation/visitors/block.ts index c26cc1cea..4eef4b6f8 100644 --- a/src/transformation/visitors/block.ts +++ b/src/transformation/visitors/block.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { performHoisting, popScope, pushScope, Scope, ScopeType } from "../utils/scope"; +import { performHoisting, Scope, ScopeType } from "../utils/scope"; export function transformBlockOrStatement(context: TransformationContext, statement: ts.Statement): lua.Statement[] { return context.transformStatements(ts.isBlock(statement) ? statement.statements : statement); @@ -12,15 +12,15 @@ export function transformScopeBlock( node: ts.Block, scopeType: ScopeType ): [lua.Block, Scope] { - pushScope(context, scopeType); + context.pushScope(scopeType, node); const statements = performHoisting(context, context.transformStatements(node.statements)); - const scope = popScope(context); + const scope = context.popScope(); return [lua.createBlock(statements, node), scope]; } export const transformBlock: FunctionVisitor = (node, context) => { - pushScope(context, ScopeType.Block); + context.pushScope(ScopeType.Block, node); const statements = performHoisting(context, context.transformStatements(node.statements)); - popScope(context); + context.popScope(); return lua.createDoStatement(statements, node); }; diff --git a/src/transformation/visitors/break-continue.ts b/src/transformation/visitors/break-continue.ts index 9211d4165..e41a7934b 100644 --- a/src/transformation/visitors/break-continue.ts +++ b/src/transformation/visitors/break-continue.ts @@ -2,28 +2,70 @@ import * as ts from "typescript"; import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; -import { unsupportedForTarget } from "../utils/diagnostics"; -import { findScope, ScopeType } from "../utils/scope"; +import { findAsyncTryScopeBeforeLoop, findScope, LoopContinued, ScopeType } from "../utils/scope"; +import { isInAsyncFunction } from "../utils/typescript"; export const transformBreakStatement: FunctionVisitor = (breakStatement, context) => { - const breakableScope = findScope(context, ScopeType.Loop | ScopeType.Switch); - if (breakableScope?.type === ScopeType.Switch) { - return lua.createGotoStatement(`____switch${breakableScope.id}_end`); - } else { - return lua.createBreakStatement(breakStatement); + const tryScope = isInAsyncFunction(breakStatement) ? findAsyncTryScopeBeforeLoop(context) : undefined; + if (tryScope) { + tryScope.asyncTryHasBreak = true; + return [ + lua.createAssignmentStatement( + lua.createIdentifier("____hasBroken"), + lua.createBooleanLiteral(true), + breakStatement + ), + lua.createReturnStatement([], breakStatement), + ]; } + return lua.createBreakStatement(breakStatement); }; export const transformContinueStatement: FunctionVisitor = (statement, context) => { - if (context.luaTarget === LuaTarget.Universal || context.luaTarget === LuaTarget.Lua51) { - context.diagnostics.push(unsupportedForTarget(statement, "Continue statement", LuaTarget.Lua51)); - } - const scope = findScope(context, ScopeType.Loop); + const continuedWith = { + [LuaTarget.Universal]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua50]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua51]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua52]: LoopContinued.WithGoto, + [LuaTarget.Lua53]: LoopContinued.WithGoto, + [LuaTarget.Lua54]: LoopContinued.WithGoto, + [LuaTarget.Lua55]: LoopContinued.WithGoto, + [LuaTarget.LuaJIT]: LoopContinued.WithGoto, + [LuaTarget.Luau]: LoopContinued.WithContinue, + }[context.luaTarget]; + if (scope) { - scope.loopContinued = true; + scope.loopContinued = continuedWith; + } + + const tryScope = isInAsyncFunction(statement) ? findAsyncTryScopeBeforeLoop(context) : undefined; + if (tryScope) { + tryScope.asyncTryHasContinue = continuedWith; + return [ + lua.createAssignmentStatement( + lua.createIdentifier("____hasContinued"), + lua.createBooleanLiteral(true), + statement + ), + lua.createReturnStatement([], statement), + ]; } - return lua.createGotoStatement(`__continue${scope?.id ?? ""}`, statement); + const label = `__continue${scope?.id ?? ""}`; + + switch (continuedWith) { + case LoopContinued.WithGoto: + return lua.createGotoStatement(label, statement); + + case LoopContinued.WithContinue: + return lua.createContinueStatement(statement); + + case LoopContinued.WithRepeatBreak: + return [ + lua.createAssignmentStatement(lua.createIdentifier(label), lua.createBooleanLiteral(true), statement), + lua.createBreakStatement(statement), + ]; + } }; diff --git a/src/transformation/visitors/call.ts b/src/transformation/visitors/call.ts index ced618c4c..c4a74135c 100644 --- a/src/transformation/visitors/call.ts +++ b/src/transformation/visitors/call.ts @@ -2,192 +2,173 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { transformBuiltinCallExpression } from "../builtins"; import { FunctionVisitor, TransformationContext } from "../context"; -import { AnnotationKind, getTypeAnnotations, isInTupleReturnFunction, isTupleReturnCall } from "../utils/annotations"; import { validateAssignment } from "../utils/assignment-validation"; -import { ContextType, getDeclarationContextType } from "../utils/function-context"; -import { createUnpackCall, wrapInTable } from "../utils/lua-ast"; -import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; +import { ContextType, getCallContextType } from "../utils/function-context"; +import { wrapInTable } from "../utils/lua-ast"; import { isValidLuaIdentifier } from "../utils/safe-names"; -import { isExpressionWithEvaluationEffect, isInDestructingAssignment } from "../utils/typescript"; +import { isExpressionWithEvaluationEffect } from "../utils/typescript"; import { transformElementAccessArgument } from "./access"; -import { shouldMultiReturnCallBeWrapped } from "./language-extensions/multi"; -import { isOperatorMapping, transformOperatorMappingExpression } from "./language-extensions/operators"; -import { - isTableDeleteCall, - isTableGetCall, - isTableHasCall, - isTableSetCall, - transformTableDeleteExpression, - transformTableGetExpression, - transformTableHasExpression, - transformTableSetExpression, -} from "./language-extensions/table"; -import { annotationRemoved, invalidTableDeleteExpression, invalidTableSetExpression } from "../utils/diagnostics"; -import { - ImmediatelyInvokedFunctionParameters, - transformToImmediatelyInvokedFunctionExpression, -} from "../utils/transform"; - -export type PropertyCallExpression = ts.CallExpression & { expression: ts.PropertyAccessExpression }; - -function getExpressionsBeforeAndAfterFirstSpread( - expressions: readonly ts.Expression[] -): [readonly ts.Expression[], readonly ts.Expression[]] { - // [a, b, ...c, d, ...e] --> [a, b] and [...c, d, ...e] - const index = expressions.findIndex(ts.isSpreadElement); - const hasSpreadElement = index !== -1; - const before = hasSpreadElement ? expressions.slice(0, index) : expressions; - const after = hasSpreadElement ? expressions.slice(index) : []; - return [before, after]; -} - -function transformSpreadableExpressionsIntoArrayConcatArguments( +import { isMultiReturnCall, shouldMultiReturnCallBeWrapped } from "./language-extensions/multi"; +import { unsupportedBuiltinOptionalCall } from "../utils/diagnostics"; +import { moveToPrecedingTemp, transformExpressionList } from "./expression-list"; +import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { getOptionalContinuationData, transformOptionalChain } from "./optional-chaining"; +import { transformImportExpression } from "./modules/import"; +import { transformLanguageExtensionCallExpression } from "./language-extensions/call-extension"; +import { getCustomNameFromSymbol } from "./identifier"; + +export function validateArguments( context: TransformationContext, - expressions: readonly ts.Expression[] | ts.NodeArray -): lua.Expression[] { - // [...array, a, b, ...tuple()] --> [ [...array], [a, b], [...tuple()] ] - // chunk non-spread arguments together so they don't concat - const chunks: ts.Expression[][] = []; - for (const [index, expression] of expressions.entries()) { - if (ts.isSpreadElement(expression)) { - chunks.push([expression]); - const next = expressions[index + 1]; - if (next && !ts.isSpreadElement(next)) { - chunks.push([]); - } - } else { - let lastChunk = chunks[chunks.length - 1]; - if (!lastChunk) { - lastChunk = []; - chunks.push(lastChunk); - } - lastChunk.push(expression); + params: readonly ts.Expression[], + signature?: ts.Signature +) { + if (!signature || signature.parameters.length < params.length) { + return; + } + for (const [index, param] of params.entries()) { + const signatureParameter = signature.parameters[index]; + if (signatureParameter.valueDeclaration !== undefined) { + const signatureType = context.checker.getTypeAtLocation(signatureParameter.valueDeclaration); + const paramType = context.checker.getTypeAtLocation(param); + validateAssignment(context, param, paramType, signatureType, signatureParameter.name); } } - - return chunks.map(chunk => wrapInTable(...chunk.map(expression => context.transformExpression(expression)))); } -export function flattenSpreadExpressions( +export function transformArguments( context: TransformationContext, - expressions: readonly ts.Expression[] + params: readonly ts.Expression[], + signature?: ts.Signature, + callContext?: ts.Expression ): lua.Expression[] { - const [preSpreadExpressions, postSpreadExpressions] = getExpressionsBeforeAndAfterFirstSpread(expressions); - const transformedPreSpreadExpressions = preSpreadExpressions.map(a => context.transformExpression(a)); + validateArguments(context, params, signature); + return transformExpressionList(context, callContext ? [callContext, ...params] : params); +} + +function transformCallWithArguments( + context: TransformationContext, + callExpression: ts.Expression, + transformedArguments: lua.Expression[], + argPrecedingStatements: lua.Statement[], + callContext?: ts.Expression +): [lua.Expression, lua.Expression[]] { + let call = context.transformExpression(callExpression); - // Nothing special required - if (postSpreadExpressions.length === 0) { - return transformedPreSpreadExpressions; + let transformedContext: lua.Expression | undefined; + if (callContext) { + transformedContext = context.transformExpression(callContext); } - // Only one spread element at the end? Will work as expected - if (postSpreadExpressions.length === 1) { - return [...transformedPreSpreadExpressions, context.transformExpression(postSpreadExpressions[0])]; + if (argPrecedingStatements.length > 0) { + if (transformedContext) { + transformedContext = moveToPrecedingTemp(context, transformedContext, callContext); + } + call = moveToPrecedingTemp(context, call, callExpression); + context.addPrecedingStatements(argPrecedingStatements); } - // Use Array.concat and unpack the result of that as the last Expression - const concatArguments = transformSpreadableExpressionsIntoArrayConcatArguments(context, postSpreadExpressions); - const lastExpression = createUnpackCall( - context, - transformLuaLibFunction(context, LuaLibFeature.ArrayConcat, undefined, ...concatArguments) - ); + if (transformedContext) { + transformedArguments.unshift(transformedContext); + } - return [...transformedPreSpreadExpressions, lastExpression]; + return [call, transformedArguments]; } -export function transformArguments( +export function transformCallAndArguments( context: TransformationContext, + callExpression: ts.Expression, params: readonly ts.Expression[], signature?: ts.Signature, callContext?: ts.Expression -): lua.Expression[] { - const parameters = flattenSpreadExpressions(context, params); - - // Add context as first param if present - if (callContext) { - parameters.unshift(context.transformExpression(callContext)); - } - - if (signature && signature.parameters.length >= params.length) { - for (const [index, param] of params.entries()) { - const signatureParameter = signature.parameters[index]; - const paramType = context.checker.getTypeAtLocation(param); - if (signatureParameter.valueDeclaration !== undefined) { - const signatureType = context.checker.getTypeAtLocation(signatureParameter.valueDeclaration); - validateAssignment(context, param, paramType, signatureType, signatureParameter.name); - } - } - } - - return parameters; +): [lua.Expression, lua.Expression[]] { + const { precedingStatements: argPrecedingStatements, result: transformedArguments } = + transformInPrecedingStatementScope(context, () => transformArguments(context, params, signature, callContext)); + return transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements); } function transformElementAccessCall( context: TransformationContext, left: ts.PropertyAccessExpression | ts.ElementAccessExpression, - args: ts.Expression[] | ts.NodeArray, - signature?: ts.Signature -): ImmediatelyInvokedFunctionParameters { - const transformedArguments = transformArguments(context, args, signature, ts.factory.createIdentifier("____self")); - + transformedArguments: lua.Expression[], + argPrecedingStatements: lua.Statement[] +) { // Cache left-side if it has effects - // (function() local ____self = context; return ____self[argument](parameters); end)() + // local ____self = context; return ____self[argument](parameters); + const selfIdentifier = lua.createIdentifier(context.createTempName("self")); + const callContext = context.transformExpression(left.expression); + const selfAssignment = lua.createVariableDeclarationStatement(selfIdentifier, callContext); + context.addPrecedingStatements(selfAssignment); + const argument = ts.isElementAccessExpression(left) ? transformElementAccessArgument(context, left) : lua.createStringLiteral(left.name.text); - const selfIdentifier = lua.createIdentifier("____self"); - const callContext = context.transformExpression(left.expression); - const selfAssignment = lua.createVariableDeclarationStatement(selfIdentifier, callContext); - const index = lua.createTableIndexExpression(selfIdentifier, argument); - const callExpression = lua.createCallExpression(index, transformedArguments); - return { statements: selfAssignment, result: callExpression }; + + let index: lua.Expression = lua.createTableIndexExpression(selfIdentifier, argument); + + if (argPrecedingStatements.length > 0) { + // Cache index in temp if args had preceding statements + index = moveToPrecedingTemp(context, index); + context.addPrecedingStatements(argPrecedingStatements); + } + + return lua.createCallExpression(index, [selfIdentifier, ...transformedArguments]); } export function transformContextualCallExpression( context: TransformationContext, node: ts.CallExpression | ts.TaggedTemplateExpression, - args: ts.Expression[] | ts.NodeArray, - signature?: ts.Signature -): lua.CallExpression | lua.MethodCallExpression { - const left = ts.isCallExpression(node) ? node.expression : node.tag; - if (ts.isPropertyAccessExpression(left) && ts.isIdentifier(left.name) && isValidLuaIdentifier(left.name.text)) { + args: ts.Expression[] | ts.NodeArray +): lua.Expression { + if (ts.isOptionalChain(node)) { + return transformOptionalChain(context, node); + } + const left = ts.isCallExpression(node) ? getCalledExpression(node) : node.tag; + + let { precedingStatements: argPrecedingStatements, result: transformedArguments } = + transformInPrecedingStatementScope(context, () => transformArguments(context, args)); + + if ( + ts.isPropertyAccessExpression(left) && + ts.isIdentifier(left.name) && + isValidLuaIdentifier(left.name.text, context.options) && + argPrecedingStatements.length === 0 + ) { // table:name() const table = context.transformExpression(left.expression); + let name = left.name.text; - if (ts.isOptionalChain(node)) { - return transformLuaLibFunction( - context, - LuaLibFeature.OptionalMethodCall, - node, - table, - lua.createStringLiteral(left.name.text, left.name), - ...transformArguments(context, args, signature) - ); - } else { - return lua.createMethodCallExpression( - table, - lua.createIdentifier(left.name.text, left.name), - transformArguments(context, args, signature), - node - ); + const symbol = context.checker.getSymbolAtLocation(left); + const customName = getCustomNameFromSymbol(context, symbol); + + if (customName) { + name = customName; } + + return lua.createMethodCallExpression(table, lua.createIdentifier(name, left.name), transformedArguments, node); } else if (ts.isElementAccessExpression(left) || ts.isPropertyAccessExpression(left)) { if (isExpressionWithEvaluationEffect(left.expression)) { - return transformToImmediatelyInvokedFunctionExpression( + return transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements); + } else { + let expression: lua.Expression; + [expression, transformedArguments] = transformCallWithArguments( context, - () => transformElementAccessCall(context, left, args, signature), - node + left, + transformedArguments, + argPrecedingStatements, + left.expression ); - } else { - const callContext = context.transformExpression(left.expression); - const expression = context.transformExpression(left); - const transformedArguments = transformArguments(context, args, signature); - return lua.createCallExpression(expression, [callContext, ...transformedArguments]); + return lua.createCallExpression(expression, transformedArguments, node); } - } else if (ts.isIdentifier(left)) { + } else if (ts.isIdentifier(left) || ts.isCallExpression(left)) { const callContext = context.isStrict ? ts.factory.createNull() : ts.factory.createIdentifier("_G"); - const transformedArguments = transformArguments(context, args, signature, callContext); - const expression = context.transformExpression(left); + let expression: lua.Expression; + [expression, transformedArguments] = transformCallWithArguments( + context, + left, + transformedArguments, + argPrecedingStatements, + callContext + ); return lua.createCallExpression(expression, transformedArguments, node); } else { throw new Error(`Unsupported LeftHandSideExpression kind: ${ts.SyntaxKind[left.kind]}`); @@ -196,117 +177,78 @@ export function transformContextualCallExpression( function transformPropertyCall( context: TransformationContext, - node: PropertyCallExpression -): lua.CallExpression | lua.MethodCallExpression { + node: ts.CallExpression, + calledMethod: ts.PropertyAccessExpression +): lua.Expression { const signature = context.checker.getResolvedSignature(node); - if (node.expression.expression.kind === ts.SyntaxKind.SuperKeyword) { + if (calledMethod.expression.kind === ts.SyntaxKind.SuperKeyword) { // Super calls take the format of super.call(self,...) const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis()); - return lua.createCallExpression(context.transformExpression(node.expression), parameters); + return lua.createCallExpression(context.transformExpression(node.expression), parameters, node); } - const signatureDeclaration = signature?.getDeclaration(); - if (!signatureDeclaration || getDeclarationContextType(context, signatureDeclaration) !== ContextType.Void) { + if (getCallContextType(context, node) !== ContextType.Void) { // table:name() - return transformContextualCallExpression(context, node, node.arguments, signature); + return transformContextualCallExpression(context, node, node.arguments); } else { // table.name() - const callPath = context.transformExpression(node.expression); - const parameters = transformArguments(context, node.arguments, signature); + const [callPath, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature); - if (ts.isOptionalChain(node)) { - return transformLuaLibFunction(context, LuaLibFeature.OptionalFunctionCall, node, callPath, ...parameters); - } else { - return lua.createCallExpression(callPath, parameters, node); - } + return lua.createCallExpression(callPath, parameters, node); } } -function transformElementCall( - context: TransformationContext, - node: ts.CallExpression -): lua.CallExpression | lua.MethodCallExpression { - const signature = context.checker.getResolvedSignature(node); - const signatureDeclaration = signature?.getDeclaration(); - if (!signatureDeclaration || getDeclarationContextType(context, signatureDeclaration) !== ContextType.Void) { +function transformElementCall(context: TransformationContext, node: ts.CallExpression): lua.Expression { + if (getCallContextType(context, node) !== ContextType.Void) { // A contextual parameter must be given to this call expression - return transformContextualCallExpression(context, node, node.arguments, signature); + return transformContextualCallExpression(context, node, node.arguments); } else { // No context - const expression = context.transformExpression(node.expression); - const parameters = transformArguments(context, node.arguments, signature); - return lua.createCallExpression(expression, parameters); + const [expression, parameters] = transformCallAndArguments(context, node.expression, node.arguments); + return lua.createCallExpression(expression, parameters, node); } } export const transformCallExpression: FunctionVisitor = (node, context) => { - const isTupleReturn = isTupleReturnCall(context, node); - const isTupleReturnForward = - node.parent && ts.isReturnStatement(node.parent) && isInTupleReturnFunction(context, node); - const isInSpread = node.parent && ts.isSpreadElement(node.parent); - const returnValueIsUsed = node.parent && !ts.isExpressionStatement(node.parent); - const wrapTupleReturn = - isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment(node) && !isInSpread && returnValueIsUsed; - const wrapResultInTable = wrapTupleReturn || shouldMultiReturnCallBeWrapped(context, node); - const wrapResultInOptional = ts.isOptionalChain(node); - - const builtinResult = transformBuiltinCallExpression(context, node); - if (builtinResult) { - return wrapResultInTable ? wrapInTable(builtinResult) : builtinResult; - } - - if (isOperatorMapping(context, node)) { - return transformOperatorMappingExpression(context, node); - } - - if (isTableDeleteCall(context, node)) { - context.diagnostics.push(invalidTableDeleteExpression(node)); - return transformToImmediatelyInvokedFunctionExpression( - context, - () => ({ statements: transformTableDeleteExpression(context, node), result: lua.createNilLiteral() }), - node - ); - } + const calledExpression = getCalledExpression(node); - if (isTableGetCall(context, node)) { - return transformTableGetExpression(context, node); + if (calledExpression.kind === ts.SyntaxKind.ImportKeyword) { + return transformImportExpression(node, context); } - if (isTableHasCall(context, node)) { - return transformTableHasExpression(context, node); + if (ts.isOptionalChain(node)) { + return transformOptionalChain(context, node); } - if (isTableSetCall(context, node)) { - context.diagnostics.push(invalidTableSetExpression(node)); - return transformToImmediatelyInvokedFunctionExpression( - context, - () => ({ statements: transformTableSetExpression(context, node), result: lua.createNilLiteral() }), - node - ); - } + const optionalContinuation = ts.isIdentifier(calledExpression) + ? getOptionalContinuationData(calledExpression) + : undefined; + const wrapResultInTable = isMultiReturnCall(context, node) && shouldMultiReturnCallBeWrapped(context, node); - if (ts.isPropertyAccessExpression(node.expression)) { - const ownerType = context.checker.getTypeAtLocation(node.expression.expression); - const annotations = getTypeAnnotations(ownerType); - if (annotations.has(AnnotationKind.LuaTable)) { - context.diagnostics.push(annotationRemoved(node, AnnotationKind.LuaTable)); + const builtinOrExtensionResult = + transformBuiltinCallExpression(context, node) ?? transformLanguageExtensionCallExpression(context, node); + if (builtinOrExtensionResult) { + if (optionalContinuation !== undefined) { + context.diagnostics.push(unsupportedBuiltinOptionalCall(node)); } + return wrapResultInTable ? wrapInTable(builtinOrExtensionResult) : builtinOrExtensionResult; + } - const result = transformPropertyCall(context, node as PropertyCallExpression); - // transformPropertyCall already wraps optional so no need to do so here + if (ts.isPropertyAccessExpression(calledExpression)) { + const result = transformPropertyCall(context, node, calledExpression); return wrapResultInTable ? wrapInTable(result) : result; } - if (ts.isElementAccessExpression(node.expression)) { + if (ts.isElementAccessExpression(calledExpression)) { const result = transformElementCall(context, node); - return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, result, node); + return wrapResultInTable ? wrapInTable(result) : result; } const signature = context.checker.getResolvedSignature(node); // Handle super calls properly - if (node.expression.kind === ts.SyntaxKind.SuperKeyword) { + if (calledExpression.kind === ts.SyntaxKind.SuperKeyword) { const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis()); return lua.createCallExpression( @@ -314,57 +256,38 @@ export const transformCallExpression: FunctionVisitor = (node context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor") ), - parameters + parameters, + node ); } - const callPath = context.transformExpression(node.expression); - const signatureDeclaration = signature?.getDeclaration(); + let callPath: lua.Expression; + let parameters: lua.Expression[]; + + const isContextualCall = getCallContextType(context, node) !== ContextType.Void; - let parameters: lua.Expression[] = []; - if (signatureDeclaration && getDeclarationContextType(context, signatureDeclaration) === ContextType.Void) { - parameters = transformArguments(context, node.arguments, signature); + if (!isContextualCall) { + [callPath, parameters] = transformCallAndArguments(context, calledExpression, node.arguments, signature); } else { - const callContext = context.isStrict ? ts.factory.createNull() : ts.factory.createIdentifier("_G"); - parameters = transformArguments(context, node.arguments, signature, callContext); + // if is optionalContinuation, context will be handled by transformOptionalChain. + const useGlobalContext = !context.isStrict && optionalContinuation === undefined; + const callContext = useGlobalContext ? ts.factory.createIdentifier("_G") : ts.factory.createNull(); + [callPath, parameters] = transformCallAndArguments( + context, + calledExpression, + node.arguments, + signature, + callContext + ); } const callExpression = lua.createCallExpression(callPath, parameters, node); - return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, callExpression, node); + if (optionalContinuation && isContextualCall) { + optionalContinuation.contextualCall = callExpression; + } + return wrapResultInTable ? wrapInTable(callExpression) : callExpression; }; -function wrapIfRequired( - context: TransformationContext, - shouldWrapInTable: boolean, - shouldWrapOptional: boolean, - call: lua.CallExpression | lua.MethodCallExpression, - node: ts.Node -): lua.Expression { - const wrappedOptional = shouldWrapOptional ? wrapOptionalCall(context, call, node) : call; - return shouldWrapInTable ? wrapInTable(wrappedOptional) : wrappedOptional; -} - -function wrapOptionalCall( - context: TransformationContext, - call: lua.CallExpression | lua.MethodCallExpression, - node: ts.Node -): lua.CallExpression { - if (lua.isMethodCallExpression(call)) { - return transformLuaLibFunction( - context, - LuaLibFeature.OptionalMethodCall, - node, - call.prefixExpression, - lua.createStringLiteral(call.name.text), - ...call.params - ); - } else { - return transformLuaLibFunction( - context, - LuaLibFeature.OptionalFunctionCall, - node, - call.expression, - ...call.params - ); - } +export function getCalledExpression(node: ts.CallExpression): ts.Expression { + return ts.skipOuterExpressions(node.expression); } diff --git a/src/transformation/visitors/class/decorators.ts b/src/transformation/visitors/class/decorators.ts index 4b913485c..11e4b75c7 100644 --- a/src/transformation/visitors/class/decorators.ts +++ b/src/transformation/visitors/class/decorators.ts @@ -1,9 +1,13 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; -import { decoratorInvalidContext } from "../../utils/diagnostics"; +import { decoratorInvalidContext, incompleteFieldDecoratorWarning } from "../../utils/diagnostics"; import { ContextType, getFunctionContextType } from "../../utils/function-context"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; +import { isNonNull } from "../../../utils"; +import { transformMemberExpressionOwnerName, transformMethodName } from "./members/method"; +import { transformPropertyName } from "../literal"; +import { isPrivateNode, isStaticNode } from "./utils"; export function transformDecoratorExpression(context: TransformationContext, decorator: ts.Decorator): lua.Expression { const expression = decorator.expression; @@ -16,7 +20,161 @@ export function transformDecoratorExpression(context: TransformationContext, dec return context.transformExpression(expression); } -export function createDecoratingExpression( +export function createClassDecoratingExpression( + context: TransformationContext, + classDeclaration: ts.ClassDeclaration | ts.ClassExpression, + className: lua.Expression +): lua.Expression { + const classDecorators = + ts.getDecorators(classDeclaration)?.map(d => transformDecoratorExpression(context, d)) ?? []; + + // If experimentalDecorators flag is set, decorate with legacy decorator logic + if (context.options.experimentalDecorators) { + return createLegacyDecoratingExpression(context, classDeclaration.kind, classDecorators, className); + } + + // Else: TypeScript 5.0 decorator + return createDecoratingExpression(context, className, className, classDecorators, { + kind: lua.createStringLiteral("class"), + name: lua.createStringLiteral(classDeclaration.name?.getText() ?? ""), + }); +} + +export function createClassMethodDecoratingExpression( + context: TransformationContext, + methodDeclaration: ts.MethodDeclaration, + originalMethod: lua.Expression, + className: lua.Identifier +): lua.Expression { + const parameterDecorators = getParameterDecorators(context, methodDeclaration); + const methodDecorators = + ts.getDecorators(methodDeclaration)?.map(d => transformDecoratorExpression(context, d)) ?? []; + + const methodName = transformMethodName(context, methodDeclaration); + + // If experimentalDecorators flag is set, decorate with legacy decorator logic + if (context.options.experimentalDecorators) { + const methodTable = transformMemberExpressionOwnerName(methodDeclaration, className); + return createLegacyDecoratingExpression( + context, + methodDeclaration.kind, + [...methodDecorators, ...parameterDecorators], + methodTable, + methodName + ); + } + + // Else: TypeScript 5.0 decorator + return createDecoratingExpression(context, className, originalMethod, methodDecorators, { + kind: lua.createStringLiteral("method"), + name: methodName, + private: lua.createBooleanLiteral(isPrivateNode(methodDeclaration)), + static: lua.createBooleanLiteral(isStaticNode(methodDeclaration)), + }); +} + +export function createClassAccessorDecoratingExpression( + context: TransformationContext, + accessor: ts.AccessorDeclaration, + originalAccessor: lua.Expression, + className: lua.Identifier +): lua.Expression { + const accessorDecorators = ts.getDecorators(accessor)?.map(d => transformDecoratorExpression(context, d)) ?? []; + const propertyName = transformPropertyName(context, accessor.name); + + // If experimentalDecorators flag is set, decorate with legacy decorator logic + if (context.options.experimentalDecorators) { + const propertyOwnerTable = transformMemberExpressionOwnerName(accessor, className); + + return createLegacyDecoratingExpression( + context, + accessor.kind, + accessorDecorators, + propertyOwnerTable, + propertyName + ); + } + + // Else: TypeScript 5.0 decorator + return createDecoratingExpression(context, className, originalAccessor, accessorDecorators, { + kind: lua.createStringLiteral(accessor.kind === ts.SyntaxKind.SetAccessor ? "setter" : "getter"), + name: propertyName, + private: lua.createBooleanLiteral(isPrivateNode(accessor)), + static: lua.createBooleanLiteral(isStaticNode(accessor)), + }); +} + +export function createClassPropertyDecoratingExpression( + context: TransformationContext, + property: ts.PropertyDeclaration, + className: lua.Identifier +): lua.Expression { + const decorators = ts.getDecorators(property) ?? []; + const propertyDecorators = decorators.map(d => transformDecoratorExpression(context, d)); + + // If experimentalDecorators flag is set, decorate with legacy decorator logic + if (context.options.experimentalDecorators) { + const propertyName = transformPropertyName(context, property.name); + const propertyOwnerTable = transformMemberExpressionOwnerName(property, className); + + return createLegacyDecoratingExpression( + context, + property.kind, + propertyDecorators, + propertyOwnerTable, + propertyName + ); + } + + // Else: TypeScript 5.0 decorator + + // Add a diagnostic when something is returned from a field decorator + for (const decorator of decorators) { + const signature = context.checker.getResolvedSignature(decorator); + const decoratorReturnType = signature?.getReturnType(); + // If return type of decorator is NOT void + if (decoratorReturnType && (decoratorReturnType.flags & ts.TypeFlags.Void) === 0) { + context.diagnostics.push(incompleteFieldDecoratorWarning(property)); + } + } + + return createDecoratingExpression(context, className, lua.createNilLiteral(), propertyDecorators, { + kind: lua.createStringLiteral("field"), + name: lua.createStringLiteral(property.name.getText()), + private: lua.createBooleanLiteral(isPrivateNode(property)), + static: lua.createBooleanLiteral(isStaticNode(property)), + }); +} + +function createDecoratingExpression( + context: TransformationContext, + className: lua.Expression, + originalValue: TValue, + decorators: lua.Expression[], + decoratorContext: Record +): lua.Expression { + const decoratorTable = lua.createTableExpression(decorators.map(d => lua.createTableFieldExpression(d))); + const decoratorContextTable = objectToLuaTableLiteral(decoratorContext); + + return transformLuaLibFunction( + context, + LuaLibFeature.Decorate, + undefined, + className, + originalValue, + decoratorTable, + decoratorContextTable + ); +} + +function objectToLuaTableLiteral(obj: Record): lua.Expression { + return lua.createTableExpression( + Object.entries(obj).map(([key, value]) => lua.createTableFieldExpression(value, lua.createStringLiteral(key))) + ); +} + +// Legacy decorators: +function createLegacyDecoratingExpression( context: TransformationContext, kind: ts.SyntaxKind, decorators: lua.Expression[], @@ -35,5 +193,39 @@ export function createDecoratingExpression( trailingExpressions.push(isMethodOrAccessor ? lua.createBooleanLiteral(true) : lua.createNilLiteral()); } - return transformLuaLibFunction(context, LuaLibFeature.Decorate, undefined, ...trailingExpressions); + return transformLuaLibFunction(context, LuaLibFeature.DecorateLegacy, undefined, ...trailingExpressions); +} + +function getParameterDecorators( + context: TransformationContext, + node: ts.FunctionLikeDeclarationBase +): lua.CallExpression[] { + return node.parameters + .flatMap((parameter, index) => + ts + .getDecorators(parameter) + ?.map(decorator => + transformLuaLibFunction( + context, + LuaLibFeature.DecorateParam, + node, + lua.createNumericLiteral(index), + transformDecoratorExpression(context, decorator) + ) + ) + ) + .filter(isNonNull); +} + +export function createConstructorDecoratingExpression( + context: TransformationContext, + node: ts.ConstructorDeclaration, + className: lua.Identifier +): lua.Statement | undefined { + const parameterDecorators = getParameterDecorators(context, node); + + if (parameterDecorators.length > 0) { + const decorateMethod = createLegacyDecoratingExpression(context, node.kind, parameterDecorators, className); + return lua.createExpressionStatement(decorateMethod); + } } diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index 98d74f84a..f2024babe 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -1,38 +1,37 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; -import { getOrUpdate } from "../../../utils"; -import { FunctionVisitor, TransformationContext } from "../../context"; -import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { annotationRemoved } from "../../utils/diagnostics"; +import { AllAccessorDeclarations, FunctionVisitor, TransformationContext } from "../../context"; import { - createDefaultExportIdentifier, + createDefaultExportExpression, createExportedIdentifier, hasDefaultExportModifier, isSymbolExported, + shouldBeExported, } from "../../utils/export"; -import { createSelfIdentifier, unwrapVisitorResult } from "../../utils/lua-ast"; +import { createSelfIdentifier } from "../../utils/lua-ast"; import { createSafeName, isUnsafeName } from "../../utils/safe-names"; -import { transformToImmediatelyInvokedFunctionExpression } from "../../utils/transform"; import { transformIdentifier } from "../identifier"; -import { createDecoratingExpression, transformDecoratorExpression } from "./decorators"; +import { createClassDecoratingExpression, createConstructorDecoratingExpression } from "./decorators"; import { transformAccessorDeclarations } from "./members/accessors"; import { createConstructorName, transformConstructorDeclaration } from "./members/constructor"; -import { - createPropertyDecoratingExpression, - transformClassInstanceFields, - transformStaticPropertyDeclaration, -} from "./members/fields"; -import { createMethodDecoratingExpression, transformMethodDeclaration } from "./members/method"; -import { checkForLuaLibType } from "./new"; -import { createClassSetup } from "./setup"; +import { transformClassInstanceFields, transformStaticPropertyDeclaration } from "./members/fields"; +import { transformMethodDeclaration } from "./members/method"; import { getExtendedNode, getExtendedType, isStaticNode } from "./utils"; +import { createClassSetup } from "./setup"; +import { LuaTarget } from "../../../CompilerOptions"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; +import { createClassPropertyDecoratingExpression } from "./decorators"; +import { findFirstNodeAbove } from "../../utils/typescript"; export const transformClassDeclaration: FunctionVisitor = (declaration, context) => { // If declaration is a default export, transform to export variable assignment instead if (hasDefaultExportModifier(declaration)) { - const left = createExportedIdentifier(context, createDefaultExportIdentifier(declaration)); - const right = transformClassAsExpression(declaration, context); - return [lua.createAssignmentStatement(left, right, declaration)]; + // Class declaration including assignment to ____exports.default are in preceding statements + const { precedingStatements } = transformInPrecedingStatementScope(context, () => { + transformClassAsExpression(declaration, context); + return []; + }); + return precedingStatements; } const { statements } = transformClassLikeDeclaration(declaration, context); @@ -45,18 +44,13 @@ export function transformClassAsExpression( expression: ts.ClassLikeDeclaration, context: TransformationContext ): lua.Expression { - return transformToImmediatelyInvokedFunctionExpression( - context, - () => { - const { statements, name } = transformClassLikeDeclaration(expression, context); - return { statements: unwrapVisitorResult(statements), result: name }; - }, - expression - ); + const { statements, name } = transformClassLikeDeclaration(expression, context); + context.addPrecedingStatements(statements); + return name; } -const classSuperInfos = new WeakMap(); -interface ClassSuperInfo { +/** @internal */ +export interface ClassSuperInfo { className: lua.Identifier; extendedTypeNode?: ts.ExpressionWithTypeArguments; } @@ -72,29 +66,14 @@ function transformClassLikeDeclaration( } else if (classDeclaration.name !== undefined) { className = transformIdentifier(context, classDeclaration.name); } else { - // TypeScript error - className = lua.createAnonymousIdentifier(); - } - - const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(classDeclaration)); - - if (annotations.has(AnnotationKind.Extension)) { - context.diagnostics.push(annotationRemoved(classDeclaration, AnnotationKind.Extension)); - } - if (annotations.has(AnnotationKind.MetaExtension)) { - context.diagnostics.push(annotationRemoved(classDeclaration, AnnotationKind.MetaExtension)); + className = lua.createIdentifier(context.createTempName("class"), classDeclaration); } // Get type that is extended - const extendedTypeNode = getExtendedNode(context, classDeclaration); + const extendedTypeNode = getExtendedNode(classDeclaration); const extendedType = getExtendedType(context, classDeclaration); - const superInfo = getOrUpdate(classSuperInfos, context, () => []); - superInfo.push({ className, extendedTypeNode }); - - if (extendedType) { - checkForLuaLibType(context, extendedType); - } + context.classSuperInfos.push({ className, extendedTypeNode }); // Get all properties with value const properties = classDeclaration.members.filter(ts.isPropertyDeclaration).filter(member => member.initializer); @@ -105,7 +84,7 @@ function transformClassLikeDeclaration( const result: lua.Statement[] = []; let localClassName: lua.Identifier; - if (isUnsafeName(className.text)) { + if (isUnsafeName(className.text, context.options)) { localClassName = lua.createIdentifier( createSafeName(className.text), undefined, @@ -135,11 +114,15 @@ function transformClassLikeDeclaration( ); if (constructorResult) result.push(constructorResult); + + // Legacy constructor decorator + const decoratingExpression = createConstructorDecoratingExpression(context, constructor, localClassName); + if (decoratingExpression) result.push(decoratingExpression); } else if (!extendedType) { // Generate a constructor if none was defined in a base class const constructorResult = transformConstructorDeclaration( context, - ts.factory.createConstructorDeclaration([], [], [], ts.factory.createBlock([], true)), + ts.factory.createConstructorDeclaration([], [], ts.factory.createBlock([], true)), localClassName, instanceFields, classDeclaration @@ -149,16 +132,20 @@ function transformClassLikeDeclaration( } else if (instanceFields.length > 0) { // Generate a constructor if none was defined in a class with instance fields that need initialization // localClassName.prototype.____constructor = function(self, ...) - // baseClassName.prototype.____constructor(self, ...) + // baseClassName.prototype.____constructor(self, ...) // or unpack(arg) for Lua 5.0 // ... const constructorBody = transformClassInstanceFields(context, instanceFields); + const argsExpression = + context.luaTarget === LuaTarget.Lua50 + ? lua.createCallExpression(lua.createIdentifier("unpack"), [lua.createArgLiteral()]) + : lua.createDotsLiteral(); const superCall = lua.createExpressionStatement( lua.createCallExpression( lua.createTableIndexExpression( context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor") ), - [createSelfIdentifier(), lua.createDotsLiteral()] + [createSelfIdentifier(), argsExpression] ) ); constructorBody.unshift(superCall); @@ -166,69 +153,109 @@ function transformClassLikeDeclaration( lua.createBlock(constructorBody), [createSelfIdentifier()], lua.createDotsLiteral(), - lua.FunctionExpressionFlags.Declaration + lua.NodeFlags.Declaration ); result.push( lua.createAssignmentStatement(createConstructorName(localClassName), constructorFunction, classDeclaration) ); } - // Transform accessors - for (const member of classDeclaration.members) { - if (!ts.isAccessor(member)) continue; - const accessors = context.resolver.getAllAccessorDeclarations(member); - if (accessors.firstAccessor !== member) continue; + // Transform class members - const accessorsResult = transformAccessorDeclarations(context, accessors, localClassName); - if (accessorsResult) { - result.push(accessorsResult); + // First transform the methods, in case the static properties call them + for (const member of classDeclaration.members) { + if (ts.isMethodDeclaration(member)) { + // Methods + const statements = transformMethodDeclaration(context, member, localClassName); + result.push(...statements); } } - const decorationStatements: lua.Statement[] = []; - + // Then transform the rest for (const member of classDeclaration.members) { if (ts.isAccessor(member)) { - const expression = createPropertyDecoratingExpression(context, member, localClassName); - if (expression) decorationStatements.push(lua.createExpressionStatement(expression)); - } else if (ts.isMethodDeclaration(member)) { - const statement = transformMethodDeclaration(context, member, localClassName); - if (statement) result.push(statement); - if (member.body) { - const statement = createMethodDecoratingExpression(context, member, localClassName); - if (statement) decorationStatements.push(statement); + // Accessors + const symbol = context.checker.getSymbolAtLocation(member.name); + if (!symbol) continue; + const accessors = getAllAccessorDeclarations(classDeclaration, symbol, context); + if (accessors.firstAccessor !== member) continue; + + const accessorsResult = transformAccessorDeclarations(context, accessors, localClassName); + if (accessorsResult) { + result.push(accessorsResult); } } else if (ts.isPropertyDeclaration(member)) { + // Properties if (isStaticNode(member)) { const statement = transformStaticPropertyDeclaration(context, member, localClassName); - if (statement) decorationStatements.push(statement); + if (statement) result.push(statement); + } + + if (ts.getDecorators(member)?.length) { + result.push( + lua.createExpressionStatement(createClassPropertyDecoratingExpression(context, member, className)) + ); + } + } else if (ts.isClassStaticBlockDeclaration(member)) { + if (member.body.statements.length > 0) { + const bodyStatements = context.transformStatements(member.body.statements); + const iif = lua.createFunctionExpression(lua.createBlock(bodyStatements), [ + lua.createIdentifier("self"), + ]); + const iife = lua.createCallExpression(iif, [localClassName]); + result.push(lua.createExpressionStatement(iife, member)); } - const expression = createPropertyDecoratingExpression(context, member, localClassName); - if (expression) decorationStatements.push(lua.createExpressionStatement(expression)); } } - result.push(...decorationStatements); - // Decorate the class - if (classDeclaration.decorators) { - const decoratingExpression = createDecoratingExpression( - context, - classDeclaration.kind, - classDeclaration.decorators.map(d => transformDecoratorExpression(context, d)), - localClassName - ); + if (ts.canHaveDecorators(classDeclaration) && ts.getDecorators(classDeclaration)) { + const decoratingExpression = createClassDecoratingExpression(context, classDeclaration, localClassName); const decoratingStatement = lua.createAssignmentStatement(localClassName, decoratingExpression); result.push(decoratingStatement); + + if (shouldBeExported(classDeclaration)) { + const exportExpression = hasDefaultExportModifier(classDeclaration) + ? createDefaultExportExpression(classDeclaration) + : createExportedIdentifier(context, localClassName); + + const classAssignment = lua.createAssignmentStatement(exportExpression, localClassName); + result.push(classAssignment); + } } - superInfo.pop(); + context.classSuperInfos.pop(); return { statements: result, name: className }; } +function getAllAccessorDeclarations( + classDeclaration: ts.ClassLikeDeclaration, + symbol: ts.Symbol, + context: TransformationContext +): AllAccessorDeclarations { + const getAccessor = classDeclaration.members.find( + (m): m is ts.GetAccessorDeclaration => + ts.isGetAccessor(m) && context.checker.getSymbolAtLocation(m.name) === symbol + ); + const setAccessor = classDeclaration.members.find( + (m): m is ts.SetAccessorDeclaration => + ts.isSetAccessor(m) && context.checker.getSymbolAtLocation(m.name) === symbol + ); + + // Get the first of the two (that is not undefined) + const firstAccessor = + getAccessor && (!setAccessor || getAccessor.pos < setAccessor.pos) ? getAccessor : setAccessor!; + + return { + firstAccessor, + setAccessor, + getAccessor, + }; +} + export const transformSuperExpression: FunctionVisitor = (expression, context) => { - const superInfos = getOrUpdate(classSuperInfos, context, () => []); + const superInfos = context.classSuperInfos; const superInfo = superInfos[superInfos.length - 1]; if (!superInfo) return lua.createAnonymousIdentifier(expression); const { className, extendedTypeNode } = superInfo; @@ -245,10 +272,14 @@ export const transformSuperExpression: FunctionVisitor = (ex } } - if (!baseClassName) { - // Use "className.____super" if the base is not a simple identifier - baseClassName = lua.createTableIndexExpression(className, lua.createStringLiteral("____super"), expression); - } + // Use "className.____super" if the base is not a simple identifier + baseClassName ??= lua.createTableIndexExpression(className, lua.createStringLiteral("____super"), expression); - return lua.createTableIndexExpression(baseClassName, lua.createStringLiteral("prototype")); + const f = findFirstNodeAbove(expression, ts.isFunctionLike); + if (f && ts.canHaveModifiers(f) && isStaticNode(f)) { + // In static method, don't add prototype to super call + return baseClassName; + } else { + return lua.createTableIndexExpression(baseClassName, lua.createStringLiteral("prototype")); + } }; diff --git a/src/transformation/visitors/class/members/accessors.ts b/src/transformation/visitors/class/members/accessors.ts index f774b9645..017100056 100644 --- a/src/transformation/visitors/class/members/accessors.ts +++ b/src/transformation/visitors/class/members/accessors.ts @@ -7,11 +7,27 @@ import { transformFunctionBody, transformParameters } from "../../function"; import { transformPropertyName } from "../../literal"; import { isStaticNode } from "../utils"; import { createPrototypeName } from "./constructor"; +import { createClassAccessorDecoratingExpression } from "../decorators"; -function transformAccessor(context: TransformationContext, node: ts.AccessorDeclaration): lua.FunctionExpression { +function transformAccessor( + context: TransformationContext, + node: ts.AccessorDeclaration, + className: lua.Identifier +): lua.Expression { const [params, dot, restParam] = transformParameters(context, node.parameters, createSelfIdentifier()); - const body = node.body ? transformFunctionBody(context, node.parameters, node.body, restParam)[0] : []; - return lua.createFunctionExpression(lua.createBlock(body), params, dot, lua.FunctionExpressionFlags.Declaration); + const body = node.body ? transformFunctionBody(context, node.parameters, node.body, node, restParam)[0] : []; + const accessorFunction = lua.createFunctionExpression( + lua.createBlock(body), + params, + dot, + lua.NodeFlags.Declaration + ); + + if (ts.getDecorators(node)?.length) { + return createClassAccessorDecoratingExpression(context, node, accessorFunction, className); + } else { + return accessorFunction; + } } export function transformAccessorDeclarations( @@ -23,12 +39,12 @@ export function transformAccessorDeclarations( const descriptor = lua.createTableExpression([]); if (getAccessor) { - const getterFunction = transformAccessor(context, getAccessor); + const getterFunction = transformAccessor(context, getAccessor, className); descriptor.fields.push(lua.createTableFieldExpression(getterFunction, lua.createStringLiteral("get"))); } if (setAccessor) { - const setterFunction = transformAccessor(context, setAccessor); + const setterFunction = transformAccessor(context, setAccessor, className); descriptor.fields.push(lua.createTableFieldExpression(setterFunction, lua.createStringLiteral("set"))); } diff --git a/src/transformation/visitors/class/members/constructor.ts b/src/transformation/visitors/class/members/constructor.ts index 11766d2a8..8bff2f4fc 100644 --- a/src/transformation/visitors/class/members/constructor.ts +++ b/src/transformation/visitors/class/members/constructor.ts @@ -2,7 +2,7 @@ import * as ts from "typescript"; import * as lua from "../../../../LuaAST"; import { TransformationContext } from "../../../context"; import { createSelfIdentifier } from "../../../utils/lua-ast"; -import { popScope, pushScope, ScopeType } from "../../../utils/scope"; +import { ScopeType } from "../../../utils/scope"; import { transformFunctionBodyContent, transformFunctionBodyHeader, transformParameters } from "../../function"; import { transformIdentifier } from "../../identifier"; import { transformClassInstanceFields } from "./fields"; @@ -28,7 +28,7 @@ export function transformConstructorDeclaration( } // Transform body - const scope = pushScope(context, ScopeType.Function); + const scope = context.pushScope(ScopeType.Function, statement); const body = transformFunctionBodyContent(context, statement.body); const [params, dotsLiteral, restParamName] = transformParameters( @@ -45,23 +45,22 @@ export function transformConstructorDeclaration( const classInstanceFields = transformClassInstanceFields(context, instanceFields); - // If there are field initializers and the first statement is a super call, - // move super call between default assignments and initializers + // If there are field initializers and there is a super call somewhere, + // move super call and everything before it to between default assignments and initializers if ( (constructorFieldsDeclarations.length > 0 || classInstanceFields.length > 0) && statement.body && statement.body.statements.length > 0 ) { - const firstStatement = statement.body.statements[0]; - if ( - ts.isExpressionStatement(firstStatement) && - ts.isCallExpression(firstStatement.expression) && - firstStatement.expression.expression.kind === ts.SyntaxKind.SuperKeyword - ) { - const superCall = body.shift(); - if (superCall) { - bodyWithFieldInitializers.push(superCall); - } + const superIndex = statement.body.statements.findIndex( + s => + ts.isExpressionStatement(s) && + ts.isCallExpression(s.expression) && + s.expression.expression.kind === ts.SyntaxKind.SuperKeyword + ); + + if (superIndex !== -1) { + bodyWithFieldInitializers.push(...body.splice(0, superIndex + 1)); } } @@ -86,11 +85,11 @@ export function transformConstructorDeclaration( const constructorWasGenerated = statement.pos === -1; - popScope(context); + context.popScope(); return lua.createAssignmentStatement( createConstructorName(className), - lua.createFunctionExpression(block, params, dotsLiteral, lua.FunctionExpressionFlags.Declaration), + lua.createFunctionExpression(block, params, dotsLiteral, lua.NodeFlags.Declaration), constructorWasGenerated ? classDeclaration : statement ); } diff --git a/src/transformation/visitors/class/members/fields.ts b/src/transformation/visitors/class/members/fields.ts index 980c6f851..2308eaac8 100644 --- a/src/transformation/visitors/class/members/fields.ts +++ b/src/transformation/visitors/class/members/fields.ts @@ -2,26 +2,8 @@ import * as ts from "typescript"; import * as lua from "../../../../LuaAST"; import { TransformationContext } from "../../../context"; import { createSelfIdentifier } from "../../../utils/lua-ast"; +import { transformInPrecedingStatementScope } from "../../../utils/preceding-statements"; import { transformPropertyName } from "../../literal"; -import { createDecoratingExpression, transformDecoratorExpression } from "../decorators"; -import { transformMemberExpressionOwnerName } from "./method"; - -export function createPropertyDecoratingExpression( - context: TransformationContext, - node: ts.PropertyDeclaration | ts.AccessorDeclaration, - className: lua.Identifier -): lua.Expression | undefined { - if (!node.decorators) return; - const propertyName = transformPropertyName(context, node.name); - const propertyOwnerTable = transformMemberExpressionOwnerName(node, className); - return createDecoratingExpression( - context, - node.kind, - node.decorators.map(d => transformDecoratorExpression(context, d)), - propertyOwnerTable, - propertyName - ); -} export function transformClassInstanceFields( context: TransformationContext, @@ -30,18 +12,22 @@ export function transformClassInstanceFields( const statements: lua.Statement[] = []; for (const f of instanceFields) { - // Get identifier - const fieldName = transformPropertyName(context, f.name); + const { precedingStatements, result: statement } = transformInPrecedingStatementScope(context, () => { + // Get identifier + const fieldName = transformPropertyName(context, f.name); + + const value = f.initializer ? context.transformExpression(f.initializer) : undefined; - const value = f.initializer ? context.transformExpression(f.initializer) : undefined; + // self[fieldName] + const selfIndex = lua.createTableIndexExpression(createSelfIdentifier(), fieldName); - // self[fieldName] - const selfIndex = lua.createTableIndexExpression(createSelfIdentifier(), fieldName); + // self[fieldName] = value + const assignClassField = lua.createAssignmentStatement(selfIndex, value, f); - // self[fieldName] = value - const assignClassField = lua.createAssignmentStatement(selfIndex, value, f); + return assignClassField; + }); - statements.push(assignClassField); + statements.push(...precedingStatements, statement); } return statements; @@ -56,5 +42,6 @@ export function transformStaticPropertyDeclaration( const fieldName = transformPropertyName(context, field.name); const value = context.transformExpression(field.initializer); const classField = lua.createTableIndexExpression(lua.cloneIdentifier(className), fieldName); + return lua.createAssignmentStatement(classField, value); } diff --git a/src/transformation/visitors/class/members/method.ts b/src/transformation/visitors/class/members/method.ts index c902ea8de..adfe2c352 100644 --- a/src/transformation/visitors/class/members/method.ts +++ b/src/transformation/visitors/class/members/method.ts @@ -4,10 +4,8 @@ import { TransformationContext } from "../../../context"; import { transformFunctionToExpression } from "../../function"; import { transformPropertyName } from "../../literal"; import { isStaticNode } from "../utils"; -import { createDecoratingExpression, transformDecoratorExpression } from "../decorators"; import { createPrototypeName } from "./constructor"; -import { transformLuaLibFunction, LuaLibFeature } from "../../../utils/lualib"; -import { isNonNull } from "../../../../utils"; +import { createClassMethodDecoratingExpression } from "../decorators"; export function transformMemberExpressionOwnerName( node: ts.PropertyDeclaration | ts.MethodDeclaration | ts.AccessorDeclaration, @@ -28,53 +26,45 @@ export function transformMethodDeclaration( context: TransformationContext, node: ts.MethodDeclaration, className: lua.Identifier -): lua.Statement | undefined { +): lua.Statement[] { // Don't transform methods without body (overload declarations) - if (!node.body) return; + if (!node.body) return []; const methodTable = transformMemberExpressionOwnerName(node, className); const methodName = transformMethodName(context, node); const [functionExpression] = transformFunctionToExpression(context, node); - return lua.createAssignmentStatement( - lua.createTableIndexExpression(methodTable, methodName), - functionExpression, - node - ); -} - -export function createMethodDecoratingExpression( - context: TransformationContext, - node: ts.MethodDeclaration, - className: lua.Identifier -): lua.Statement | undefined { - const methodTable = transformMemberExpressionOwnerName(node, className); - const methodName = transformMethodName(context, node); - - const parameterDecorators = node.parameters - .flatMap((parameter, index) => - parameter.decorators?.map(decorator => - transformLuaLibFunction( - context, - LuaLibFeature.DecorateParam, - node, - lua.createNumericLiteral(index), - transformDecoratorExpression(context, decorator) - ) - ) - ) - .filter(isNonNull); - - const methodDecorators = node.decorators?.map(d => transformDecoratorExpression(context, d)) ?? []; + const methodHasDecorators = (ts.getDecorators(node)?.length ?? 0) > 0; + const methodHasParameterDecorators = node.parameters.some(p => (ts.getDecorators(p)?.length ?? 0) > 0); // Legacy decorators - if (methodDecorators.length > 0 || parameterDecorators.length > 0) { - const decorateMethod = createDecoratingExpression( - context, - node.kind, - [...methodDecorators, ...parameterDecorators], - methodTable, - methodName - ); - return lua.createExpressionStatement(decorateMethod); + if (methodHasDecorators || methodHasParameterDecorators) { + if (context.options.experimentalDecorators) { + // Legacy decorator statement + return [ + lua.createAssignmentStatement( + lua.createTableIndexExpression(methodTable, methodName), + functionExpression + ), + lua.createExpressionStatement( + createClassMethodDecoratingExpression(context, node, functionExpression, className) + ), + ]; + } else { + return [ + lua.createAssignmentStatement( + lua.createTableIndexExpression(methodTable, methodName), + createClassMethodDecoratingExpression(context, node, functionExpression, className), + node + ), + ]; + } + } else { + return [ + lua.createAssignmentStatement( + lua.createTableIndexExpression(methodTable, methodName), + functionExpression, + node + ), + ]; } } diff --git a/src/transformation/visitors/class/new.ts b/src/transformation/visitors/class/new.ts index 721cc26e5..0c5733451 100644 --- a/src/transformation/visitors/class/new.ts +++ b/src/transformation/visitors/class/new.ts @@ -1,73 +1,48 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; -import { FunctionVisitor, TransformationContext } from "../../context"; +import { FunctionVisitor } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { annotationInvalidArgumentCount, annotationRemoved } from "../../utils/diagnostics"; -import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; -import { transformArguments } from "../call"; +import { annotationInvalidArgumentCount, unsupportedArrayWithLengthConstructor } from "../../utils/diagnostics"; +import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; +import { transformArguments, transformCallAndArguments } from "../call"; import { isTableNewCall } from "../language-extensions/table"; - -const builtinErrorTypeNames = new Set([ - "Error", - "ErrorConstructor", - "RangeError", - "RangeErrorConstructor", - "ReferenceError", - "ReferenceErrorConstructor", - "SyntaxError", - "SyntaxErrorConstructor", - "TypeError", - "TypeErrorConstructor", - "URIError", - "URIErrorConstructor", -]); - -// TODO: Do it in identifier? -export function checkForLuaLibType(context: TransformationContext, type: ts.Type): void { - if (!type.symbol) return; - - const name = context.checker.getFullyQualifiedName(type.symbol); - switch (name) { - case "Map": - importLuaLibFeature(context, LuaLibFeature.Map); - return; - case "Set": - importLuaLibFeature(context, LuaLibFeature.Set); - return; - case "WeakMap": - importLuaLibFeature(context, LuaLibFeature.WeakMap); - return; - case "WeakSet": - importLuaLibFeature(context, LuaLibFeature.WeakSet); - return; - } - - if (builtinErrorTypeNames.has(name)) { - importLuaLibFeature(context, LuaLibFeature.Error); - } -} +import { tryGetStandardLibrarySymbolOfType } from "../../builtins"; export const transformNewExpression: FunctionVisitor = (node, context) => { - const type = context.checker.getTypeAtLocation(node); - - const annotations = getTypeAnnotations(type); - - if (annotations.has(AnnotationKind.LuaTable)) { - context.diagnostics.push(annotationRemoved(node, AnnotationKind.LuaTable)); - } - if (isTableNewCall(context, node)) { return lua.createTableExpression(undefined, node); } - const name = context.transformExpression(node.expression); - const signature = context.checker.getResolvedSignature(node); - const params = node.arguments - ? transformArguments(context, node.arguments, signature) - : [lua.createBooleanLiteral(true)]; + const constructorType = context.checker.getTypeAtLocation(node.expression); + if (tryGetStandardLibrarySymbolOfType(context, constructorType)?.name === "ArrayConstructor") { + if (node.arguments === undefined || node.arguments.length === 0) { + // turn new Array<>() into a simple {} + return lua.createTableExpression([], node); + } else { + // More than one argument, check if items constructor + const signature = context.checker.getResolvedSignature(node); + const signatureDeclaration = signature?.getDeclaration(); + if ( + signatureDeclaration?.parameters.length === 1 && + signatureDeclaration.parameters[0].dotDotDotToken === undefined + ) { + context.diagnostics.push(unsupportedArrayWithLengthConstructor(node)); + return lua.createTableExpression([], node); + } else { + const callArguments = transformArguments(context, node.arguments, signature); + return lua.createTableExpression( + callArguments.map(e => lua.createTableFieldExpression(e)), + node + ); + } + } + } - checkForLuaLibType(context, type); + const signature = context.checker.getResolvedSignature(node); + const [name, params] = transformCallAndArguments(context, node.expression, node.arguments ?? [], signature); + const type = context.checker.getTypeAtLocation(node); + const annotations = getTypeAnnotations(type); const customConstructorAnnotation = annotations.get(AnnotationKind.CustomConstructor); if (customConstructorAnnotation) { if (customConstructorAnnotation.args.length === 1) { diff --git a/src/transformation/visitors/class/setup.ts b/src/transformation/visitors/class/setup.ts index 151e68a77..ab6eeea92 100644 --- a/src/transformation/visitors/class/setup.ts +++ b/src/transformation/visitors/class/setup.ts @@ -55,13 +55,13 @@ export function createClassSetup( result.push( lua.createAssignmentStatement( lua.createTableIndexExpression(lua.cloneIdentifier(localClassName), lua.createStringLiteral("name")), - getReflectionClassName(context, statement, className), + getReflectionClassName(statement, className), statement ) ); if (extendsType) { - const extendedNode = getExtendedNode(context, statement); + const extendedNode = getExtendedNode(statement); assert(extendedNode); result.push( lua.createExpressionStatement( @@ -80,7 +80,6 @@ export function createClassSetup( } export function getReflectionClassName( - context: TransformationContext, declaration: ts.ClassLikeDeclarationBase, className: lua.Identifier ): lua.Expression { @@ -92,7 +91,7 @@ export function getReflectionClassName( return lua.createStringLiteral("default"); } - if (getExtendedNode(context, declaration)) { + if (getExtendedNode(declaration)) { return lua.createTableIndexExpression(className, lua.createStringLiteral("name")); } diff --git a/src/transformation/visitors/class/utils.ts b/src/transformation/visitors/class/utils.ts index aea06680a..0cd4384bb 100644 --- a/src/transformation/visitors/class/utils.ts +++ b/src/transformation/visitors/class/utils.ts @@ -1,30 +1,22 @@ import * as ts from "typescript"; import { TransformationContext } from "../../context"; -import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { annotationRemoved } from "../../utils/diagnostics"; -export function isStaticNode(node: ts.Node): boolean { - return (node.modifiers ?? []).some(m => m.kind === ts.SyntaxKind.StaticKeyword); +export function isPrivateNode(node: ts.HasModifiers): boolean { + return node.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword) === true; +} + +export function isStaticNode(node: ts.HasModifiers): boolean { + return node.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword) === true; } export function getExtendsClause(node: ts.ClassLikeDeclarationBase): ts.HeritageClause | undefined { - return (node.heritageClauses ?? []).find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword); + return node.heritageClauses?.find(clause => clause.token === ts.SyntaxKind.ExtendsKeyword); } -export function getExtendedNode( - context: TransformationContext, - node: ts.ClassLikeDeclarationBase -): ts.ExpressionWithTypeArguments | undefined { +export function getExtendedNode(node: ts.ClassLikeDeclarationBase): ts.ExpressionWithTypeArguments | undefined { const extendsClause = getExtendsClause(node); if (!extendsClause) return; - const superType = context.checker.getTypeAtLocation(extendsClause.types[0]); - const annotations = getTypeAnnotations(superType); - - if (annotations.has(AnnotationKind.PureAbstract)) { - context.diagnostics.push(annotationRemoved(extendsClause, AnnotationKind.PureAbstract)); - } - return extendsClause.types[0]; } @@ -32,6 +24,6 @@ export function getExtendedType( context: TransformationContext, node: ts.ClassLikeDeclarationBase ): ts.Type | undefined { - const extendedNode = getExtendedNode(context, node); + const extendedNode = getExtendedNode(node); return extendedNode && context.checker.getTypeAtLocation(extendedNode); } diff --git a/src/transformation/visitors/conditional.ts b/src/transformation/visitors/conditional.ts index 2fab7494c..6285a488d 100644 --- a/src/transformation/visitors/conditional.ts +++ b/src/transformation/visitors/conditional.ts @@ -1,92 +1,118 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../utils/preceding-statements"; +import { performHoisting, ScopeType } from "../utils/scope"; import { transformBlockOrStatement } from "./block"; - -function canBeFalsy(context: TransformationContext, type: ts.Type): boolean { - const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true; - - const falsyFlags = - ts.TypeFlags.Boolean | - ts.TypeFlags.BooleanLiteral | - ts.TypeFlags.Undefined | - ts.TypeFlags.Null | - ts.TypeFlags.Never | - ts.TypeFlags.Void | - ts.TypeFlags.Any; - - if (type.flags & falsyFlags) { - return true; - } else if (!strictNullChecks && !type.isLiteral()) { - return true; - } else if (type.isUnion()) { - return type.types.some(subType => canBeFalsy(context, subType)); - } else { - return false; - } -} - -function wrapInFunctionCall(expression: lua.Expression): lua.FunctionExpression { - const returnStatement = lua.createReturnStatement([expression]); - - return lua.createFunctionExpression( - lua.createBlock([returnStatement]), - undefined, - undefined, - lua.FunctionExpressionFlags.Inline - ); -} +import { canBeFalsy } from "../utils/typescript"; +import { truthyOnlyConditionalValue } from "../utils/diagnostics"; +import { LuaTarget } from "../../CompilerOptions"; function transformProtectedConditionalExpression( context: TransformationContext, - expression: ts.ConditionalExpression -): lua.CallExpression { - const condition = context.transformExpression(expression.condition); - const val1 = context.transformExpression(expression.whenTrue); - const val2 = context.transformExpression(expression.whenFalse); + expression: ts.ConditionalExpression, + condition: WithPrecedingStatements, + whenTrue: WithPrecedingStatements, + whenFalse: WithPrecedingStatements +): lua.Expression { + const tempVar = context.createTempNameForNode(expression.condition); - const val1Function = wrapInFunctionCall(val1); - const val2Function = wrapInFunctionCall(val2); + const trueStatements = whenTrue.precedingStatements.concat( + lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenTrue.result, expression.whenTrue) + ); + + const falseStatements = whenFalse.precedingStatements.concat( + lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenFalse.result, expression.whenFalse) + ); - // (condition and (() => v1) or (() => v2))() - const conditionAnd = lua.createBinaryExpression(condition, val1Function, lua.SyntaxKind.AndOperator); - const orExpression = lua.createBinaryExpression(conditionAnd, val2Function, lua.SyntaxKind.OrOperator); - return lua.createCallExpression(orExpression, [], expression); + context.addPrecedingStatements([ + lua.createVariableDeclarationStatement(tempVar, undefined, expression.condition), + ...condition.precedingStatements, + lua.createIfStatement( + condition.result, + lua.createBlock(trueStatements, expression.whenTrue), + lua.createBlock(falseStatements, expression.whenFalse), + expression + ), + ]); + return lua.cloneIdentifier(tempVar); } export const transformConditionalExpression: FunctionVisitor = (expression, context) => { - if (canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue))) { - return transformProtectedConditionalExpression(context, expression); + if (context.luaTarget === LuaTarget.Luau) { + // Luau's ternary operator doesn't have these issues + return lua.createConditionalExpression( + context.transformExpression(expression.condition), + context.transformExpression(expression.whenTrue), + context.transformExpression(expression.whenFalse), + expression + ); } - const condition = context.transformExpression(expression.condition); - const val1 = context.transformExpression(expression.whenTrue); - const val2 = context.transformExpression(expression.whenFalse); + // Check if we need to add diagnostic about Lua truthiness + checkOnlyTruthyCondition(expression.condition, context); + + const condition = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression.condition) + ); + const whenTrue = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression.whenTrue) + ); + const whenFalse = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression.whenFalse) + ); + if ( + whenTrue.precedingStatements.length > 0 || + whenFalse.precedingStatements.length > 0 || + canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue)) + ) { + return transformProtectedConditionalExpression(context, expression, condition, whenTrue, whenFalse); + } // condition and v1 or v2 - const conditionAnd = lua.createBinaryExpression(condition, val1, lua.SyntaxKind.AndOperator); - return lua.createBinaryExpression(conditionAnd, val2, lua.SyntaxKind.OrOperator, expression); + context.addPrecedingStatements(condition.precedingStatements); + const conditionAnd = lua.createBinaryExpression(condition.result, whenTrue.result, lua.SyntaxKind.AndOperator); + return lua.createBinaryExpression(conditionAnd, whenFalse.result, lua.SyntaxKind.OrOperator, expression); }; export function transformIfStatement(statement: ts.IfStatement, context: TransformationContext): lua.IfStatement { - pushScope(context, ScopeType.Conditional); + context.pushScope(ScopeType.Conditional, statement); + + // Check if we need to add diagnostic about Lua truthiness + checkOnlyTruthyCondition(statement.expression, context); + const condition = context.transformExpression(statement.expression); const statements = performHoisting(context, transformBlockOrStatement(context, statement.thenStatement)); - popScope(context); + context.popScope(); const ifBlock = lua.createBlock(statements); if (statement.elseStatement) { if (ts.isIfStatement(statement.elseStatement)) { - const elseStatement = transformIfStatement(statement.elseStatement, context); - return lua.createIfStatement(condition, ifBlock, elseStatement); + const tsElseStatement = statement.elseStatement; + const { precedingStatements, result: elseStatement } = transformInPrecedingStatementScope(context, () => + transformIfStatement(tsElseStatement, context) + ); + // If else-if condition generates preceding statements, we can't use elseif, we have to break it down: + // if conditionA then + // ... + // else + // conditionB's preceding statements + // if conditionB then + // end + // end + if (precedingStatements.length > 0) { + const elseBlock = lua.createBlock([...precedingStatements, elseStatement]); + return lua.createIfStatement(condition, ifBlock, elseBlock); + } else { + return lua.createIfStatement(condition, ifBlock, elseStatement); + } } else { - pushScope(context, ScopeType.Conditional); + context.pushScope(ScopeType.Conditional, statement); const elseStatements = performHoisting( context, transformBlockOrStatement(context, statement.elseStatement) ); - popScope(context); + context.popScope(); const elseBlock = lua.createBlock(elseStatements); return lua.createIfStatement(condition, ifBlock, elseBlock); } @@ -94,3 +120,12 @@ export function transformIfStatement(statement: ts.IfStatement, context: Transfo return lua.createIfStatement(condition, ifBlock); } + +export function checkOnlyTruthyCondition(condition: ts.Expression, context: TransformationContext) { + if (context.options.strictNullChecks === false) return; // This check is not valid if everything could implicitly be nil + if (ts.isElementAccessExpression(condition)) return; // Array index could always implicitly return nil + + if (!canBeFalsy(context, context.checker.getTypeAtLocation(condition))) { + context.diagnostics.push(truthyOnlyConditionalValue(condition)); + } +} diff --git a/src/transformation/visitors/delete.ts b/src/transformation/visitors/delete.ts index 39bbf1d57..efa879c2e 100644 --- a/src/transformation/visitors/delete.ts +++ b/src/transformation/visitors/delete.ts @@ -5,8 +5,13 @@ import { transformLuaLibFunction, LuaLibFeature } from "../utils/lualib"; import { unsupportedProperty } from "../utils/diagnostics"; import { isArrayType, isNumberType } from "../utils/typescript"; import { addToNumericExpression } from "../utils/lua-ast"; +import { transformOptionalDeleteExpression } from "./optional-chaining"; export const transformDeleteExpression: FunctionVisitor = (node, context) => { + if (ts.isOptionalChain(node.expression)) { + return transformOptionalDeleteExpression(context, node, node.expression); + } + let ownerExpression: lua.Expression | undefined; let propertyExpression: lua.Expression | undefined; diff --git a/src/transformation/visitors/enum.ts b/src/transformation/visitors/enum.ts index 918e685f6..9de658a45 100644 --- a/src/transformation/visitors/enum.ts +++ b/src/transformation/visitors/enum.ts @@ -2,7 +2,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; -import { getSymbolExportScope } from "../utils/export"; +import { addExportToIdentifier, getSymbolExportScope } from "../utils/export"; import { createLocalOrExportedOrGlobalDeclaration } from "../utils/lua-ast"; import { isFirstDeclaration } from "../utils/typescript"; import { transformIdentifier } from "./identifier"; @@ -32,7 +32,7 @@ export const transformEnumDeclaration: FunctionVisitor = (no if (!membersOnly && isFirstDeclaration(context, node)) { const name = transformIdentifier(context, node.name); const table = lua.createBinaryExpression( - lua.cloneIdentifier(name), + addExportToIdentifier(context, name), lua.createTableExpression(), lua.SyntaxKind.OrOperator ); @@ -60,9 +60,7 @@ export const transformEnumDeclaration: FunctionVisitor = (no } } - if (!valueExpression) { - valueExpression = context.transformExpression(member.initializer); - } + valueExpression ??= context.transformExpression(member.initializer); } else { valueExpression = lua.createNilLiteral(); } diff --git a/src/transformation/visitors/errors.ts b/src/transformation/visitors/errors.ts index e05ed55f3..a070caac6 100644 --- a/src/transformation/visitors/errors.ts +++ b/src/transformation/visitors/errors.ts @@ -1,22 +1,175 @@ import * as ts from "typescript"; +import { LuaLibFeature, LuaTarget } from "../.."; import * as lua from "../../LuaAST"; -import { FunctionVisitor } from "../context"; -import { isInTupleReturnFunction } from "../utils/annotations"; +import { FunctionVisitor, TransformationContext } from "../context"; +import { unsupportedForTarget, unsupportedForTargetButOverrideAvailable } from "../utils/diagnostics"; import { createUnpackCall } from "../utils/lua-ast"; -import { findScope, ScopeType } from "../utils/scope"; +import { transformLuaLibFunction } from "../utils/lualib"; +import { findScope, LoopContinued, Scope, ScopeType } from "../utils/scope"; +import { isInAsyncFunction, isInGeneratorFunction } from "../utils/typescript"; +import { wrapInAsyncAwaiter } from "./async-await"; import { transformScopeBlock } from "./block"; import { transformIdentifier } from "./identifier"; import { isInMultiReturnFunction } from "./language-extensions/multi"; +import { createReturnStatement } from "./return"; + +const transformAsyncTry: FunctionVisitor = (statement, context) => { + const [tryBlock, tryScope] = transformScopeBlock(context, statement.tryBlock, ScopeType.Try); + + if ( + (context.options.luaTarget === LuaTarget.Lua50 || context.options.luaTarget === LuaTarget.Lua51) && + !context.options.lua51AllowTryCatchInAsyncAwait + ) { + context.diagnostics.push( + unsupportedForTargetButOverrideAvailable( + statement, + "try/catch inside async functions", + LuaTarget.Lua51, + "lua51AllowTryCatchInAsyncAwait" + ) + ); + return tryBlock.statements; + } + + // __TS__AsyncAwaiter() + const awaiter = wrapInAsyncAwaiter(context, tryBlock.statements, false); + const awaiterIdentifier = lua.createIdentifier("____try"); + const awaiterDefinition = lua.createVariableDeclarationStatement(awaiterIdentifier, awaiter); + + // Transform catch/finally and collect scope info before building the result + let catchScope: Scope | undefined; + const chainCalls: lua.Statement[] = []; + + if (statement.catchClause) { + // ____try = ____try.catch() + const [catchFunction, cScope] = transformCatchClause(context, statement.catchClause); + catchScope = cScope; + if (catchFunction.params) { + catchFunction.params.unshift(lua.createAnonymousIdentifier()); + } + + const catchBodyStatements = catchFunction.body ? catchFunction.body.statements : []; + const asyncWrappedCatch = wrapInAsyncAwaiter(context, [...catchBodyStatements], false); + catchFunction.body = lua.createBlock([lua.createReturnStatement([asyncWrappedCatch])]); + + const awaiterCatch = lua.createTableIndexExpression(awaiterIdentifier, lua.createStringLiteral("catch")); + const catchCall = lua.createCallExpression(awaiterCatch, [awaiterIdentifier, catchFunction]); + chainCalls.push(lua.createAssignmentStatement(lua.cloneIdentifier(awaiterIdentifier), catchCall)); + } + + if (statement.finallyBlock) { + // ____try = ____try.finally() + const finallyStatements = context.transformStatements(statement.finallyBlock.statements); + const asyncWrappedFinally = wrapInAsyncAwaiter(context, finallyStatements, false); + const finallyFunction = lua.createFunctionExpression( + lua.createBlock([lua.createReturnStatement([asyncWrappedFinally])]) + ); + + const awaiterFinally = lua.createTableIndexExpression(awaiterIdentifier, lua.createStringLiteral("finally")); + const finallyCall = lua.createCallExpression( + awaiterFinally, + [awaiterIdentifier, finallyFunction], + statement.finallyBlock + ); + chainCalls.push(lua.createAssignmentStatement(lua.cloneIdentifier(awaiterIdentifier), finallyCall)); + } + + // __TS__Await(____try) + const promiseAwait = transformLuaLibFunction(context, LuaLibFeature.Await, statement, awaiterIdentifier); + chainCalls.push(lua.createExpressionStatement(promiseAwait, statement)); + + const hasReturn = tryScope.asyncTryHasReturn ?? catchScope?.asyncTryHasReturn; + const hasBreak = tryScope.asyncTryHasBreak ?? catchScope?.asyncTryHasBreak; + const hasContinue = tryScope.asyncTryHasContinue ?? catchScope?.asyncTryHasContinue; + + // Build result in output order: flag declarations, awaiter, chain calls, post-checks + const result: lua.Statement[] = []; + + if (hasReturn || hasBreak || hasContinue !== undefined) { + const flagDecls: lua.Identifier[] = []; + if (hasReturn) { + flagDecls.push(lua.createIdentifier("____hasReturned")); + flagDecls.push(lua.createIdentifier("____returnValue")); + } + if (hasBreak) { + flagDecls.push(lua.createIdentifier("____hasBroken")); + } + if (hasContinue !== undefined) { + flagDecls.push(lua.createIdentifier("____hasContinued")); + } + result.push(lua.createVariableDeclarationStatement(flagDecls)); + } + + result.push(awaiterDefinition); + result.push(...chainCalls); + + if (hasReturn) { + result.push( + lua.createIfStatement( + lua.createIdentifier("____hasReturned"), + lua.createBlock([createReturnStatement(context, [lua.createIdentifier("____returnValue")], statement)]) + ) + ); + } + + if (hasBreak) { + result.push( + lua.createIfStatement(lua.createIdentifier("____hasBroken"), lua.createBlock([lua.createBreakStatement()])) + ); + } + + if (hasContinue !== undefined) { + const loopScope = findScope(context, ScopeType.Loop); + const label = `__continue${loopScope?.id ?? ""}`; + + const continueStatements: lua.Statement[] = []; + switch (hasContinue) { + case LoopContinued.WithGoto: + continueStatements.push(lua.createGotoStatement(label)); + break; + case LoopContinued.WithContinue: + continueStatements.push(lua.createContinueStatement()); + break; + case LoopContinued.WithRepeatBreak: + continueStatements.push( + lua.createAssignmentStatement(lua.createIdentifier(label), lua.createBooleanLiteral(true)) + ); + continueStatements.push(lua.createBreakStatement()); + break; + } + + result.push( + lua.createIfStatement(lua.createIdentifier("____hasContinued"), lua.createBlock(continueStatements)) + ); + } + + return result; +}; export const transformTryStatement: FunctionVisitor = (statement, context) => { + if (isInAsyncFunction(statement)) { + return transformAsyncTry(statement, context); + } + const [tryBlock, tryScope] = transformScopeBlock(context, statement.tryBlock, ScopeType.Try); + if ( + (context.options.luaTarget === LuaTarget.Lua50 || context.options.luaTarget === LuaTarget.Lua51) && + isInGeneratorFunction(statement) + ) { + context.diagnostics.push( + unsupportedForTarget(statement, "try/catch inside generator functions", LuaTarget.Lua51) + ); + return tryBlock.statements; + } + const tryResultIdentifier = lua.createIdentifier("____try"); const returnValueIdentifier = lua.createIdentifier("____returnValue"); + const rethrowIdentifier = lua.createIdentifier("____rethrow"); const result: lua.Statement[] = []; - let returnedIdentifier: lua.Identifier | undefined; + const returnedIdentifier = lua.createIdentifier("____hasReturned"); let returnCondition: lua.Expression | undefined; const pCall = lua.createIdentifier("pcall"); @@ -24,41 +177,55 @@ export const transformTryStatement: FunctionVisitor = (statemen if (statement.catchClause && statement.catchClause.block.statements.length > 0) { // try with catch - let [catchBlock, catchScope] = transformScopeBlock(context, statement.catchClause.block, ScopeType.Catch); - if (statement.catchClause.variableDeclaration) { - // Replace ____returned with catch variable - returnedIdentifier = transformIdentifier( - context, - statement.catchClause.variableDeclaration.name as ts.Identifier - ); - } else if (tryScope.functionReturned || catchScope.functionReturned) { - returnedIdentifier = lua.createIdentifier("____returned"); - } + const [catchFunction, catchScope] = transformCatchClause(context, statement.catchClause); + const catchIdentifier = lua.createIdentifier("____catch"); + result.push(lua.createVariableDeclarationStatement(catchIdentifier, catchFunction)); + + const hasReturn = tryScope.functionReturned ?? catchScope.functionReturned; const tryReturnIdentifiers = [tryResultIdentifier]; // ____try - if (returnedIdentifier) { - tryReturnIdentifiers.push(returnedIdentifier); // ____returned or catch variable - if (tryScope.functionReturned || catchScope.functionReturned) { + if (hasReturn || statement.catchClause.variableDeclaration) { + tryReturnIdentifiers.push(returnedIdentifier); // ____returned + if (hasReturn) { tryReturnIdentifiers.push(returnValueIdentifier); // ____returnValue returnCondition = lua.cloneIdentifier(returnedIdentifier); } } result.push(lua.createVariableDeclarationStatement(tryReturnIdentifiers, tryCall)); - - if ((tryScope.functionReturned || catchScope.functionReturned) && returnedIdentifier) { - // Wrap catch in function if try or catch has return - const catchCall = lua.createCallExpression(lua.createFunctionExpression(catchBlock), []); - const catchAssign = lua.createAssignmentStatement( - [lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], - catchCall - ); - catchBlock = lua.createBlock([catchAssign]); + if (statement.finallyBlock) { + result.push(lua.createVariableDeclarationStatement(rethrowIdentifier)); } + + const catchCall = lua.createCallExpression( + catchIdentifier, + statement.catchClause.variableDeclaration ? [lua.cloneIdentifier(returnedIdentifier)] : [] + ); + const catchCallStatement = hasReturn + ? lua.createAssignmentStatement( + [lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], + catchCall + ) + : lua.createExpressionStatement(catchCall); + + const catchCallFunction = lua.createFunctionExpression(lua.createBlock([catchCallStatement])); + + const tryCatchCall = lua.createCallExpression(pCall, [catchCallFunction]); + + const tryCatchCallStatement = lua.createAssignmentStatement( + [lua.cloneIdentifier(tryResultIdentifier), lua.cloneIdentifier(rethrowIdentifier)], + tryCatchCall + ); + const notTryCondition = lua.createUnaryExpression(tryResultIdentifier, lua.SyntaxKind.NotOperator); - result.push(lua.createIfStatement(notTryCondition, catchBlock)); + result.push( + lua.createIfStatement( + notTryCondition, + lua.createBlock(statement.finallyBlock ? [tryCatchCallStatement] : [catchCallStatement]) + ) + ); } else if (tryScope.functionReturned) { // try with return, but no catch - returnedIdentifier = lua.createIdentifier("____returned"); + // returnedIdentifier = lua.createIdentifier("____returned"); const returnedVariables = [tryResultIdentifier, returnedIdentifier, returnValueIdentifier]; result.push(lua.createVariableDeclarationStatement(returnedVariables, tryCall)); @@ -68,6 +235,10 @@ export const transformTryStatement: FunctionVisitor = (statemen returnedIdentifier, lua.SyntaxKind.AndOperator ); + } else if (statement.finallyBlock) { + // try without catch, but with finally — need to capture error for re-throw + const errorIdentifier = lua.createIdentifier("____error"); + result.push(lua.createVariableDeclarationStatement([tryResultIdentifier, errorIdentifier], tryCall)); } else { // try without return or catch result.push(lua.createExpressionStatement(tryCall)); @@ -77,25 +248,45 @@ export const transformTryStatement: FunctionVisitor = (statemen result.push(...context.transformStatements(statement.finallyBlock)); } + // Re-throw error if try had a finally. + // On pcall failure the error is the second return value, which lands in + // ____hasReturned (when functionReturned) or ____error (otherwise). + if (statement.finallyBlock) { + const notTryCondition = lua.createUnaryExpression( + lua.cloneIdentifier(tryResultIdentifier), + lua.SyntaxKind.NotOperator + ); + + if (!statement.catchClause) { + const errorIdentifier = tryScope.functionReturned + ? lua.cloneIdentifier(returnedIdentifier) + : lua.createIdentifier("____error"); + const rethrow = lua.createExpressionStatement( + lua.createCallExpression(lua.createIdentifier("error"), [errorIdentifier, lua.createNumericLiteral(0)]) + ); + result.push(lua.createIfStatement(notTryCondition, lua.createBlock([rethrow]))); + } else if (statement.catchClause.block.statements.length > 0) { + // Re-throw is possible only from non-empty blocks. + const rethrow = lua.createExpressionStatement( + lua.createCallExpression(lua.createIdentifier("error"), [ + rethrowIdentifier, + lua.createNumericLiteral(0), + ]) + ); + result.push(lua.createIfStatement(notTryCondition, lua.createBlock([rethrow]))); + } + } + if (returnCondition && returnedIdentifier) { - // With catch clause: - // if ____returned then return ____returnValue end - // No catch clause: - // if ____try and ____returned then return ____returnValue end const returnValues: lua.Expression[] = []; - const parentTryCatch = findScope(context, ScopeType.Function | ScopeType.Try | ScopeType.Catch); - if (parentTryCatch && parentTryCatch.type !== ScopeType.Function) { - // Nested try/catch needs to prefix a 'true' return value - returnValues.push(lua.createBooleanLiteral(true)); - } - if (isInTupleReturnFunction(context, statement) || isInMultiReturnFunction(context, statement)) { + if (isInMultiReturnFunction(context, statement)) { returnValues.push(createUnpackCall(context, lua.cloneIdentifier(returnValueIdentifier))); } else { returnValues.push(lua.cloneIdentifier(returnValueIdentifier)); } - const returnStatement = lua.createReturnStatement(returnValues); + const returnStatement = createReturnStatement(context, returnValues, statement); const ifReturnedStatement = lua.createIfStatement(returnCondition, lua.createBlock([returnStatement])); result.push(ifReturnedStatement); } @@ -116,3 +307,20 @@ export const transformThrowStatement: FunctionVisitor = (stat statement ); }; + +function transformCatchClause( + context: TransformationContext, + catchClause: ts.CatchClause +): [lua.FunctionExpression, Scope] { + const [catchBlock, catchScope] = transformScopeBlock(context, catchClause.block, ScopeType.Catch); + + const catchParameter = catchClause.variableDeclaration + ? transformIdentifier(context, catchClause.variableDeclaration.name as ts.Identifier) + : undefined; + const catchFunction = lua.createFunctionExpression( + catchBlock, + catchParameter ? [lua.cloneIdentifier(catchParameter)] : [] + ); + + return [catchFunction, catchScope]; +} diff --git a/src/transformation/visitors/expression-list.ts b/src/transformation/visitors/expression-list.ts new file mode 100644 index 000000000..617d09d4a --- /dev/null +++ b/src/transformation/visitors/expression-list.ts @@ -0,0 +1,197 @@ +import assert = require("assert"); +import * as ts from "typescript"; +import * as lua from "../../LuaAST"; +import { TransformationContext, tempSymbolId } from "../context"; +import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; +import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { isConstIdentifier } from "../utils/typescript"; +import { isOptionalContinuation } from "./optional-chaining"; + +export function shouldMoveToTemp(context: TransformationContext, expression: lua.Expression, tsOriginal?: ts.Node) { + return ( + !lua.isLiteral(expression) && + !(lua.isIdentifier(expression) && expression.symbolId === tempSymbolId) && // Treat generated temps as consts + !( + tsOriginal && + (isConstIdentifier(context, tsOriginal) || + isOptionalContinuation(tsOriginal) || + tsOriginal.kind === ts.SyntaxKind.ThisKeyword) + ) + ); +} + +// Cache an expression in a preceding statement and return the temp identifier +export function moveToPrecedingTemp( + context: TransformationContext, + expression: lua.Expression, + tsOriginal?: ts.Node +): lua.Expression { + if (!shouldMoveToTemp(context, expression, tsOriginal)) { + return expression; + } + const tempIdentifier = context.createTempNameForLuaExpression(expression); + const tempDeclaration = lua.createVariableDeclarationStatement(tempIdentifier, expression, tsOriginal); + context.addPrecedingStatements(tempDeclaration); + return lua.cloneIdentifier(tempIdentifier, tsOriginal); +} + +function transformExpressions( + context: TransformationContext, + expressions: readonly ts.Expression[] +): { + transformedExpressions: lua.Expression[]; + precedingStatements: lua.Statement[][]; + lastPrecedingStatementsIndex: number; +} { + const precedingStatements: lua.Statement[][] = []; + const transformedExpressions: lua.Expression[] = []; + let lastPrecedingStatementsIndex = -1; + for (let i = 0; i < expressions.length; ++i) { + const { precedingStatements: expressionPrecedingStatements, result: expression } = + transformInPrecedingStatementScope(context, () => context.transformExpression(expressions[i])); + transformedExpressions.push(expression); + if (expressionPrecedingStatements.length > 0) { + lastPrecedingStatementsIndex = i; + } + precedingStatements.push(expressionPrecedingStatements); + } + return { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex }; +} + +function transformExpressionsUsingTemps( + context: TransformationContext, + expressions: readonly ts.Expression[], + transformedExpressions: lua.Expression[], + precedingStatements: lua.Statement[][], + lastPrecedingStatementsIndex: number +) { + for (let i = 0; i < transformedExpressions.length; ++i) { + context.addPrecedingStatements(precedingStatements[i]); + if (i < lastPrecedingStatementsIndex) { + transformedExpressions[i] = moveToPrecedingTemp(context, transformedExpressions[i], expressions[i]); + } + } + return transformedExpressions; +} + +function pushToSparseArray( + context: TransformationContext, + arrayIdentifier: lua.Identifier | undefined, + expressions: lua.Expression[] +) { + if (!arrayIdentifier) { + arrayIdentifier = lua.createIdentifier(context.createTempName("array")); + const libCall = transformLuaLibFunction(context, LuaLibFeature.SparseArrayNew, undefined, ...expressions); + const declaration = lua.createVariableDeclarationStatement(arrayIdentifier, libCall); + context.addPrecedingStatements(declaration); + } else { + const libCall = transformLuaLibFunction( + context, + LuaLibFeature.SparseArrayPush, + undefined, + arrayIdentifier, + ...expressions + ); + context.addPrecedingStatements(lua.createExpressionStatement(libCall)); + } + return arrayIdentifier; +} + +function transformExpressionsUsingSparseArray( + context: TransformationContext, + expressions: readonly ts.Expression[], + transformedExpressions: lua.Expression[], + precedingStatements: lua.Statement[][] +) { + let arrayIdentifier: lua.Identifier | undefined; + + let expressionBatch: lua.Expression[] = []; + for (let i = 0; i < expressions.length; ++i) { + // Expressions with preceding statements should always be at the start of a batch + if (precedingStatements[i].length > 0 && expressionBatch.length > 0) { + arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch); + expressionBatch = []; + } + + context.addPrecedingStatements(precedingStatements[i]); + expressionBatch.push(transformedExpressions[i]); + + // Spread expressions should always be at the end of a batch + if (ts.isSpreadElement(expressions[i])) { + arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch); + expressionBatch = []; + } + } + + if (expressionBatch.length > 0) { + arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch); + } + + assert(arrayIdentifier); + return [transformLuaLibFunction(context, LuaLibFeature.SparseArraySpread, undefined, arrayIdentifier)]; +} + +function countNeededTemps( + context: TransformationContext, + expressions: readonly ts.Expression[], + transformedExpressions: lua.Expression[], + lastPrecedingStatementsIndex: number +) { + if (lastPrecedingStatementsIndex < 0) { + return 0; + } + return transformedExpressions + .slice(0, lastPrecedingStatementsIndex) + .filter((e, i) => shouldMoveToTemp(context, e, expressions[i])).length; +} + +// Transforms a list of expressions while flattening spreads and maintaining execution order +export function transformExpressionList( + context: TransformationContext, + expressions: readonly ts.Expression[] +): lua.Expression[] { + const { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex } = transformExpressions( + context, + expressions + ); + + // If more than this number of temps are required to preserve execution order, we'll fall back to using the + // sparse array lib functions instead to prevent excessive locals. + const maxTemps = 2; + + // Use sparse array lib if there are spreads before the last expression + // or if too many temps are needed to preserve order + const lastSpread = expressions.findIndex(e => ts.isSpreadElement(e)); + if ( + (lastSpread >= 0 && lastSpread < expressions.length - 1) || + countNeededTemps(context, expressions, transformedExpressions, lastPrecedingStatementsIndex) > maxTemps + ) { + return transformExpressionsUsingSparseArray(context, expressions, transformedExpressions, precedingStatements); + } else { + return transformExpressionsUsingTemps( + context, + expressions, + transformedExpressions, + precedingStatements, + lastPrecedingStatementsIndex + ); + } +} + +// Transforms a series of expressions while maintaining execution order +export function transformOrderedExpressions( + context: TransformationContext, + expressions: readonly ts.Expression[] +): lua.Expression[] { + const { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex } = transformExpressions( + context, + expressions + ); + return transformExpressionsUsingTemps( + context, + expressions, + transformedExpressions, + precedingStatements, + lastPrecedingStatementsIndex + ); +} diff --git a/src/transformation/visitors/expression-statement.ts b/src/transformation/visitors/expression-statement.ts index 228307f25..a247fd29b 100644 --- a/src/transformation/visitors/expression-statement.ts +++ b/src/transformation/visitors/expression-statement.ts @@ -1,26 +1,10 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; -import { FunctionVisitor } from "../context"; +import { FunctionVisitor, tempSymbolId } from "../context"; import { transformBinaryExpressionStatement } from "./binary-expression"; -import { - isTableDeleteCall, - isTableSetCall, - transformTableDeleteExpression, - transformTableSetExpression, -} from "./language-extensions/table"; import { transformUnaryExpressionStatement } from "./unary-expression"; export const transformExpressionStatement: FunctionVisitor = (node, context) => { - const expression = node.expression; - - if (ts.isCallExpression(expression) && isTableDeleteCall(context, expression)) { - return transformTableDeleteExpression(context, expression); - } - - if (ts.isCallExpression(expression) && isTableSetCall(context, expression)) { - return transformTableSetExpression(context, expression); - } - const unaryExpressionResult = transformUnaryExpressionStatement(context, node); if (unaryExpressionResult) { return unaryExpressionResult; @@ -31,9 +15,22 @@ export const transformExpressionStatement: FunctionVisitor context.transformExpression(value) + ); + if (!lua.isNilLiteral(parameterValue)) { + statements.push(lua.createAssignmentStatement(parameterName, parameterValue)); + } + if (statements.length === 0) return undefined; const nilCondition = lua.createBinaryExpression( parameterName, @@ -32,7 +43,7 @@ function transformParameterDefaultValueDeclaration( lua.SyntaxKind.EqualityOperator ); - const ifBlock = lua.createBlock([assignment]); + const ifBlock = lua.createBlock(statements, tsOriginal); return lua.createIfStatement(nilCondition, ifBlock, undefined, tsOriginal); } @@ -48,10 +59,48 @@ function isRestParameterReferenced(identifier: lua.Identifier, scope: Scope): bo return references !== undefined && references.length > 0; } +export function createCallableTable(functionExpression: lua.Expression): lua.Expression { + // __call metamethod receives the table as the first argument, so we need to add a dummy parameter + if (lua.isFunctionExpression(functionExpression)) { + functionExpression.params?.unshift(lua.createAnonymousIdentifier()); + } else { + // functionExpression may have been replaced (lib functions, etc...), + // so we create a forwarding function to eat the extra argument + functionExpression = lua.createFunctionExpression( + lua.createBlock([ + lua.createReturnStatement([lua.createCallExpression(functionExpression, [lua.createDotsLiteral()])]), + ]), + [lua.createAnonymousIdentifier()], + lua.createDotsLiteral(), + lua.NodeFlags.Inline + ); + } + return lua.createCallExpression(lua.createIdentifier("setmetatable"), [ + lua.createTableExpression(), + lua.createTableExpression([ + lua.createTableFieldExpression(functionExpression, lua.createStringLiteral("__call")), + ]), + ]); +} + +export function isFunctionTypeWithProperties(context: TransformationContext, functionType: ts.Type): boolean { + if (functionType.isUnion()) { + return functionType.types.some(t => isFunctionTypeWithProperties(context, t)); + } else { + return ( + isFunctionType(functionType) && + functionType.getProperties().length > 0 && + getExtensionKindForType(context, functionType) === undefined // ignore TSTL extension functions like $range + ); + } +} + export function transformFunctionBodyContent(context: TransformationContext, body: ts.ConciseBody): lua.Statement[] { if (!ts.isBlock(body)) { - const returnStatement = transformExpressionBodyToReturnStatement(context, body); - return [returnStatement]; + const { precedingStatements, result: returnStatement } = transformInPrecedingStatementScope(context, () => + transformExpressionBodyToReturnStatement(context, body) + ); + return [...precedingStatements, returnStatement]; } const bodyStatements = performHoisting(context, context.transformStatements(body.statements)); @@ -64,7 +113,7 @@ export function transformFunctionBodyHeader( parameters: ts.NodeArray, spreadIdentifier?: lua.Identifier ): lua.Statement[] { - const headerStatements = []; + const headerStatements: lua.Statement[] = []; // Add default parameters and object binding patterns const bindingPatternDeclarations: lua.Statement[] = []; @@ -74,28 +123,35 @@ export function transformFunctionBodyHeader( const identifier = lua.createIdentifier(`____bindingPattern${bindPatternIndex++}`); if (declaration.initializer !== undefined) { // Default binding parameter - headerStatements.push( - transformParameterDefaultValueDeclaration(context, identifier, declaration.initializer) + const initializer = transformParameterDefaultValueDeclaration( + context, + identifier, + declaration.initializer ); + if (initializer) headerStatements.push(initializer); } // Binding pattern - bindingPatternDeclarations.push(...transformBindingPattern(context, declaration.name, identifier)); + const name = declaration.name; + const { precedingStatements, result: bindings } = transformInPrecedingStatementScope(context, () => + transformBindingPattern(context, name, identifier) + ); + bindingPatternDeclarations.push(...precedingStatements, ...bindings); } else if (declaration.initializer !== undefined) { // Default parameter - headerStatements.push( - transformParameterDefaultValueDeclaration( - context, - transformIdentifier(context, declaration.name), - declaration.initializer - ) + const initializer = transformParameterDefaultValueDeclaration( + context, + transformIdentifier(context, declaration.name), + declaration.initializer ); + if (initializer) headerStatements.push(initializer); } } // Push spread operator here if (spreadIdentifier && isRestParameterReferenced(spreadIdentifier, bodyScope)) { - const spreadTable = wrapInTable(lua.createDotsLiteral()); + const spreadTable = + context.luaTarget === LuaTarget.Lua50 ? lua.createArgLiteral() : wrapInTable(lua.createDotsLiteral()); headerStatements.push(lua.createVariableDeclarationStatement(spreadIdentifier, spreadTable)); } @@ -109,14 +165,16 @@ export function transformFunctionBody( context: TransformationContext, parameters: ts.NodeArray, body: ts.ConciseBody, - spreadIdentifier?: lua.Identifier, - node?: ts.FunctionLikeDeclaration + node: ts.FunctionLikeDeclaration, + spreadIdentifier?: lua.Identifier ): [lua.Statement[], Scope] { - const scope = pushScope(context, ScopeType.Function); - scope.node = node; - const bodyStatements = transformFunctionBodyContent(context, body); + const scope = context.pushScope(ScopeType.Function, node); + let bodyStatements = transformFunctionBodyContent(context, body); + if (node && isAsyncFunction(node)) { + bodyStatements = [lua.createReturnStatement([wrapInAsyncAwaiter(context, bodyStatements)])]; + } const headerStatements = transformFunctionBodyHeader(context, scope, parameters, spreadIdentifier); - popScope(context); + context.popScope(); return [[...headerStatements, ...bodyStatements], scope]; } @@ -137,7 +195,7 @@ export function transformParameters( // Only push parameter name to paramName array if it isn't a spread parameter for (const param of parameters) { - if (ts.isIdentifier(param.name) && param.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword) { + if (ts.isIdentifier(param.name) && ts.identifierToKeywordKind(param.name) === ts.SyntaxKind.ThisKeyword) { continue; } @@ -167,9 +225,21 @@ export function transformFunctionToExpression( ): [lua.Expression, Scope] { assert(node.body); + if (node.asteriskToken && isAsyncFunction(node)) { + context.diagnostics.push(unsupportedAsyncGenerator(node)); + } + const type = context.checker.getTypeAtLocation(node); let functionContext: lua.Identifier | undefined; - if (getFunctionContextType(context, type) !== ContextType.Void) { + + const firstParam = node.parameters[0]; + const hasThisVoidParameter = + firstParam && + ts.isIdentifier(firstParam.name) && + ts.identifierToKeywordKind(firstParam.name) === ts.SyntaxKind.ThisKeyword && + firstParam.type?.kind === ts.SyntaxKind.VoidKeyword; + + if (!hasThisVoidParameter && getFunctionContextType(context, type) !== ContextType.Void) { if (ts.isArrowFunction(node)) { // dummy context for arrow functions with parameters if (node.parameters.length > 0) { @@ -181,10 +251,10 @@ export function transformFunctionToExpression( } } - let flags = lua.FunctionExpressionFlags.None; - if (!ts.isBlock(node.body)) flags |= lua.FunctionExpressionFlags.Inline; + let flags = lua.NodeFlags.None; + if (!ts.isBlock(node.body)) flags |= lua.NodeFlags.Inline; if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) { - flags |= lua.FunctionExpressionFlags.Declaration; + flags |= lua.NodeFlags.Declaration; } const [paramNames, dotsLiteral, spreadIdentifier] = transformParameters(context, node.parameters, functionContext); @@ -192,9 +262,10 @@ export function transformFunctionToExpression( context, node.parameters, node.body, - spreadIdentifier, - node + node, + spreadIdentifier ); + const functionExpression = lua.createFunctionExpression( lua.createBlock(transformedBody), paramNames, @@ -222,8 +293,9 @@ export function transformFunctionLikeDeclaration( const [functionExpression, functionScope] = transformFunctionToExpression(context, node); + const isNamedFunctionExpression = ts.isFunctionExpression(node) && node.name; // Handle named function expressions which reference themselves - if (ts.isFunctionExpression(node) && node.name && functionScope.referencedSymbols) { + if (isNamedFunctionExpression && functionScope.referencedSymbols) { const symbol = context.checker.getSymbolAtLocation(node.name); if (symbol) { // TODO: Not using symbol ids because of https://github.com/microsoft/TypeScript/issues/37131 @@ -231,22 +303,27 @@ export function transformFunctionLikeDeclaration( nodes.some(n => context.checker.getSymbolAtLocation(n)?.valueDeclaration === symbol.valueDeclaration) ); - // Only wrap if the name is actually referenced inside the function + // Only handle if the name is actually referenced inside the function if (isReferenced) { const nameIdentifier = transformIdentifier(context, node.name); - // We cannot use transformToImmediatelyInvokedFunctionExpression() here because we need to transpile - // the function first to determine if it's self-referencing. Fortunately, this does not cause issues - // with var-arg optimization because the IIFE is just wrapping another function which will already push - // another scope. - return createImmediatelyInvokedFunctionExpression( - [lua.createVariableDeclarationStatement(nameIdentifier, functionExpression)], - lua.cloneIdentifier(nameIdentifier) - ); + if (isFunctionTypeWithProperties(context, context.checker.getTypeAtLocation(node))) { + context.addPrecedingStatements([ + lua.createVariableDeclarationStatement(nameIdentifier), + lua.createAssignmentStatement(nameIdentifier, createCallableTable(functionExpression)), + ]); + } else { + context.addPrecedingStatements( + lua.createVariableDeclarationStatement(nameIdentifier, functionExpression) + ); + } + return lua.cloneIdentifier(nameIdentifier); } } } - return functionExpression; + return isNamedFunctionExpression && isFunctionTypeWithProperties(context, context.checker.getTypeAtLocation(node)) + ? createCallableTable(functionExpression) + : functionExpression; } export const transformFunctionDeclaration: FunctionVisitor = (node, context) => { @@ -270,15 +347,19 @@ export const transformFunctionDeclaration: FunctionVisitor = (expression, context) => { diff --git a/src/transformation/visitors/identifier.ts b/src/transformation/visitors/identifier.ts index 17706848c..3b2e016e4 100644 --- a/src/transformation/visitors/identifier.ts +++ b/src/transformation/visitors/identifier.ts @@ -1,80 +1,134 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; -import { transformBuiltinIdentifierExpression } from "../builtins"; -import { FunctionVisitor, TransformationContext } from "../context"; -import { AnnotationKind, isForRangeType } from "../utils/annotations"; -import { - invalidMultiFunctionUse, - invalidOperatorMappingUse, - invalidRangeUse, - invalidVarargUse, - invalidTableExtensionUse, - annotationRemoved, -} from "../utils/diagnostics"; +import { transformBuiltinIdentifierExpression, checkForLuaLibType } from "../builtins"; +import { isPromiseClass, createPromiseIdentifier } from "../builtins/promise"; +import { FunctionVisitor, tempSymbolId, TransformationContext } from "../context"; +import { invalidCallExtensionUse } from "../utils/diagnostics"; import { createExportedIdentifier, getSymbolExportScope } from "../utils/export"; import { createSafeName, hasUnsafeIdentifierName } from "../utils/safe-names"; import { getIdentifierSymbolId } from "../utils/symbols"; -import { isMultiFunctionNode } from "./language-extensions/multi"; -import { isOperatorMapping } from "./language-extensions/operators"; -import { isRangeFunctionNode } from "./language-extensions/range"; -import { isTableExtensionIdentifier } from "./language-extensions/table"; -import { isVarargConstantNode } from "./language-extensions/vararg"; +import { getOptionalContinuationData, isOptionalContinuation } from "./optional-chaining"; +import { isStandardLibraryType } from "../utils/typescript"; +import { getExtensionKindForNode, getExtensionKindForSymbol } from "../utils/language-extensions"; +import { callExtensions } from "./language-extensions/call-extension"; +import { isIdentifierExtensionValue, reportInvalidExtensionValue } from "./language-extensions/identifier"; +import { Annotation, AnnotationKind, getNodeAnnotations } from "../utils/annotations"; export function transformIdentifier(context: TransformationContext, identifier: ts.Identifier): lua.Identifier { - if (isMultiFunctionNode(context, identifier)) { - context.diagnostics.push(invalidMultiFunctionUse(identifier)); - return lua.createAnonymousIdentifier(identifier); - } + return transformNonValueIdentifier(context, identifier, context.checker.getSymbolAtLocation(identifier)); +} - if (isOperatorMapping(context, identifier)) { - context.diagnostics.push(invalidOperatorMappingUse(identifier)); - } +export function getCustomNameFromSymbol(context: TransformationContext, symbol?: ts.Symbol): undefined | string { + let retVal: undefined | string; + + if (symbol) { + const declarations = symbol.getDeclarations(); + if (declarations) { + let customNameAnnotation: undefined | Annotation = undefined; + for (const declaration of declarations) { + const nodeAnnotations = getNodeAnnotations(declaration); + const foundAnnotation = nodeAnnotations.get(AnnotationKind.CustomName); + + if (foundAnnotation) { + customNameAnnotation = foundAnnotation; + break; + } + + // If the symbol is an imported value, check the original declaration + // beware of declaration.propertyName, this is the import name alias and should not be renamed! + if (ts.isImportSpecifier(declaration) && !declaration.propertyName) { + const importedType = context.checker.getTypeAtLocation(declaration); + if (importedType.symbol) { + const importedCustomName = getCustomNameFromSymbol(context, importedType.symbol); + if (importedCustomName) { + return importedCustomName; + } + } + } + } - if (isTableExtensionIdentifier(context, identifier)) { - context.diagnostics.push(invalidTableExtensionUse(identifier)); + if (customNameAnnotation) { + retVal = customNameAnnotation.args[0]; + } + } } - if (isRangeFunctionNode(context, identifier)) { - context.diagnostics.push(invalidRangeUse(identifier)); - return lua.createAnonymousIdentifier(identifier); + return retVal; +} + +function transformNonValueIdentifier( + context: TransformationContext, + identifier: ts.Identifier, + symbol: ts.Symbol | undefined +) { + if (isOptionalContinuation(identifier)) { + const result = lua.createIdentifier(identifier.text, undefined, tempSymbolId); + getOptionalContinuationData(identifier)!.usedIdentifiers.push(result); + return result; } - if (isVarargConstantNode(context, identifier)) { - context.diagnostics.push(invalidVarargUse(identifier)); - return lua.createAnonymousIdentifier(identifier); + const extensionKind = symbol + ? getExtensionKindForSymbol(context, symbol) + : getExtensionKindForNode(context, identifier); + + if (extensionKind) { + if (callExtensions.has(extensionKind)) { + // Avoid putting duplicate diagnostic on the name of a variable declaration, due to the inferred type + if (!(ts.isVariableDeclaration(identifier.parent) && identifier.parent.name === identifier)) { + context.diagnostics.push(invalidCallExtensionUse(identifier)); + } + // fall through + } else if (isIdentifierExtensionValue(symbol, extensionKind)) { + reportInvalidExtensionValue(context, identifier, extensionKind); + return lua.createAnonymousIdentifier(identifier); + } } - if (isForRangeType(context, identifier)) { - context.diagnostics.push(annotationRemoved(identifier, AnnotationKind.ForRange)); + const type = context.checker.getTypeAtLocation(identifier); + if (isStandardLibraryType(context, type, undefined)) { + checkForLuaLibType(context, type); + if (isPromiseClass(context, identifier)) { + return createPromiseIdentifier(identifier); + } } - const text = hasUnsafeIdentifierName(context, identifier) ? createSafeName(identifier.text) : identifier.text; + let text = hasUnsafeIdentifierName(context, identifier, symbol) ? createSafeName(identifier.text) : identifier.text; - const symbolId = getIdentifierSymbolId(context, identifier); + const customName = getCustomNameFromSymbol(context, symbol); + if (customName) text = customName; + + const symbolId = getIdentifierSymbolId(context, identifier, symbol); return lua.createIdentifier(text, identifier, symbolId, identifier.text); } -export const transformIdentifierExpression: FunctionVisitor = (node, context) => { - const symbol = context.checker.getSymbolAtLocation(node); +export function transformIdentifierWithSymbol( + context: TransformationContext, + node: ts.Identifier, + symbol: ts.Symbol | undefined +): lua.Expression { if (symbol) { const exportScope = getSymbolExportScope(context, symbol); if (exportScope) { const name = symbol.name; - const text = hasUnsafeIdentifierName(context, node) ? createSafeName(name) : name; - const symbolId = getIdentifierSymbolId(context, node); + const text = hasUnsafeIdentifierName(context, node, symbol) ? createSafeName(name) : name; + const symbolId = getIdentifierSymbolId(context, node, symbol); const identifier = lua.createIdentifier(text, node, symbolId, name); return createExportedIdentifier(context, identifier, exportScope); } } - - if (node.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) { - return lua.createNilLiteral(); - } - - const builtinResult = transformBuiltinIdentifierExpression(context, node); + const builtinResult = transformBuiltinIdentifierExpression(context, node, symbol); if (builtinResult) { return builtinResult; } - return transformIdentifier(context, node); + return transformNonValueIdentifier(context, node, symbol); +} + +export const transformIdentifierExpression: FunctionVisitor = (node, context) => { + if (ts.identifierToKeywordKind(node) === ts.SyntaxKind.UndefinedKeyword) { + return lua.createNilLiteral(node); + } + + const symbol = context.checker.getSymbolAtLocation(node); + return transformIdentifierWithSymbol(context, node, symbol); }; diff --git a/src/transformation/visitors/index.ts b/src/transformation/visitors/index.ts index b9983ae31..466f5ed35 100644 --- a/src/transformation/visitors/index.ts +++ b/src/transformation/visitors/index.ts @@ -40,6 +40,8 @@ import { transformTypeOfExpression } from "./typeof"; import { typescriptVisitors } from "./typescript"; import { transformPostfixUnaryExpression, transformPrefixUnaryExpression } from "./unary-expression"; import { transformVariableStatement } from "./variable-declaration"; +import { transformAwaitExpression } from "./async-await"; +import { transformVoidExpression } from "./void"; const transformEmptyStatement: FunctionVisitor = () => undefined; const transformParenthesizedExpression: FunctionVisitor = (node, context) => @@ -49,6 +51,7 @@ export const standardVisitors: Visitors = { ...literalVisitors, ...typescriptVisitors, [ts.SyntaxKind.ArrowFunction]: transformFunctionLikeDeclaration, + [ts.SyntaxKind.AwaitExpression]: transformAwaitExpression, [ts.SyntaxKind.BinaryExpression]: transformBinaryExpression, [ts.SyntaxKind.Block]: transformBlock, [ts.SyntaxKind.BreakStatement]: transformBreakStatement, @@ -96,4 +99,5 @@ export const standardVisitors: Visitors = { [ts.SyntaxKind.VariableStatement]: transformVariableStatement, [ts.SyntaxKind.WhileStatement]: transformWhileStatement, [ts.SyntaxKind.YieldExpression]: transformYieldExpression, + [ts.SyntaxKind.VoidExpression]: transformVoidExpression, }; diff --git a/src/transformation/visitors/language-extensions/call-extension.ts b/src/transformation/visitors/language-extensions/call-extension.ts new file mode 100644 index 000000000..49c05b72e --- /dev/null +++ b/src/transformation/visitors/language-extensions/call-extension.ts @@ -0,0 +1,34 @@ +import { TransformationContext } from "../../context"; +import * as ts from "typescript"; +import { ExtensionKind, getExtensionKindForNode } from "../../utils/language-extensions"; +import * as lua from "../../../LuaAST"; +import { operatorExtensionTransformers } from "./operators"; +import { tableExtensionTransformers, tableNewExtensions } from "./table"; + +const allCallExtensionHandlers: LanguageExtensionCallTransformerMap = { + ...operatorExtensionTransformers, + ...tableExtensionTransformers, +}; +export const callExtensions = new Set(Object.keys(allCallExtensionHandlers) as ExtensionKind[]); +tableNewExtensions.forEach(kind => callExtensions.add(kind)); + +export type LanguageExtensionCallTransformer = ( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +) => lua.Expression; + +export type LanguageExtensionCallTransformerMap = { + [P in ExtensionKind]?: LanguageExtensionCallTransformer; +}; +export function transformLanguageExtensionCallExpression( + context: TransformationContext, + node: ts.CallExpression +): lua.Expression | undefined { + const extensionKind = getExtensionKindForNode(context, node.expression); + if (!extensionKind) return; + const transformer = allCallExtensionHandlers[extensionKind]; + if (transformer) { + return transformer(context, node, extensionKind); + } +} diff --git a/src/transformation/visitors/language-extensions/identifier.ts b/src/transformation/visitors/language-extensions/identifier.ts new file mode 100644 index 000000000..945126e6d --- /dev/null +++ b/src/transformation/visitors/language-extensions/identifier.ts @@ -0,0 +1,27 @@ +import * as ts from "typescript"; +import { ExtensionKind } from "../../utils/language-extensions"; +import { TransformationContext } from "../../context"; +import { invalidMultiFunctionUse, invalidRangeUse, invalidVarargUse } from "../../utils/diagnostics"; + +const extensionKindToValueName: { [T in ExtensionKind]?: string } = { + [ExtensionKind.MultiFunction]: "$multi", + [ExtensionKind.RangeFunction]: "$range", + [ExtensionKind.VarargConstant]: "$vararg", +}; +export function isIdentifierExtensionValue(symbol: ts.Symbol | undefined, extensionKind: ExtensionKind): boolean { + return symbol !== undefined && extensionKindToValueName[extensionKind] === symbol.name; +} + +export function reportInvalidExtensionValue( + context: TransformationContext, + identifier: ts.Identifier, + extensionKind: ExtensionKind +): void { + if (extensionKind === ExtensionKind.MultiFunction) { + context.diagnostics.push(invalidMultiFunctionUse(identifier)); + } else if (extensionKind === ExtensionKind.RangeFunction) { + context.diagnostics.push(invalidRangeUse(identifier)); + } else if (extensionKind === ExtensionKind.VarargConstant) { + context.diagnostics.push(invalidVarargUse(identifier)); + } +} diff --git a/src/transformation/visitors/language-extensions/iterable.ts b/src/transformation/visitors/language-extensions/iterable.ts index 769e15093..ee1ded7be 100644 --- a/src/transformation/visitors/language-extensions/iterable.ts +++ b/src/transformation/visitors/language-extensions/iterable.ts @@ -1,34 +1,23 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; -import * as extensions from "../../utils/language-extensions"; import { TransformationContext } from "../../context"; import { getVariableDeclarationBinding, transformForInitializer } from "../loops/utils"; import { transformArrayBindingElement } from "../variable-declaration"; -import { invalidMultiIterableWithoutDestructuring } from "../../utils/diagnostics"; +import { + invalidMultiIterableWithoutDestructuring, + invalidPairsIterableWithoutDestructuring, +} from "../../utils/diagnostics"; import { cast } from "../../../utils"; import { isMultiReturnType } from "./multi"; -export function isIterableType(type: ts.Type): boolean { - return extensions.isExtensionType(type, extensions.ExtensionKind.IterableType); -} - -export function returnsIterableType(context: TransformationContext, node: ts.CallExpression): boolean { - const signature = context.checker.getResolvedSignature(node); - const type = signature?.getReturnType(); - return type ? isIterableType(type) : false; -} - -export function isIterableExpression(context: TransformationContext, expression: ts.Expression): boolean { - const type = context.checker.getTypeAtLocation(expression); - return isIterableType(type); -} - function transformForOfMultiIterableStatement( context: TransformationContext, statement: ts.ForOfStatement, - block: lua.Block + block: lua.Block, + luaIterator: lua.Expression, + invalidMultiUseDiagnostic: (node: ts.Node) => ts.Diagnostic ): lua.Statement { - const luaIterator = context.transformExpression(statement.expression); + context.pushPrecedingStatements(); let identifiers: lua.Identifier[] = []; if (ts.isVariableDeclarationList(statement.initializer)) { @@ -38,7 +27,7 @@ function transformForOfMultiIterableStatement( if (ts.isArrayBindingPattern(binding)) { identifiers = binding.elements.map(e => transformArrayBindingElement(context, e)); } else { - context.diagnostics.push(invalidMultiIterableWithoutDestructuring(binding)); + context.diagnostics.push(invalidMultiUseDiagnostic(binding)); } } else if (ts.isArrayLiteralExpression(statement.initializer)) { // Variables NOT declared in for loop - catch iterator values in temps and assign @@ -56,13 +45,15 @@ function transformForOfMultiIterableStatement( ); } } else { - context.diagnostics.push(invalidMultiIterableWithoutDestructuring(statement.initializer)); + context.diagnostics.push(invalidMultiUseDiagnostic(statement.initializer)); } if (identifiers.length === 0) { identifiers.push(lua.createAnonymousIdentifier()); } + block.statements.unshift(...context.popPrecedingStatements()); + return lua.createForInStatement(block, identifiers, [luaIterator], statement); } @@ -71,12 +62,53 @@ export function transformForOfIterableStatement( statement: ts.ForOfStatement, block: lua.Block ): lua.Statement { - const type = context.checker.getTypeAtLocation(statement.expression); - if (type.aliasTypeArguments?.length === 2 && isMultiReturnType(type.aliasTypeArguments[0])) { - return transformForOfMultiIterableStatement(context, statement, block); + const iteratedExpressionType = context.checker.getTypeAtLocation(statement.expression); + const iterableType = + iteratedExpressionType.isIntersection() && + iteratedExpressionType.types.find(t => t.symbol.escapedName === "Iterable"); + const iterableTypeArguments = (iterableType as ts.TypeReference)?.typeArguments; + + if (iterableTypeArguments && iterableTypeArguments.length > 0 && isMultiReturnType(iterableTypeArguments[0])) { + const luaIterator = context.transformExpression(statement.expression); + return transformForOfMultiIterableStatement( + context, + statement, + block, + luaIterator, + invalidMultiIterableWithoutDestructuring + ); } const luaIterator = context.transformExpression(statement.expression); const identifier = transformForInitializer(context, statement.initializer, block); return lua.createForInStatement(block, [identifier], [luaIterator], statement); } + +export function transformForOfPairsIterableStatement( + context: TransformationContext, + statement: ts.ForOfStatement, + block: lua.Block +): lua.Statement { + const pairsCall = lua.createCallExpression(lua.createIdentifier("pairs"), [ + context.transformExpression(statement.expression), + ]); + return transformForOfMultiIterableStatement( + context, + statement, + block, + pairsCall, + invalidPairsIterableWithoutDestructuring + ); +} + +export function transformForOfPairsKeyIterableStatement( + context: TransformationContext, + statement: ts.ForOfStatement, + block: lua.Block +): lua.Statement { + const pairsCall = lua.createCallExpression(lua.createIdentifier("pairs"), [ + context.transformExpression(statement.expression), + ]); + const identifier = transformForInitializer(context, statement.initializer, block); + return lua.createForInStatement(block, [identifier], [pairsCall], statement); +} diff --git a/src/transformation/visitors/language-extensions/multi.ts b/src/transformation/visitors/language-extensions/multi.ts index 85b3c6a29..d9d7cbc02 100644 --- a/src/transformation/visitors/language-extensions/multi.ts +++ b/src/transformation/visitors/language-extensions/multi.ts @@ -1,12 +1,24 @@ import * as ts from "typescript"; import * as extensions from "../../utils/language-extensions"; +import { + getExtensionKindForNode, + getIterableExtensionKindForNode, + IterableExtensionKind, +} from "../../utils/language-extensions"; import { TransformationContext } from "../../context"; -import { findFirstNodeAbove } from "../../utils/typescript"; -import { isIterableExpression } from "./iterable"; -import { invalidMultiFunctionUse } from "../../utils/diagnostics"; +import { findFirstNodeAbove, findFirstNonOuterParent } from "../../utils/typescript"; +const multiReturnExtensionName = "__tstlMultiReturn"; export function isMultiReturnType(type: ts.Type): boolean { - return extensions.isExtensionType(type, extensions.ExtensionKind.MultiType); + return type.getProperty(multiReturnExtensionName) !== undefined; +} + +export function canBeMultiReturnType(type: ts.Type): boolean { + return ( + (type.flags & ts.TypeFlags.Any) !== 0 || + isMultiReturnType(type) || + (type.isUnion() && type.types.some(t => canBeMultiReturnType(t))) + ); } export function isMultiFunctionCall(context: TransformationContext, expression: ts.CallExpression): boolean { @@ -24,8 +36,11 @@ export function isMultiReturnCall(context: TransformationContext, expression: ts } export function isMultiFunctionNode(context: TransformationContext, node: ts.Node): boolean { - const symbol = context.checker.getSymbolAtLocation(node); - return symbol ? extensions.isExtensionValue(context, symbol, extensions.ExtensionKind.MultiFunction) : false; + return ( + ts.isIdentifier(node) && + node.text === "$multi" && + getExtensionKindForNode(context, node) === extensions.ExtensionKind.MultiFunction + ); } export function isInMultiReturnFunction(context: TransformationContext, node: ts.Node) { @@ -43,67 +58,52 @@ export function shouldMultiReturnCallBeWrapped(context: TransformationContext, n return false; } + const parent = findFirstNonOuterParent(node); + // Variable declaration with destructuring - if (ts.isVariableDeclaration(node.parent) && ts.isArrayBindingPattern(node.parent.name)) { + if (ts.isVariableDeclaration(parent) && ts.isArrayBindingPattern(parent.name)) { return false; } // Variable assignment with destructuring if ( - ts.isBinaryExpression(node.parent) && - node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && - ts.isArrayLiteralExpression(node.parent.left) + ts.isBinaryExpression(parent) && + parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && + ts.isArrayLiteralExpression(parent.left) ) { return false; } // Spread operator - if (ts.isSpreadElement(node.parent)) { + if (ts.isSpreadElement(parent)) { return false; } // Stand-alone expression - if (ts.isExpressionStatement(node.parent)) { + if (ts.isExpressionStatement(parent)) { return false; } // Forwarded multi-return call if ( - (ts.isReturnStatement(node.parent) || ts.isArrowFunction(node.parent)) && // Body-less arrow func + (ts.isReturnStatement(parent) || ts.isArrowFunction(parent)) && // Body-less arrow func isInMultiReturnFunction(context, node) ) { return false; } // Element access expression 'foo()[0]' will be optimized using 'select' - if (ts.isElementAccessExpression(node.parent)) { + if (ts.isElementAccessExpression(parent)) { return false; } // LuaIterable in for...of - if (ts.isForOfStatement(node.parent) && isIterableExpression(context, node)) { + if ( + ts.isForOfStatement(parent) && + getIterableExtensionKindForNode(context, node) === IterableExtensionKind.Iterable + ) { return false; } return true; } - -export function findMultiAssignmentViolations( - context: TransformationContext, - node: ts.ObjectLiteralExpression -): ts.Node[] { - const result: ts.Node[] = []; - - for (const element of node.properties) { - if (!ts.isShorthandPropertyAssignment(element)) continue; - const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element); - if (valueSymbol) { - if (extensions.isExtensionValue(context, valueSymbol, extensions.ExtensionKind.MultiFunction)) { - context.diagnostics.push(invalidMultiFunctionUse(element)); - result.push(element); - } - } - } - - return result; -} diff --git a/src/transformation/visitors/language-extensions/operators.ts b/src/transformation/visitors/language-extensions/operators.ts index 5cc039d31..4cb08abc2 100644 --- a/src/transformation/visitors/language-extensions/operators.ts +++ b/src/transformation/visitors/language-extensions/operators.ts @@ -1,138 +1,125 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; -import * as extensions from "../../utils/language-extensions"; import { assert } from "../../../utils"; -import { getFunctionTypeForCall } from "../../utils/typescript"; import { LuaTarget } from "../../../CompilerOptions"; import { unsupportedForTarget } from "../../utils/diagnostics"; +import { ExtensionKind, getBinaryCallExtensionArgs, getUnaryCallExtensionArg } from "../../utils/language-extensions"; +import { LanguageExtensionCallTransformerMap } from "./call-extension"; +import { transformOrderedExpressions } from "../expression-list"; -const binaryOperatorMappings = new Map([ - [extensions.ExtensionKind.AdditionOperatorType, lua.SyntaxKind.AdditionOperator], - [extensions.ExtensionKind.AdditionOperatorMethodType, lua.SyntaxKind.AdditionOperator], - [extensions.ExtensionKind.SubtractionOperatorType, lua.SyntaxKind.SubtractionOperator], - [extensions.ExtensionKind.SubtractionOperatorMethodType, lua.SyntaxKind.SubtractionOperator], - [extensions.ExtensionKind.MultiplicationOperatorType, lua.SyntaxKind.MultiplicationOperator], - [extensions.ExtensionKind.MultiplicationOperatorMethodType, lua.SyntaxKind.MultiplicationOperator], - [extensions.ExtensionKind.DivisionOperatorType, lua.SyntaxKind.DivisionOperator], - [extensions.ExtensionKind.DivisionOperatorMethodType, lua.SyntaxKind.DivisionOperator], - [extensions.ExtensionKind.ModuloOperatorType, lua.SyntaxKind.ModuloOperator], - [extensions.ExtensionKind.ModuloOperatorMethodType, lua.SyntaxKind.ModuloOperator], - [extensions.ExtensionKind.PowerOperatorType, lua.SyntaxKind.PowerOperator], - [extensions.ExtensionKind.PowerOperatorMethodType, lua.SyntaxKind.PowerOperator], - [extensions.ExtensionKind.FloorDivisionOperatorType, lua.SyntaxKind.FloorDivisionOperator], - [extensions.ExtensionKind.FloorDivisionOperatorMethodType, lua.SyntaxKind.FloorDivisionOperator], - [extensions.ExtensionKind.BitwiseAndOperatorType, lua.SyntaxKind.BitwiseAndOperator], - [extensions.ExtensionKind.BitwiseAndOperatorMethodType, lua.SyntaxKind.BitwiseAndOperator], - [extensions.ExtensionKind.BitwiseOrOperatorType, lua.SyntaxKind.BitwiseOrOperator], - [extensions.ExtensionKind.BitwiseOrOperatorMethodType, lua.SyntaxKind.BitwiseOrOperator], - [extensions.ExtensionKind.BitwiseExclusiveOrOperatorType, lua.SyntaxKind.BitwiseExclusiveOrOperator], - [extensions.ExtensionKind.BitwiseExclusiveOrOperatorMethodType, lua.SyntaxKind.BitwiseExclusiveOrOperator], - [extensions.ExtensionKind.BitwiseLeftShiftOperatorType, lua.SyntaxKind.BitwiseLeftShiftOperator], - [extensions.ExtensionKind.BitwiseLeftShiftOperatorMethodType, lua.SyntaxKind.BitwiseLeftShiftOperator], - [extensions.ExtensionKind.BitwiseRightShiftOperatorType, lua.SyntaxKind.BitwiseRightShiftOperator], - [extensions.ExtensionKind.BitwiseRightShiftOperatorMethodType, lua.SyntaxKind.BitwiseRightShiftOperator], - [extensions.ExtensionKind.ConcatOperatorType, lua.SyntaxKind.ConcatOperator], - [extensions.ExtensionKind.ConcatOperatorMethodType, lua.SyntaxKind.ConcatOperator], - [extensions.ExtensionKind.LessThanOperatorType, lua.SyntaxKind.LessThanOperator], - [extensions.ExtensionKind.LessThanOperatorMethodType, lua.SyntaxKind.LessThanOperator], - [extensions.ExtensionKind.GreaterThanOperatorType, lua.SyntaxKind.GreaterThanOperator], - [extensions.ExtensionKind.GreaterThanOperatorMethodType, lua.SyntaxKind.GreaterThanOperator], +const binaryOperatorMappings = new Map([ + [ExtensionKind.AdditionOperatorType, lua.SyntaxKind.AdditionOperator], + [ExtensionKind.AdditionOperatorMethodType, lua.SyntaxKind.AdditionOperator], + [ExtensionKind.SubtractionOperatorType, lua.SyntaxKind.SubtractionOperator], + [ExtensionKind.SubtractionOperatorMethodType, lua.SyntaxKind.SubtractionOperator], + [ExtensionKind.MultiplicationOperatorType, lua.SyntaxKind.MultiplicationOperator], + [ExtensionKind.MultiplicationOperatorMethodType, lua.SyntaxKind.MultiplicationOperator], + [ExtensionKind.DivisionOperatorType, lua.SyntaxKind.DivisionOperator], + [ExtensionKind.DivisionOperatorMethodType, lua.SyntaxKind.DivisionOperator], + [ExtensionKind.ModuloOperatorType, lua.SyntaxKind.ModuloOperator], + [ExtensionKind.ModuloOperatorMethodType, lua.SyntaxKind.ModuloOperator], + [ExtensionKind.PowerOperatorType, lua.SyntaxKind.PowerOperator], + [ExtensionKind.PowerOperatorMethodType, lua.SyntaxKind.PowerOperator], + [ExtensionKind.FloorDivisionOperatorType, lua.SyntaxKind.FloorDivisionOperator], + [ExtensionKind.FloorDivisionOperatorMethodType, lua.SyntaxKind.FloorDivisionOperator], + [ExtensionKind.BitwiseAndOperatorType, lua.SyntaxKind.BitwiseAndOperator], + [ExtensionKind.BitwiseAndOperatorMethodType, lua.SyntaxKind.BitwiseAndOperator], + [ExtensionKind.BitwiseOrOperatorType, lua.SyntaxKind.BitwiseOrOperator], + [ExtensionKind.BitwiseOrOperatorMethodType, lua.SyntaxKind.BitwiseOrOperator], + [ExtensionKind.BitwiseExclusiveOrOperatorType, lua.SyntaxKind.BitwiseExclusiveOrOperator], + [ExtensionKind.BitwiseExclusiveOrOperatorMethodType, lua.SyntaxKind.BitwiseExclusiveOrOperator], + [ExtensionKind.BitwiseLeftShiftOperatorType, lua.SyntaxKind.BitwiseLeftShiftOperator], + [ExtensionKind.BitwiseLeftShiftOperatorMethodType, lua.SyntaxKind.BitwiseLeftShiftOperator], + [ExtensionKind.BitwiseRightShiftOperatorType, lua.SyntaxKind.BitwiseRightShiftOperator], + [ExtensionKind.BitwiseRightShiftOperatorMethodType, lua.SyntaxKind.BitwiseRightShiftOperator], + [ExtensionKind.ConcatOperatorType, lua.SyntaxKind.ConcatOperator], + [ExtensionKind.ConcatOperatorMethodType, lua.SyntaxKind.ConcatOperator], + [ExtensionKind.LessThanOperatorType, lua.SyntaxKind.LessThanOperator], + [ExtensionKind.LessThanOperatorMethodType, lua.SyntaxKind.LessThanOperator], + [ExtensionKind.GreaterThanOperatorType, lua.SyntaxKind.GreaterThanOperator], + [ExtensionKind.GreaterThanOperatorMethodType, lua.SyntaxKind.GreaterThanOperator], ]); -const unaryOperatorMappings = new Map([ - [extensions.ExtensionKind.NegationOperatorType, lua.SyntaxKind.NegationOperator], - [extensions.ExtensionKind.NegationOperatorMethodType, lua.SyntaxKind.NegationOperator], - [extensions.ExtensionKind.BitwiseNotOperatorType, lua.SyntaxKind.BitwiseNotOperator], - [extensions.ExtensionKind.BitwiseNotOperatorMethodType, lua.SyntaxKind.BitwiseNotOperator], - [extensions.ExtensionKind.LengthOperatorType, lua.SyntaxKind.LengthOperator], - [extensions.ExtensionKind.LengthOperatorMethodType, lua.SyntaxKind.LengthOperator], +const unaryOperatorMappings = new Map([ + [ExtensionKind.NegationOperatorType, lua.SyntaxKind.NegationOperator], + [ExtensionKind.NegationOperatorMethodType, lua.SyntaxKind.NegationOperator], + [ExtensionKind.BitwiseNotOperatorType, lua.SyntaxKind.BitwiseNotOperator], + [ExtensionKind.BitwiseNotOperatorMethodType, lua.SyntaxKind.BitwiseNotOperator], + [ExtensionKind.LengthOperatorType, lua.SyntaxKind.LengthOperator], + [ExtensionKind.LengthOperatorMethodType, lua.SyntaxKind.LengthOperator], ]); -const operatorMapExtensions = [...binaryOperatorMappings.keys(), ...unaryOperatorMappings.keys()]; +const bitwiseOperatorMapExtensions = new Set([ + ExtensionKind.BitwiseAndOperatorType, + ExtensionKind.BitwiseAndOperatorMethodType, + ExtensionKind.BitwiseOrOperatorType, + ExtensionKind.BitwiseOrOperatorMethodType, + ExtensionKind.BitwiseExclusiveOrOperatorType, + ExtensionKind.BitwiseExclusiveOrOperatorMethodType, + ExtensionKind.BitwiseLeftShiftOperatorType, + ExtensionKind.BitwiseLeftShiftOperatorMethodType, + ExtensionKind.BitwiseRightShiftOperatorType, + ExtensionKind.BitwiseRightShiftOperatorMethodType, + ExtensionKind.BitwiseNotOperatorType, + ExtensionKind.BitwiseNotOperatorMethodType, +]); -const bitwiseOperatorMapExtensions = new Set([ - extensions.ExtensionKind.BitwiseAndOperatorType, - extensions.ExtensionKind.BitwiseAndOperatorMethodType, - extensions.ExtensionKind.BitwiseOrOperatorType, - extensions.ExtensionKind.BitwiseOrOperatorMethodType, - extensions.ExtensionKind.BitwiseExclusiveOrOperatorType, - extensions.ExtensionKind.BitwiseExclusiveOrOperatorMethodType, - extensions.ExtensionKind.BitwiseLeftShiftOperatorType, - extensions.ExtensionKind.BitwiseLeftShiftOperatorMethodType, - extensions.ExtensionKind.BitwiseRightShiftOperatorType, - extensions.ExtensionKind.BitwiseRightShiftOperatorMethodType, - extensions.ExtensionKind.BitwiseNotOperatorType, - extensions.ExtensionKind.BitwiseNotOperatorMethodType, +const requiresLua53 = new Set([ + ...bitwiseOperatorMapExtensions, + ExtensionKind.FloorDivisionOperatorType, + ExtensionKind.FloorDivisionOperatorMethodType, ]); -function getOperatorMapExtensionKindForCall(context: TransformationContext, node: ts.CallExpression) { - const type = getFunctionTypeForCall(context, node); - return type && operatorMapExtensions.find(extensionKind => extensions.isExtensionType(type, extensionKind)); +export const operatorExtensionTransformers: LanguageExtensionCallTransformerMap = {}; +for (const kind of binaryOperatorMappings.keys()) { + operatorExtensionTransformers[kind] = transformBinaryOperator; +} +for (const kind of unaryOperatorMappings.keys()) { + operatorExtensionTransformers[kind] = transformUnaryOperator; } -export function isOperatorMapping(context: TransformationContext, node: ts.CallExpression | ts.Identifier) { - if (ts.isCallExpression(node)) { - return getOperatorMapExtensionKindForCall(context, node) !== undefined; - } else { - const type = context.checker.getTypeAtLocation(node); - return operatorMapExtensions.some(extensionKind => extensions.isExtensionType(type, extensionKind)); - } +function transformBinaryOperator(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind) { + if (requiresLua53.has(kind)) checkHasLua53(context, node, kind); + + const args = getBinaryCallExtensionArgs(context, node, kind); + if (!args) return lua.createNilLiteral(); + + const [left, right] = transformOrderedExpressions(context, args); + + const luaOperator = binaryOperatorMappings.get(kind); + assert(luaOperator); + return lua.createBinaryExpression(left, right, luaOperator); } -export function transformOperatorMappingExpression( - context: TransformationContext, - node: ts.CallExpression -): lua.Expression { - const extensionKind = getOperatorMapExtensionKindForCall(context, node); - assert(extensionKind); +function transformUnaryOperator(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind) { + if (requiresLua53.has(kind)) checkHasLua53(context, node, kind); + const arg = getUnaryCallExtensionArg(context, node, kind); + if (!arg) return lua.createNilLiteral(); + + const luaOperator = unaryOperatorMappings.get(kind); + assert(luaOperator); + return lua.createUnaryExpression(context.transformExpression(arg), luaOperator); +} + +function checkHasLua53(context: TransformationContext, node: ts.CallExpression, kind: ExtensionKind) { const isBefore53 = + context.luaTarget === LuaTarget.Lua50 || context.luaTarget === LuaTarget.Lua51 || context.luaTarget === LuaTarget.Lua52 || context.luaTarget === LuaTarget.LuaJIT || context.luaTarget === LuaTarget.Universal; if (isBefore53) { const luaTarget = context.luaTarget === LuaTarget.Universal ? LuaTarget.Lua51 : context.luaTarget; - if (bitwiseOperatorMapExtensions.has(extensionKind)) { - context.diagnostics.push(unsupportedForTarget(node, "Native bitwise operations", luaTarget)); - } else if ( - extensionKind === extensions.ExtensionKind.FloorDivisionOperatorType || - extensionKind === extensions.ExtensionKind.FloorDivisionOperatorMethodType - ) { - context.diagnostics.push(unsupportedForTarget(node, "Floor division operator", luaTarget)); - } - } - - const args = node.arguments.slice(); - if (binaryOperatorMappings.has(extensionKind)) { if ( - args.length === 1 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) + kind === ExtensionKind.FloorDivisionOperatorType || + kind === ExtensionKind.FloorDivisionOperatorMethodType ) { - args.unshift(node.expression.expression); - } - - const luaOperator = binaryOperatorMappings.get(extensionKind); - assert(luaOperator); - return lua.createBinaryExpression( - context.transformExpression(args[0]), - context.transformExpression(args[1]), - luaOperator - ); - } else { - let arg: ts.Expression; - if ( - args.length === 0 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) - ) { - arg = node.expression.expression; + context.diagnostics.push(unsupportedForTarget(node, "Floor division operator", luaTarget)); } else { - arg = args[0]; + // is bitwise operator + context.diagnostics.push(unsupportedForTarget(node, "Native bitwise operations", luaTarget)); } - - const luaOperator = unaryOperatorMappings.get(extensionKind); - assert(luaOperator); - return lua.createUnaryExpression(context.transformExpression(arg), luaOperator); } } diff --git a/src/transformation/visitors/language-extensions/range.ts b/src/transformation/visitors/language-extensions/range.ts index 43f297a9a..00647180c 100644 --- a/src/transformation/visitors/language-extensions/range.ts +++ b/src/transformation/visitors/language-extensions/range.ts @@ -7,14 +7,18 @@ import { transformIdentifier } from "../identifier"; import { transformArguments } from "../call"; import { assert } from "../../../utils"; import { invalidRangeControlVariable } from "../../utils/diagnostics"; +import { getExtensionKindForNode } from "../../utils/language-extensions"; export function isRangeFunction(context: TransformationContext, expression: ts.CallExpression): boolean { return isRangeFunctionNode(context, expression.expression); } export function isRangeFunctionNode(context: TransformationContext, node: ts.Node): boolean { - const symbol = context.checker.getSymbolAtLocation(node); - return symbol ? extensions.isExtensionValue(context, symbol, extensions.ExtensionKind.RangeFunction) : false; + return ( + ts.isIdentifier(node) && + node.text === "$range" && + getExtensionKindForNode(context, node) === extensions.ExtensionKind.RangeFunction + ); } function getControlVariable(context: TransformationContext, statement: ts.ForOfStatement) { diff --git a/src/transformation/visitors/language-extensions/table.ts b/src/transformation/visitors/language-extensions/table.ts index 695bcd3b1..e42e3f8c7 100644 --- a/src/transformation/visitors/language-extensions/table.ts +++ b/src/transformation/visitors/language-extensions/table.ts @@ -1,124 +1,83 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; -import * as extensions from "../../utils/language-extensions"; -import { getFunctionTypeForCall } from "../../utils/typescript"; -import { assert } from "../../../utils"; - -const tableDeleteExtensions = [ - extensions.ExtensionKind.TableDeleteType, - extensions.ExtensionKind.TableDeleteMethodType, -]; - -const tableGetExtensions = [extensions.ExtensionKind.TableGetType, extensions.ExtensionKind.TableGetMethodType]; - -const tableHasExtensions = [extensions.ExtensionKind.TableHasType, extensions.ExtensionKind.TableHasMethodType]; - -const tableSetExtensions = [extensions.ExtensionKind.TableSetType, extensions.ExtensionKind.TableSetMethodType]; - -const tableExtensions = [ - extensions.ExtensionKind.TableNewType, - ...tableDeleteExtensions, - ...tableGetExtensions, - ...tableHasExtensions, - ...tableSetExtensions, -]; - -function getTableExtensionKindForCall( - context: TransformationContext, - node: ts.CallExpression, - validExtensions: extensions.ExtensionKind[] -) { - const type = getFunctionTypeForCall(context, node); - return type && validExtensions.find(extensionKind => extensions.isExtensionType(type, extensionKind)); -} - -export function isTableExtensionIdentifier(context: TransformationContext, node: ts.Identifier) { - const type = context.checker.getTypeAtLocation(node); - return tableExtensions.some(extensionKind => extensions.isExtensionType(type, extensionKind)); -} - -export function isTableDeleteCall(context: TransformationContext, node: ts.CallExpression) { - return getTableExtensionKindForCall(context, node, tableDeleteExtensions) !== undefined; -} - -export function isTableGetCall(context: TransformationContext, node: ts.CallExpression) { - return getTableExtensionKindForCall(context, node, tableGetExtensions) !== undefined; -} - -export function isTableHasCall(context: TransformationContext, node: ts.CallExpression) { - return getTableExtensionKindForCall(context, node, tableHasExtensions) !== undefined; -} - -export function isTableSetCall(context: TransformationContext, node: ts.CallExpression) { - return getTableExtensionKindForCall(context, node, tableSetExtensions) !== undefined; -} +import { + ExtensionKind, + getBinaryCallExtensionArgs, + getExtensionKindForNode, + getNaryCallExtensionArgs, + getUnaryCallExtensionArg, +} from "../../utils/language-extensions"; +import { transformOrderedExpressions } from "../expression-list"; +import { LanguageExtensionCallTransformerMap } from "./call-extension"; export function isTableNewCall(context: TransformationContext, node: ts.NewExpression) { - const type = context.checker.getTypeAtLocation(node.expression); - return extensions.isExtensionType(type, extensions.ExtensionKind.TableNewType); + return getExtensionKindForNode(context, node.expression) === ExtensionKind.TableNewType; } -export function transformTableDeleteExpression(context: TransformationContext, node: ts.CallExpression): lua.Statement { - const extensionKind = getTableExtensionKindForCall(context, node, tableDeleteExtensions); - assert(extensionKind); - - const args = node.arguments.slice(); - if ( - args.length === 1 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) - ) { - // In case of method (no table argument), push method owner to front of args list - args.unshift(node.expression.expression); +export const tableNewExtensions = [ExtensionKind.TableNewType]; + +export const tableExtensionTransformers: LanguageExtensionCallTransformerMap = { + [ExtensionKind.TableDeleteType]: transformTableDeleteExpression, + [ExtensionKind.TableDeleteMethodType]: transformTableDeleteExpression, + [ExtensionKind.TableGetType]: transformTableGetExpression, + [ExtensionKind.TableGetMethodType]: transformTableGetExpression, + [ExtensionKind.TableHasType]: transformTableHasExpression, + [ExtensionKind.TableHasMethodType]: transformTableHasExpression, + [ExtensionKind.TableSetType]: transformTableSetExpression, + [ExtensionKind.TableSetMethodType]: transformTableSetExpression, + [ExtensionKind.TableAddKeyType]: transformTableAddKeyExpression, + [ExtensionKind.TableAddKeyMethodType]: transformTableAddKeyExpression, + [ExtensionKind.TableIsEmptyType]: transformTableIsEmptyExpression, + [ExtensionKind.TableIsEmptyMethodType]: transformTableIsEmptyExpression, +}; + +function transformTableDeleteExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getBinaryCallExtensionArgs(context, node, extensionKind); + if (!args) { + return lua.createNilLiteral(); } + const [table, key] = transformOrderedExpressions(context, args); // arg0[arg1] = nil - return lua.createAssignmentStatement( - lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1])), - lua.createNilLiteral(), - node + context.addPrecedingStatements( + lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), lua.createNilLiteral(), node) ); + return lua.createBooleanLiteral(true); } -export function transformTableGetExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression { - const extensionKind = getTableExtensionKindForCall(context, node, tableGetExtensions); - assert(extensionKind); - - const args = node.arguments.slice(); - if ( - args.length === 1 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) - ) { - // In case of method (no table argument), push method owner to front of args list - args.unshift(node.expression.expression); +function transformTableGetExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getBinaryCallExtensionArgs(context, node, extensionKind); + if (!args) { + return lua.createNilLiteral(); } + const [table, key] = transformOrderedExpressions(context, args); // arg0[arg1] - return lua.createTableIndexExpression( - context.transformExpression(args[0]), - context.transformExpression(args[1]), - node - ); + return lua.createTableIndexExpression(table, key, node); } -export function transformTableHasExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression { - const extensionKind = getTableExtensionKindForCall(context, node, tableHasExtensions); - assert(extensionKind); - - const args = node.arguments.slice(); - if ( - args.length === 1 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) - ) { - // In case of method (no table argument), push method owner to front of args list - args.unshift(node.expression.expression); +function transformTableHasExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getBinaryCallExtensionArgs(context, node, extensionKind); + if (!args) { + return lua.createNilLiteral(); } + const [table, key] = transformOrderedExpressions(context, args); // arg0[arg1] - const tableIndexExpression = lua.createTableIndexExpression( - context.transformExpression(args[0]), - context.transformExpression(args[1]) - ); + const tableIndexExpression = lua.createTableIndexExpression(table, key); // arg0[arg1] ~= nil return lua.createBinaryExpression( @@ -129,23 +88,58 @@ export function transformTableHasExpression(context: TransformationContext, node ); } -export function transformTableSetExpression(context: TransformationContext, node: ts.CallExpression): lua.Statement { - const extensionKind = getTableExtensionKindForCall(context, node, tableSetExtensions); - assert(extensionKind); - - const args = node.arguments.slice(); - if ( - args.length === 2 && - (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression)) - ) { - // In case of method (no table argument), push method owner to front of args list - args.unshift(node.expression.expression); +function transformTableSetExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getNaryCallExtensionArgs(context, node, extensionKind, 3); + if (!args) { + return lua.createNilLiteral(); } + const [table, key, value] = transformOrderedExpressions(context, args); // arg0[arg1] = arg2 - return lua.createAssignmentStatement( - lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1])), - context.transformExpression(args[2]), + context.addPrecedingStatements( + lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), value, node) + ); + return lua.createNilLiteral(); +} + +function transformTableAddKeyExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getNaryCallExtensionArgs(context, node, extensionKind, 2); + if (!args) { + return lua.createNilLiteral(); + } + + const [table, key] = transformOrderedExpressions(context, args); + // arg0[arg1] = true + context.addPrecedingStatements( + lua.createAssignmentStatement(lua.createTableIndexExpression(table, key), lua.createBooleanLiteral(true), node) + ); + return lua.createNilLiteral(); +} + +function transformTableIsEmptyExpression( + context: TransformationContext, + node: ts.CallExpression, + extensionKind: ExtensionKind +): lua.Expression { + const args = getUnaryCallExtensionArg(context, node, extensionKind); + if (!args) { + return lua.createNilLiteral(); + } + + const table = context.transformExpression(args); + // next(arg0) == nil + return lua.createBinaryExpression( + lua.createCallExpression(lua.createIdentifier("next"), [table], node), + lua.createNilLiteral(), + lua.SyntaxKind.EqualityOperator, node ); } diff --git a/src/transformation/visitors/language-extensions/vararg.ts b/src/transformation/visitors/language-extensions/vararg.ts index 99eea82a9..4576737c8 100644 --- a/src/transformation/visitors/language-extensions/vararg.ts +++ b/src/transformation/visitors/language-extensions/vararg.ts @@ -1,16 +1,20 @@ import * as ts from "typescript"; import { TransformationContext } from "../../context"; import * as extensions from "../../utils/language-extensions"; +import { getExtensionKindForSymbol } from "../../utils/language-extensions"; import { Scope, ScopeType } from "../../utils/scope"; export function isGlobalVarargConstant(context: TransformationContext, symbol: ts.Symbol, scope: Scope) { + return scope.type === ScopeType.File && isVarargConstantSymbol(context, symbol); +} +function isVarargConstantSymbol(context: TransformationContext, symbol: ts.Symbol) { return ( - scope.type === ScopeType.File && - extensions.isExtensionValue(context, symbol, extensions.ExtensionKind.VarargConstant) + symbol.getName() === "$vararg" && + getExtensionKindForSymbol(context, symbol) === extensions.ExtensionKind.VarargConstant ); } export function isVarargConstantNode(context: TransformationContext, node: ts.Node): boolean { const symbol = context.checker.getSymbolAtLocation(node); - return symbol ? extensions.isExtensionValue(context, symbol, extensions.ExtensionKind.VarargConstant) : false; + return symbol !== undefined && isVarargConstantSymbol(context, symbol); } diff --git a/src/transformation/visitors/literal.ts b/src/transformation/visitors/literal.ts index 8fa85e4e4..1d91c89d9 100644 --- a/src/transformation/visitors/literal.ts +++ b/src/transformation/visitors/literal.ts @@ -2,15 +2,14 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { assertNever } from "../../utils"; import { FunctionVisitor, TransformationContext, Visitors } from "../context"; -import { unsupportedAccessorInObjectLiteral, invalidMultiFunctionUse } from "../utils/diagnostics"; -import { createExportedIdentifier, getSymbolExportScope } from "../utils/export"; +import { undefinedInArrayLiteral, unsupportedAccessorInObjectLiteral } from "../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { createSafeName, hasUnsafeIdentifierName, hasUnsafeSymbolName } from "../utils/safe-names"; -import { getSymbolIdOfSymbol, trackSymbolReference } from "../utils/symbols"; +import { trackSymbolReference } from "../utils/symbols"; import { isArrayType } from "../utils/typescript"; import { transformFunctionLikeDeclaration } from "./function"; -import { flattenSpreadExpressions } from "./call"; -import { findMultiAssignmentViolations } from "./language-extensions/multi"; +import { moveToPrecedingTemp, transformExpressionList } from "./expression-list"; +import { transformIdentifierWithSymbol } from "./identifier"; +import { LuaTarget } from "../../CompilerOptions"; // TODO: Move to object-literal.ts? export function transformPropertyName(context: TransformationContext, node: ts.PropertyName): lua.Expression { @@ -30,54 +29,53 @@ export function createShorthandIdentifier( valueSymbol: ts.Symbol | undefined, propertyIdentifier: ts.Identifier ): lua.Expression { - const propertyName = propertyIdentifier.text; - - const isUnsafeName = valueSymbol - ? hasUnsafeSymbolName(context, valueSymbol, propertyIdentifier) - : hasUnsafeIdentifierName(context, propertyIdentifier, false); - - const name = isUnsafeName ? createSafeName(propertyName) : propertyName; - - let identifier = context.transformExpression(ts.factory.createIdentifier(name)); - lua.setNodeOriginal(identifier, propertyIdentifier); - if (valueSymbol !== undefined && lua.isIdentifier(identifier)) { - identifier.symbolId = getSymbolIdOfSymbol(context, valueSymbol); - - const exportScope = getSymbolExportScope(context, valueSymbol); - if (exportScope) { - identifier = createExportedIdentifier(context, identifier, exportScope); - } - } - - return identifier; + return transformIdentifierWithSymbol(context, propertyIdentifier, valueSymbol); } -const transformNumericLiteralExpression: FunctionVisitor = expression => { +const transformNumericLiteralExpression: FunctionVisitor = (expression, context) => { if (expression.text === "Infinity") { - const math = lua.createIdentifier("math"); - const huge = lua.createStringLiteral("huge"); - return lua.createTableIndexExpression(math, huge, expression); + if (context.luaTarget === LuaTarget.Lua50) { + const one = lua.createNumericLiteral(1); + const zero = lua.createNumericLiteral(0); + return lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator); + } else { + const math = lua.createIdentifier("math"); + const huge = lua.createStringLiteral("huge"); + return lua.createTableIndexExpression(math, huge, expression); + } } return lua.createNumericLiteral(Number(expression.text), expression); }; const transformObjectLiteralExpression: FunctionVisitor = (expression, context) => { - const violations = findMultiAssignmentViolations(context, expression); - if (violations.length > 0) { - context.diagnostics.push(...violations.map(e => invalidMultiFunctionUse(e))); - return lua.createNilLiteral(expression); - } + const properties: lua.Expression[] = []; + const initializers: ts.Node[] = []; + const keyPrecedingStatements: lua.Statement[][] = []; + const valuePrecedingStatements: lua.Statement[][] = []; + let lastPrecedingStatementsIndex = -1; - let properties: lua.TableFieldExpression[] = []; - const tableExpressions: lua.Expression[] = []; + for (let i = 0; i < expression.properties.length; ++i) { + const element = expression.properties[i]; + + // Transform key and cache preceding statements + context.pushPrecedingStatements(); - for (const element of expression.properties) { const name = element.name ? transformPropertyName(context, element.name) : undefined; + let precedingStatements = context.popPrecedingStatements(); + keyPrecedingStatements.push(precedingStatements); + if (precedingStatements.length > 0) { + lastPrecedingStatementsIndex = i; + } + + // Transform value and cache preceding statements + context.pushPrecedingStatements(); + if (ts.isPropertyAssignment(element)) { const expression = context.transformExpression(element.initializer); properties.push(lua.createTableFieldExpression(expression, name, element)); + initializers.push(element.initializer); } else if (ts.isShorthandPropertyAssignment(element)) { const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element); if (valueSymbol) { @@ -86,18 +84,12 @@ const transformObjectLiteralExpression: FunctionVisitor __TS__ObjectAssign({x = 0}, {y = 2}, {y = 1, z = 2}) - if (properties.length > 0) { - const tableExpression = lua.createTableExpression(properties, expression); - tableExpressions.push(tableExpression); - properties = []; - } - const type = context.checker.getTypeAtLocation(element.expression); let tableExpression: lua.Expression; if (isArrayType(context, type)) { @@ -111,39 +103,115 @@ const transformObjectLiteralExpression: FunctionVisitor 0) { + lastPrecedingStatementsIndex = i; + } + } + + // Expressions referenced before others that produced preceding statements need to be cached in temps + if (lastPrecedingStatementsIndex >= 0) { + for (let i = 0; i < properties.length; ++i) { + const property = properties[i]; + + // Bubble up key's preceding statements + context.addPrecedingStatements(keyPrecedingStatements[i]); + + // Cache computed property name in temp if before the last expression that generated preceding statements + if (i <= lastPrecedingStatementsIndex && lua.isTableFieldExpression(property) && property.key) { + property.key = moveToPrecedingTemp(context, property.key, expression.properties[i].name); + } + + // Bubble up value's preceding statements + context.addPrecedingStatements(valuePrecedingStatements[i]); + + // Cache property value in temp if before the last expression that generated preceding statements + if (i < lastPrecedingStatementsIndex) { + if (lua.isTableFieldExpression(property)) { + property.value = moveToPrecedingTemp(context, property.value, initializers[i]); + } else { + properties[i] = moveToPrecedingTemp(context, property, initializers[i]); + } + } + } + } + + // Sort into field expressions and tables to pass into __TS__ObjectAssign + let fields: lua.TableFieldExpression[] = []; + const tableExpressions: lua.Expression[] = []; + for (const property of properties) { + if (lua.isTableFieldExpression(property)) { + fields.push(property); + } else { + if (fields.length > 0) { + tableExpressions.push(lua.createTableExpression(fields)); + } + tableExpressions.push(property); + fields = []; + } } if (tableExpressions.length === 0) { - return lua.createTableExpression(properties, expression); + return lua.createTableExpression(fields, expression); } else { - if (properties.length > 0) { - const tableExpression = lua.createTableExpression(properties, expression); + if (fields.length > 0) { + const tableExpression = lua.createTableExpression(fields, expression); tableExpressions.push(tableExpression); } if (tableExpressions[0].kind !== lua.SyntaxKind.TableExpression) { tableExpressions.unshift(lua.createTableExpression(undefined, expression)); } - return transformLuaLibFunction(context, LuaLibFeature.ObjectAssign, expression, ...tableExpressions); } }; const transformArrayLiteralExpression: FunctionVisitor = (expression, context) => { + // Disallow using undefined/null in array literals + checkForUndefinedOrNullInArrayLiteral(expression, context); + const filteredElements = expression.elements.map(e => ts.isOmittedExpression(e) ? ts.factory.createIdentifier("undefined") : e ); - const values = flattenSpreadExpressions(context, filteredElements).map(e => lua.createTableFieldExpression(e)); + const values = transformExpressionList(context, filteredElements).map(e => lua.createTableFieldExpression(e)); return lua.createTableExpression(values, expression); }; +function checkForUndefinedOrNullInArrayLiteral(array: ts.ArrayLiteralExpression, context: TransformationContext) { + // Look for last non-nil element in literal + let lastNonUndefinedIndex = array.elements.length - 1; + for (; lastNonUndefinedIndex >= 0; lastNonUndefinedIndex--) { + if (!isUndefinedOrNull(array.elements[lastNonUndefinedIndex])) { + break; + } + } + + // Add diagnostics for non-trailing nil elements in array literal + for (let i = 0; i < array.elements.length; i++) { + if (i < lastNonUndefinedIndex && isUndefinedOrNull(array.elements[i])) { + context.diagnostics.push(undefinedInArrayLiteral(array.elements[i])); + } + } +} + +function isUndefinedOrNull(node: ts.Node) { + return ( + node.kind === ts.SyntaxKind.UndefinedKeyword || + node.kind === ts.SyntaxKind.NullKeyword || + (ts.isIdentifier(node) && node.text === "undefined") + ); +} + export const literalVisitors: Visitors = { [ts.SyntaxKind.NullKeyword]: node => lua.createNilLiteral(node), [ts.SyntaxKind.TrueKeyword]: node => lua.createBooleanLiteral(true, node), diff --git a/src/transformation/visitors/loops/do-while.ts b/src/transformation/visitors/loops/do-while.ts index 0fafc710a..f4c714c71 100644 --- a/src/transformation/visitors/loops/do-while.ts +++ b/src/transformation/visitors/loops/do-while.ts @@ -1,23 +1,77 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor } from "../../context"; -import { transformLoopBody } from "./utils"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; +import { checkOnlyTruthyCondition } from "../conditional"; +import { invertCondition, transformLoopBody } from "./utils"; -export const transformWhileStatement: FunctionVisitor = (statement, context) => - lua.createWhileStatement( - lua.createBlock(transformLoopBody(context, statement)), - context.transformExpression(statement.expression), - statement +export const transformWhileStatement: FunctionVisitor = (statement, context) => { + // Check if we need to add diagnostic about Lua truthiness + checkOnlyTruthyCondition(statement.expression, context); + + const body = transformLoopBody(context, statement); + + let { precedingStatements: conditionPrecedingStatements, result: condition } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(statement.expression) ); + // If condition has preceding statements, ensure they are executed every iteration by using the form: + // + // while true do + // condition's preceding statements + // if not condition then + // break + // end + // ... + // end + if (conditionPrecedingStatements.length > 0) { + conditionPrecedingStatements.push( + lua.createIfStatement( + invertCondition(condition), + lua.createBlock([lua.createBreakStatement()]), + undefined, + statement.expression + ) + ); + body.unshift(...conditionPrecedingStatements); + condition = lua.createBooleanLiteral(true); + } + + return lua.createWhileStatement(lua.createBlock(body), condition, statement); +}; + export const transformDoStatement: FunctionVisitor = (statement, context) => { + // Check if we need to add diagnostic about Lua truthiness + checkOnlyTruthyCondition(statement.expression, context); + const body = lua.createDoStatement(transformLoopBody(context, statement)); - let condition = context.transformExpression(statement.expression); - if (lua.isUnaryExpression(condition) && condition.operator === lua.SyntaxKind.NotOperator) { - condition = condition.operand; - } else { - condition = lua.createUnaryExpression(condition, lua.SyntaxKind.NotOperator); + + let { precedingStatements: conditionPrecedingStatements, result: condition } = transformInPrecedingStatementScope( + context, + () => invertCondition(context.transformExpression(statement.expression)) + ); + + // If condition has preceding statements, ensure they are executed every iteration by using the form: + // + // repeat + // ... + // condition's preceding statements + // if condition then + // break + // end + // end + if (conditionPrecedingStatements.length > 0) { + conditionPrecedingStatements.push( + lua.createIfStatement( + condition, + lua.createBlock([lua.createBreakStatement()]), + undefined, + statement.expression + ) + ); + condition = lua.createBooleanLiteral(false); } - return lua.createRepeatStatement(lua.createBlock([body]), condition, statement); + return lua.createRepeatStatement(lua.createBlock([body, ...conditionPrecedingStatements]), condition, statement); }; diff --git a/src/transformation/visitors/loops/for-of.ts b/src/transformation/visitors/loops/for-of.ts index 64d2c211b..5071623db 100644 --- a/src/transformation/visitors/loops/for-of.ts +++ b/src/transformation/visitors/loops/for-of.ts @@ -1,13 +1,18 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../../context"; -import { AnnotationKind, isForRangeType, isLuaIteratorType } from "../../utils/annotations"; -import { annotationRemoved } from "../../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { isArrayType } from "../../utils/typescript"; -import { isIterableExpression, transformForOfIterableStatement } from "../language-extensions/iterable"; +import { + transformForOfIterableStatement, + transformForOfPairsIterableStatement, + transformForOfPairsKeyIterableStatement, +} from "../language-extensions/iterable"; import { isRangeFunction, transformRangeStatement } from "../language-extensions/range"; import { transformForInitializer, transformLoopBody } from "./utils"; +import { getIterableExtensionKindForNode, IterableExtensionKind } from "../../utils/language-extensions"; +import { unsupportedForAwaitOf } from "../../utils/diagnostics"; +import { assertNever } from "../../../utils"; function transformForOfArrayStatement( context: TransformationContext, @@ -39,19 +44,30 @@ function transformForOfIteratorStatement( } export const transformForOfStatement: FunctionVisitor = (node, context) => { + if (node.awaitModifier) { + context.diagnostics.push(unsupportedForAwaitOf(node.awaitModifier)); + } + const body = lua.createBlock(transformLoopBody(context, node)); if (ts.isCallExpression(node.expression) && isRangeFunction(context, node.expression)) { return transformRangeStatement(context, node, body); - } else if (ts.isCallExpression(node.expression) && isForRangeType(context, node.expression.expression)) { - context.diagnostics.push(annotationRemoved(node.expression, AnnotationKind.ForRange)); - } else if (isIterableExpression(context, node.expression)) { - return transformForOfIterableStatement(context, node, body); - } else if (isLuaIteratorType(context, node.expression)) { - context.diagnostics.push(annotationRemoved(node.expression, AnnotationKind.LuaIterator)); - } else if (isArrayType(context, context.checker.getTypeAtLocation(node.expression))) { + } + const iterableExtensionType = getIterableExtensionKindForNode(context, node.expression); + if (iterableExtensionType) { + if (iterableExtensionType === IterableExtensionKind.Iterable) { + return transformForOfIterableStatement(context, node, body); + } else if (iterableExtensionType === IterableExtensionKind.Pairs) { + return transformForOfPairsIterableStatement(context, node, body); + } else if (iterableExtensionType === IterableExtensionKind.PairsKey) { + return transformForOfPairsKeyIterableStatement(context, node, body); + } else { + assertNever(iterableExtensionType); + } + } + if (isArrayType(context, context.checker.getTypeAtLocation(node.expression))) { return transformForOfArrayStatement(context, node, body); - } else { - return transformForOfIteratorStatement(context, node, body); } + + return transformForOfIteratorStatement(context, node, body); }; diff --git a/src/transformation/visitors/loops/for.ts b/src/transformation/visitors/loops/for.ts index 98864082e..5ae3bf0ea 100644 --- a/src/transformation/visitors/loops/for.ts +++ b/src/transformation/visitors/loops/for.ts @@ -1,12 +1,16 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor } from "../../context"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; import { checkVariableDeclarationList, transformVariableDeclaration } from "../variable-declaration"; -import { transformLoopBody } from "./utils"; +import { invertCondition, transformLoopBody } from "./utils"; +import { ScopeType } from "../../utils/scope"; export const transformForStatement: FunctionVisitor = (statement, context) => { const result: lua.Statement[] = []; + context.pushScope(ScopeType.Loop, statement); + if (statement.initializer) { if (ts.isVariableDeclarationList(statement.initializer)) { checkVariableDeclarationList(context, statement.initializer); @@ -17,19 +21,50 @@ export const transformForStatement: FunctionVisitor = (statemen } } - const condition = statement.condition - ? context.transformExpression(statement.condition) - : lua.createBooleanLiteral(true); - - // Add body const body: lua.Statement[] = transformLoopBody(context, statement); + let condition: lua.Expression; + if (statement.condition) { + const tsCondition = statement.condition; + const { precedingStatements: conditionPrecedingStatements, result } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(tsCondition) + ); + condition = result; + + // If condition has preceding statements, ensure they are executed every iteration by using the form: + // + // while true do + // condition's preceding statements + // if not condition then + // break + // end + // ... + // end + if (conditionPrecedingStatements.length > 0) { + conditionPrecedingStatements.push( + lua.createIfStatement( + invertCondition(condition), + lua.createBlock([lua.createBreakStatement()]), + undefined, + statement.condition + ) + ); + body.unshift(...conditionPrecedingStatements); + condition = lua.createBooleanLiteral(true); + } + } else { + condition = lua.createBooleanLiteral(true); + } + if (statement.incrementor) { body.push(...context.transformStatements(ts.factory.createExpressionStatement(statement.incrementor))); } // while (condition) do ... end - result.push(lua.createWhileStatement(lua.createBlock(body), condition)); + result.push(lua.createWhileStatement(lua.createBlock(body), condition, statement)); + + context.popScope(); return lua.createDoStatement(result, statement); }; diff --git a/src/transformation/visitors/loops/utils.ts b/src/transformation/visitors/loops/utils.ts index a7402b653..d7e4a3093 100644 --- a/src/transformation/visitors/loops/utils.ts +++ b/src/transformation/visitors/loops/utils.ts @@ -1,7 +1,8 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { TransformationContext } from "../../context"; -import { performHoisting, popScope, pushScope, ScopeType } from "../../utils/scope"; +import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; +import { LoopContinued, performHoisting, ScopeType } from "../../utils/scope"; import { isAssignmentPattern } from "../../utils/typescript"; import { transformAssignment } from "../binary-expression/assignments"; import { transformAssignmentPattern } from "../binary-expression/destructuring-assignments"; @@ -13,20 +14,49 @@ export function transformLoopBody( context: TransformationContext, loop: ts.WhileStatement | ts.DoStatement | ts.ForStatement | ts.ForOfStatement | ts.ForInOrOfStatement ): lua.Statement[] { - pushScope(context, ScopeType.Loop); + context.pushScope(ScopeType.Loop, loop); const body = performHoisting(context, transformBlockOrStatement(context, loop.statement)); - const scope = popScope(context); + const scope = context.popScope(); const scopeId = scope.id; - if (!scope.loopContinued) { - return body; - } + switch (scope.loopContinued) { + case undefined: + case LoopContinued.WithContinue: + return body; + + case LoopContinued.WithGoto: + return [lua.createDoStatement(body), lua.createLabelStatement(`__continue${scopeId}`)]; + + case LoopContinued.WithRepeatBreak: + const identifier = lua.createIdentifier(`__continue${scopeId}`); + const literalTrue = lua.createBooleanLiteral(true); - const baseResult: lua.Statement[] = [lua.createDoStatement(body)]; - const continueLabel = lua.createLabelStatement(`__continue${scopeId}`); - baseResult.push(continueLabel); + // If there is a break in the body statements, do not include any code afterwards + const transformedBodyStatements = []; + let bodyBroken = false; + for (const statement of body) { + transformedBodyStatements.push(statement); + if (lua.isBreakStatement(statement)) { + bodyBroken = true; + break; + } + } + if (!bodyBroken) { + // Tell loop to continue if not broken + transformedBodyStatements.push(lua.createAssignmentStatement(identifier, literalTrue)); + } - return baseResult; + return [ + lua.createDoStatement([ + lua.createVariableDeclarationStatement(identifier), + lua.createRepeatStatement(lua.createBlock(transformedBodyStatements), literalTrue), + lua.createIfStatement( + lua.createUnaryExpression(identifier, lua.SyntaxKind.NotOperator), + lua.createBlock([lua.createBreakStatement()]) + ), + ]), + ]; + } } export function getVariableDeclarationBinding( @@ -49,14 +79,20 @@ export function transformForInitializer( ): lua.Identifier { const valueVariable = lua.createIdentifier("____value"); + context.pushScope(ScopeType.LoopInitializer, initializer); + if (ts.isVariableDeclarationList(initializer)) { // Declaration of new variable const binding = getVariableDeclarationBinding(context, initializer); if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) { - block.statements.unshift(...transformBindingPattern(context, binding, valueVariable)); + const { precedingStatements, result: bindings } = transformInPrecedingStatementScope(context, () => + transformBindingPattern(context, binding, valueVariable) + ); + block.statements.unshift(...precedingStatements, ...bindings); } else { // Single variable declared in for loop + context.popScope(); return transformIdentifier(context, binding); } } else { @@ -64,10 +100,21 @@ export function transformForInitializer( block.statements.unshift( ...(isAssignmentPattern(initializer) - ? transformAssignmentPattern(context, initializer, valueVariable) + ? transformAssignmentPattern(context, initializer, valueVariable, false) : transformAssignment(context, initializer, valueVariable)) ); } + context.popScope(); return valueVariable; } + +export function invertCondition(expression: lua.Expression) { + if (lua.isUnaryExpression(expression) && expression.operator === lua.SyntaxKind.NotOperator) { + return expression.operand; + } else { + const notExpression = lua.createUnaryExpression(expression, lua.SyntaxKind.NotOperator); + lua.setNodePosition(notExpression, lua.getOriginalPos(expression)); + return notExpression; + } +} diff --git a/src/transformation/visitors/modules/export.ts b/src/transformation/visitors/modules/export.ts index 955f56866..c814b8257 100644 --- a/src/transformation/visitors/modules/export.ts +++ b/src/transformation/visitors/modules/export.ts @@ -2,17 +2,12 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { assert } from "../../../utils"; import { FunctionVisitor, TransformationContext } from "../../context"; -import { - createDefaultExportIdentifier, - createDefaultExportStringLiteral, - createExportedIdentifier, -} from "../../utils/export"; +import { createDefaultExportExpression, createDefaultExportStringLiteral } from "../../utils/export"; import { createExportsIdentifier } from "../../utils/lua-ast"; -import { ScopeType } from "../../utils/scope"; -import { transformScopeBlock } from "../block"; -import { transformIdentifier } from "../identifier"; -import { createShorthandIdentifier } from "../literal"; +import { createShorthandIdentifier, transformPropertyName } from "../literal"; import { createModuleRequire } from "./import"; +import { createSafeName } from "../../utils/safe-names"; +import * as path from "path"; export const transformExportAssignment: FunctionVisitor = (node, context) => { if (!context.resolver.isValueAliasDeclaration(node)) { @@ -39,10 +34,6 @@ export const transformExportAssignment: FunctionVisitor = ( function transformExportAll(context: TransformationContext, node: ts.ExportDeclaration): lua.Statement | undefined { assert(node.moduleSpecifier); - if (!context.resolver.moduleExportsSomeValue(node.moduleSpecifier)) { - return undefined; - } - const moduleRequire = createModuleRequire(context, node.moduleSpecifier); // export * as ns from "..."; @@ -105,21 +96,37 @@ function transformExportAll(context: TransformationContext, node: ts.ExportDecla } const isDefaultExportSpecifier = (node: ts.ExportSpecifier) => - (node.name && node.name.originalKeywordKind === ts.SyntaxKind.DefaultKeyword) || - (node.propertyName && node.propertyName.originalKeywordKind === ts.SyntaxKind.DefaultKeyword); + (node.name && + ts.isIdentifier(node.name) && + ts.identifierToKeywordKind(node.name) === ts.SyntaxKind.DefaultKeyword) || + (node.propertyName && + ts.isIdentifier(node.propertyName) && + ts.identifierToKeywordKind(node.propertyName) === ts.SyntaxKind.DefaultKeyword); function transformExportSpecifier(context: TransformationContext, node: ts.ExportSpecifier): lua.AssignmentStatement { - const exportedSymbol = context.checker.getExportSpecifierLocalTargetSymbol(node); - const exportedIdentifier = node.propertyName ? node.propertyName : node.name; - const exportedExpression = createShorthandIdentifier(context, exportedSymbol, exportedIdentifier); + const exportedName = node.name; + const exportedValue = node.propertyName ?? node.name; + let rhs: lua.Expression; + if (ts.isIdentifier(exportedValue)) { + const exportedSymbol = context.checker.getExportSpecifierLocalTargetSymbol(node); + rhs = createShorthandIdentifier(context, exportedSymbol, exportedValue); + } else { + rhs = lua.createStringLiteral(exportedName.text, exportedValue); + } - const isDefault = isDefaultExportSpecifier(node); - const identifierToExport = isDefault - ? createDefaultExportIdentifier(node) - : transformIdentifier(context, node.name); - const exportAssignmentLeftHandSide = createExportedIdentifier(context, identifierToExport); + if (isDefaultExportSpecifier(node)) { + const lhs = createDefaultExportExpression(node); + return lua.createAssignmentStatement(lhs, rhs, node); + } else { + const exportsTable = createExportsIdentifier(); + const lhs = lua.createTableIndexExpression( + exportsTable, + lua.createStringLiteral(exportedName.text), + exportedName + ); - return lua.createAssignmentStatement(exportAssignmentLeftHandSide, exportedExpression, node); + return lua.createAssignmentStatement(lhs, rhs, node); + } } function transformExportSpecifiersFrom( @@ -128,37 +135,32 @@ function transformExportSpecifiersFrom( moduleSpecifier: ts.Expression, exportSpecifiers: ts.ExportSpecifier[] ): lua.Statement { - // First transpile as import clause - const importClause = ts.factory.createImportClause( - false, - undefined, - ts.factory.createNamedImports( - exportSpecifiers.map(s => ts.factory.createImportSpecifier(s.propertyName, s.name)) - ) - ); + const result: lua.Statement[] = []; - const importDeclaration = ts.factory.createImportDeclaration( - statement.decorators, - statement.modifiers, - importClause, - moduleSpecifier - ); + const importPath = ts.isStringLiteral(moduleSpecifier) ? moduleSpecifier.text.replace(/"/g, "") : "module"; - // Wrap in block to prevent imports from hoisting out of `do` statement - const [block] = transformScopeBlock(context, ts.factory.createBlock([importDeclaration]), ScopeType.Block); - const result = block.statements; + // Create the require statement to extract values. + // local ____module = require("module") + const importUniqueName = lua.createIdentifier(createSafeName(path.basename(importPath))); + const requireCall = createModuleRequire(context, moduleSpecifier); + result.push(lua.createVariableDeclarationStatement(importUniqueName, requireCall, statement)); - // Now the module is imported, add the imports to the export table for (const specifier of exportSpecifiers) { - result.push( - lua.createAssignmentStatement( - createExportedIdentifier(context, transformIdentifier(context, specifier.name)), - transformIdentifier(context, specifier.name) - ) + // Assign to exports table + const exportsTable = createExportsIdentifier(); + const exportedName = specifier.name; + const exportedNameTransformed = transformPropertyName(context, exportedName); + const lhs = lua.createTableIndexExpression(exportsTable, exportedNameTransformed, exportedName); + + const exportedValue = specifier.propertyName ?? specifier.name; + const rhs = lua.createTableIndexExpression( + lua.cloneIdentifier(importUniqueName), + transformPropertyName(context, exportedValue), + specifier ); + result.push(lua.createAssignmentStatement(lhs, rhs, specifier)); } - // Wrap this in a DoStatement to prevent polluting the scope. return lua.createDoStatement(result, statement); } diff --git a/src/transformation/visitors/modules/import.ts b/src/transformation/visitors/modules/import.ts index d8daba8c9..7c6a597ac 100644 --- a/src/transformation/visitors/modules/import.ts +++ b/src/transformation/visitors/modules/import.ts @@ -1,13 +1,15 @@ import * as path from "path"; import * as ts from "typescript"; import * as lua from "../../../LuaAST"; +import { createStaticPromiseFunctionAccessor } from "../../builtins/promise"; import { FunctionVisitor, TransformationContext } from "../../context"; import { AnnotationKind, getSymbolAnnotations } from "../../utils/annotations"; import { createDefaultExportStringLiteral } from "../../utils/export"; import { createHoistableVariableDeclarationStatement } from "../../utils/lua-ast"; +import { importLuaLibFeature, LuaLibFeature } from "../../utils/lualib"; import { createSafeName } from "../../utils/safe-names"; import { peekScope } from "../../utils/scope"; -import { transformIdentifier } from "../identifier"; +import { getCustomNameFromSymbol, transformIdentifier } from "../identifier"; import { transformPropertyName } from "../literal"; function isNoResolutionPath(context: TransformationContext, moduleSpecifier: ts.Expression): boolean { @@ -44,11 +46,15 @@ function transformImportSpecifier( importSpecifier: ts.ImportSpecifier, moduleTableName: lua.Identifier ): lua.VariableDeclarationStatement { + const type = context.checker.getTypeAtLocation(importSpecifier.name); + const leftIdentifier = transformIdentifier(context, importSpecifier.name); - const propertyName = transformPropertyName( - context, - importSpecifier.propertyName ? importSpecifier.propertyName : importSpecifier.name - ); + + // If imported value has a customName annotation use that, otherwise use regular property + const customName = getCustomNameFromSymbol(context, type.getSymbol()); + const propertyName = customName + ? lua.createStringLiteral(customName, importSpecifier.propertyName ?? importSpecifier.name) + : transformPropertyName(context, importSpecifier.propertyName ?? importSpecifier.name); return lua.createVariableDeclarationStatement( leftIdentifier, @@ -60,9 +66,7 @@ function transformImportSpecifier( export const transformImportDeclaration: FunctionVisitor = (statement, context) => { const scope = peekScope(context); - if (!scope.importStatements) { - scope.importStatements = []; - } + scope.importStatements ??= []; const result: lua.Statement[] = []; const requireCall = createModuleRequire(context, statement.moduleSpecifier); @@ -72,12 +76,8 @@ export const transformImportDeclaration: FunctionVisitor = if (statement.importClause === undefined) { result.push(lua.createExpressionStatement(requireCall)); - if (scope.importStatements) { - scope.importStatements.push(...result); - return undefined; - } else { - return result; - } + scope.importStatements.push(...result); + return undefined; } const importPath = ts.isStringLiteral(statement.moduleSpecifier) @@ -144,12 +144,8 @@ export const transformImportDeclaration: FunctionVisitor = result.unshift(lua.createVariableDeclarationStatement(importUniqueName, requireCall, statement)); } - if (scope.importStatements) { - scope.importStatements.push(...result); - return undefined; - } else { - return result; - } + scope.importStatements.push(...result); + return undefined; }; export const transformExternalModuleReference: FunctionVisitor = (node, context) => @@ -169,3 +165,11 @@ export const transformImportEqualsDeclaration: FunctionVisitor = (node, context) => { + importLuaLibFeature(context, LuaLibFeature.Promise); + + const moduleRequire = + node.arguments.length > 0 ? createModuleRequire(context, node.arguments[0], node) : lua.createNilLiteral(); + return lua.createCallExpression(createStaticPromiseFunctionAccessor("resolve", node), [moduleRequire], node); +}; diff --git a/src/transformation/visitors/namespace.ts b/src/transformation/visitors/namespace.ts index d41aefd75..49a3f2289 100644 --- a/src/transformation/visitors/namespace.ts +++ b/src/transformation/visitors/namespace.ts @@ -1,24 +1,32 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { AnnotationKind, getTypeAnnotations } from "../utils/annotations"; -import { annotationRemoved } from "../utils/diagnostics"; import { addExportToIdentifier, createExportedIdentifier, getIdentifierExportScope } from "../utils/export"; import { createHoistableVariableDeclarationStatement, createLocalOrExportedOrGlobalDeclaration, } from "../utils/lua-ast"; import { createSafeName, isUnsafeName } from "../utils/safe-names"; -import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; +import { performHoisting, ScopeType } from "../utils/scope"; import { getSymbolIdOfSymbol } from "../utils/symbols"; import { transformIdentifier } from "./identifier"; +export function createModuleLocalName(context: TransformationContext, module: ts.ModuleDeclaration): lua.Expression { + if (!ts.isSourceFile(module.parent) && ts.isModuleDeclaration(module.parent)) { + const parentDeclaration = createModuleLocalName(context, module.parent); + const name = createModuleLocalNameIdentifier(context, module); + return lua.createTableIndexExpression(parentDeclaration, lua.createStringLiteral(name.text), module.name); + } + + return createModuleLocalNameIdentifier(context, module); +} + export function createModuleLocalNameIdentifier( context: TransformationContext, declaration: ts.ModuleDeclaration ): lua.Identifier { const moduleSymbol = context.checker.getSymbolAtLocation(declaration.name); - if (moduleSymbol !== undefined && isUnsafeName(moduleSymbol.name)) { + if (moduleSymbol !== undefined && isUnsafeName(moduleSymbol.name, context.options)) { return lua.createIdentifier( createSafeName(declaration.name.text), declaration.name, @@ -27,7 +35,6 @@ export function createModuleLocalNameIdentifier( ); } - // TODO: Should synthetic name nodes be escaped as well? return transformIdentifier(context, declaration.name as ts.Identifier); } @@ -47,17 +54,8 @@ function moduleHasEmittedBody( return false; } -// Static context -> namespace dictionary keeping the current namespace for each transformation context -const currentNamespaces = new WeakMap(); - export const transformModuleDeclaration: FunctionVisitor = (node, context) => { - const annotations = getTypeAnnotations(context.checker.getTypeAtLocation(node)); - // If phantom namespace elide the declaration and return the body - if (annotations.has(AnnotationKind.Phantom)) { - context.diagnostics.push(annotationRemoved(node, AnnotationKind.Phantom)); - } - - const currentNamespace = currentNamespaces.get(context); + const currentNamespace = context.currentNamespaces; const result: lua.Statement[] = []; const symbol = context.checker.getSymbolAtLocation(node.name); @@ -115,20 +113,21 @@ export const transformModuleDeclaration: FunctionVisitor = // Set current namespace for nested NS // Keep previous namespace to reset after block transpilation - currentNamespaces.set(context, node); + + context.currentNamespaces = node; // Transform moduleblock to block and visit it if (moduleHasEmittedBody(node)) { - pushScope(context, ScopeType.Block); + context.pushScope(ScopeType.Block, node); const statements = performHoisting( context, context.transformStatements(ts.isModuleBlock(node.body) ? node.body.statements : node.body) ); - popScope(context); + context.popScope(); result.push(lua.createDoStatement(statements)); } - currentNamespaces.set(context, currentNamespace); + context.currentNamespaces = currentNamespace; return result; }; diff --git a/src/transformation/visitors/optional-chaining.ts b/src/transformation/visitors/optional-chaining.ts new file mode 100644 index 000000000..6d6deeb8d --- /dev/null +++ b/src/transformation/visitors/optional-chaining.ts @@ -0,0 +1,286 @@ +import * as ts from "typescript"; +import * as lua from "../../LuaAST"; +import { tempSymbolId, TransformationContext } from "../context"; +import { assert, assertNever } from "../../utils"; +import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { transformElementAccessExpressionWithCapture, transformPropertyAccessExpressionWithCapture } from "./access"; +import { shouldMoveToTemp } from "./expression-list"; +import { canBeFalsyWhenNotNull, expressionResultIsUsed } from "../utils/typescript"; +import { wrapInStatement } from "./expression-statement"; + +type NormalOptionalChain = ts.PropertyAccessChain | ts.ElementAccessChain | ts.CallChain; + +function skipNonNullChains(chain: ts.OptionalChain): NormalOptionalChain { + while (ts.isNonNullChain(chain)) { + chain = chain.expression as ts.OptionalChain; + } + return chain; +} + +function flattenChain(chain: ts.OptionalChain) { + chain = skipNonNullChains(chain); + const links: NormalOptionalChain[] = [chain]; + while (!chain.questionDotToken && !ts.isTaggedTemplateExpression(chain)) { + const nextLink: ts.Expression = chain.expression; + assert(ts.isOptionalChain(nextLink)); + chain = skipNonNullChains(nextLink); + links.unshift(chain); + } + return { expression: chain.expression, chain: links }; +} + +export interface ExpressionWithThisValue { + expression: lua.Expression; + thisValue?: lua.Expression; +} + +function transformExpressionWithThisValueCapture( + context: TransformationContext, + node: ts.Expression, + thisValueCapture: lua.Identifier +): ExpressionWithThisValue { + if (ts.isParenthesizedExpression(node)) { + return transformExpressionWithThisValueCapture(context, node.expression, thisValueCapture); + } + if (ts.isPropertyAccessExpression(node)) { + return transformPropertyAccessExpressionWithCapture(context, node, thisValueCapture); + } + if (ts.isElementAccessExpression(node)) { + return transformElementAccessExpressionWithCapture(context, node, thisValueCapture); + } + return { expression: context.transformExpression(node) }; +} + +// returns thisValueCapture exactly if a temp variable was used. +export function captureThisValue( + context: TransformationContext, + expression: lua.Expression, + thisValueCapture: lua.Identifier, + tsOriginal: ts.Node +): lua.Expression { + if (!shouldMoveToTemp(context, expression, tsOriginal)) { + return expression; + } + const tempAssignment = lua.createAssignmentStatement(thisValueCapture, expression, tsOriginal); + context.addPrecedingStatements(tempAssignment); + return thisValueCapture; +} + +export interface OptionalContinuation { + contextualCall?: lua.CallExpression; + usedIdentifiers: lua.Identifier[]; +} + +const optionalContinuations = new WeakMap(); + +// should be translated verbatim to lua +function createOptionalContinuationIdentifier(text: string, tsOriginal: ts.Expression): ts.Identifier { + const identifier = ts.factory.createIdentifier(text); + ts.setOriginalNode(identifier, tsOriginal); + optionalContinuations.set(identifier, { + usedIdentifiers: [], + }); + return identifier; +} + +export function isOptionalContinuation(node: ts.Node): boolean { + return ts.isIdentifier(node) && optionalContinuations.has(node); +} + +export function getOptionalContinuationData(identifier: ts.Identifier): OptionalContinuation | undefined { + return optionalContinuations.get(identifier); +} + +export function transformOptionalChain(context: TransformationContext, node: ts.OptionalChain): lua.Expression { + return transformOptionalChainWithCapture(context, node, undefined).expression; +} + +export function transformOptionalChainWithCapture( + context: TransformationContext, + tsNode: ts.OptionalChain, + thisValueCapture: lua.Identifier | undefined, + isDelete?: ts.DeleteExpression +): ExpressionWithThisValue { + const luaTempName = context.createTempName("opt"); + + const { expression: tsLeftExpression, chain } = flattenChain(tsNode); + + // build temp.b.c.d + const tsTemp = createOptionalContinuationIdentifier(luaTempName, tsLeftExpression); + let tsRightExpression: ts.Expression = tsTemp; + for (const link of chain) { + if (ts.isPropertyAccessExpression(link)) { + tsRightExpression = ts.factory.createPropertyAccessExpression(tsRightExpression, link.name); + } else if (ts.isElementAccessExpression(link)) { + tsRightExpression = ts.factory.createElementAccessExpression(tsRightExpression, link.argumentExpression); + } else if (ts.isCallExpression(link)) { + tsRightExpression = ts.factory.createCallExpression(tsRightExpression, undefined, link.arguments); + } else { + assertNever(link); + } + ts.setOriginalNode(tsRightExpression, link); + } + if (isDelete) { + tsRightExpression = ts.factory.createDeleteExpression(tsRightExpression); + ts.setOriginalNode(tsRightExpression, isDelete); + } + + // transform right expression first to check if thisValue capture is needed + // capture and return thisValue if requested from outside + let returnThisValue: lua.Expression | undefined; + const { precedingStatements: rightPrecedingStatements, result: rightExpression } = + transformInPrecedingStatementScope(context, () => { + if (!thisValueCapture) { + return context.transformExpression(tsRightExpression); + } + + const { expression: result, thisValue } = transformExpressionWithThisValueCapture( + context, + tsRightExpression, + thisValueCapture + ); + returnThisValue = thisValue; + return result; + }); + + // transform left expression, handle thisValue if needed by rightExpression + const thisValueCaptureName = context.createTempName("this"); + const leftThisValueTemp = lua.createIdentifier(thisValueCaptureName, undefined, tempSymbolId); + let capturedThisValue: lua.Expression | undefined; + + const optionalContinuationData = getOptionalContinuationData(tsTemp); + const rightContextualCall = optionalContinuationData?.contextualCall; + const { precedingStatements: leftPrecedingStatements, result: leftExpression } = transformInPrecedingStatementScope( + context, + () => { + let result: lua.Expression; + if (rightContextualCall) { + ({ expression: result, thisValue: capturedThisValue } = transformExpressionWithThisValueCapture( + context, + tsLeftExpression, + leftThisValueTemp + )); + } else { + result = context.transformExpression(tsLeftExpression); + } + return result; + } + ); + + // handle super calls by passing self as context + function getLeftMostChainItem(node: ts.Node): ts.Node { + if (ts.isPropertyAccessExpression(node)) { + return getLeftMostChainItem(node.expression); + } else { + return node; + } + } + if (getLeftMostChainItem(tsLeftExpression).kind === ts.SyntaxKind.SuperKeyword) { + capturedThisValue = lua.createIdentifier("self"); + } + + // handle context + if (rightContextualCall) { + if (capturedThisValue) { + rightContextualCall.params[0] = capturedThisValue; + if (capturedThisValue === leftThisValueTemp) { + context.addPrecedingStatements(lua.createVariableDeclarationStatement(leftThisValueTemp)); + } + } else { + if (context.isStrict) { + rightContextualCall.params[0] = lua.createNilLiteral(); + } else { + const identifier = lua.createIdentifier("_G"); + if (rightPrecedingStatements.length === 0) { + rightContextualCall.params[0] = identifier; + } else { + const tempContext = context.createTempNameForLuaExpression(identifier); + rightPrecedingStatements.unshift(lua.createVariableDeclarationStatement(tempContext, identifier)); + rightContextualCall.params[0] = tempContext; + } + } + } + } + + // evaluate optional chain + context.addPrecedingStatements(leftPrecedingStatements); + + // try use existing variable instead of creating new one, if possible + let leftIdentifier: lua.Identifier | undefined; + const usedLuaIdentifiers = optionalContinuationData?.usedIdentifiers; + const reuseLeftIdentifier = + usedLuaIdentifiers && + usedLuaIdentifiers.length > 0 && + lua.isIdentifier(leftExpression) && + (rightPrecedingStatements.length === 0 || !shouldMoveToTemp(context, leftExpression, tsLeftExpression)); + if (reuseLeftIdentifier) { + leftIdentifier = leftExpression; + for (const usedIdentifier of usedLuaIdentifiers) { + usedIdentifier.text = leftIdentifier.text; + } + } else { + leftIdentifier = lua.createIdentifier(luaTempName, undefined, tempSymbolId); + context.addPrecedingStatements(lua.createVariableDeclarationStatement(leftIdentifier, leftExpression)); + } + + if (!expressionResultIsUsed(tsNode) || isDelete) { + // if left ~= nil then + // + // + // end + + const innerExpression = wrapInStatement(rightExpression); + const innerStatements = rightPrecedingStatements; + if (innerExpression) innerStatements.push(innerExpression); + + context.addPrecedingStatements( + lua.createIfStatement( + lua.createBinaryExpression(leftIdentifier, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator), + lua.createBlock(innerStatements) + ) + ); + return { expression: lua.createNilLiteral(), thisValue: returnThisValue }; + } else if ( + rightPrecedingStatements.length === 0 && + !canBeFalsyWhenNotNull(context, context.checker.getTypeAtLocation(tsLeftExpression)) + ) { + // return a && a.b + return { + expression: lua.createBinaryExpression(leftIdentifier, rightExpression, lua.SyntaxKind.AndOperator, tsNode), + thisValue: returnThisValue, + }; + } else { + let resultIdentifier: lua.Identifier; + if (!reuseLeftIdentifier) { + // reuse temp variable for output + resultIdentifier = leftIdentifier; + } else { + resultIdentifier = lua.createIdentifier(context.createTempName("opt_result"), undefined, tempSymbolId); + context.addPrecedingStatements(lua.createVariableDeclarationStatement(resultIdentifier)); + } + // if left ~= nil then + // + // result = + // end + // return result + context.addPrecedingStatements( + lua.createIfStatement( + lua.createBinaryExpression(leftIdentifier, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator), + lua.createBlock([ + ...rightPrecedingStatements, + lua.createAssignmentStatement(resultIdentifier, rightExpression), + ]) + ) + ); + return { expression: resultIdentifier, thisValue: returnThisValue }; + } +} + +export function transformOptionalDeleteExpression( + context: TransformationContext, + node: ts.DeleteExpression, + innerExpression: ts.OptionalChain +) { + transformOptionalChainWithCapture(context, innerExpression, undefined, node); + return lua.createBooleanLiteral(true, node); +} diff --git a/src/transformation/visitors/return.ts b/src/transformation/visitors/return.ts index f309874f7..3a61314ff 100644 --- a/src/transformation/visitors/return.ts +++ b/src/transformation/visitors/return.ts @@ -1,11 +1,9 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { isInTupleReturnFunction, isTupleReturnCall } from "../utils/annotations"; import { validateAssignment } from "../utils/assignment-validation"; import { createUnpackCall, wrapInTable } from "../utils/lua-ast"; -import { ScopeType, walkScopesUp } from "../utils/scope"; -import { isArrayType } from "../utils/typescript"; +import { findAsyncTryScopeInStack, ScopeType, walkScopesUp } from "../utils/scope"; import { transformArguments } from "./call"; import { returnsMultiType, @@ -13,88 +11,67 @@ import { isMultiFunctionCall, isMultiReturnType, isInMultiReturnFunction, + canBeMultiReturnType, } from "./language-extensions/multi"; import { invalidMultiFunctionReturnType } from "../utils/diagnostics"; +import { isInAsyncFunction } from "../utils/typescript"; -function transformExpressionsInReturn( - context: TransformationContext, - node: ts.Expression, - insideTryCatch: boolean -): lua.Expression[] { +function transformExpressionsInReturn(context: TransformationContext, node: ts.Expression): lua.Expression[] { const expressionType = context.checker.getTypeAtLocation(node); - if (ts.isCallExpression(node)) { + // skip type assertions + // don't skip parenthesis as it may arise confusion with lua behavior (where parenthesis are significant) + const innerNode = ts.skipOuterExpressions(node, ts.OuterExpressionKinds.Assertions); + + if (ts.isCallExpression(innerNode)) { // $multi(...) - if (isMultiFunctionCall(context, node)) { + if (isMultiFunctionCall(context, innerNode)) { // Don't allow $multi to be implicitly cast to something other than LuaMultiReturn const type = context.checker.getContextualType(node); - if (type && !isMultiReturnType(type)) { - context.diagnostics.push(invalidMultiFunctionReturnType(node)); + if (type && !canBeMultiReturnType(type)) { + context.diagnostics.push(invalidMultiFunctionReturnType(innerNode)); } - let returnValues = transformArguments(context, node.arguments); - if (insideTryCatch) { - returnValues = [wrapInTable(...returnValues)]; // Wrap results when returning inside try/catch - } - return returnValues; + return transformArguments(context, innerNode.arguments); } - - // Force-wrap LuaMultiReturn when returning inside try/catch - if (insideTryCatch && returnsMultiType(context, node) && !shouldMultiReturnCallBeWrapped(context, node)) { - return [wrapInTable(context.transformExpression(node))]; - } - } else if (isInMultiReturnFunction(context, node) && isMultiReturnType(expressionType)) { + } else if (isInMultiReturnFunction(context, innerNode) && isMultiReturnType(expressionType)) { // Unpack objects typed as LuaMultiReturn - return [createUnpackCall(context, context.transformExpression(node), node)]; - } - - if (!isInTupleReturnFunction(context, node)) { - return [context.transformExpression(node)]; - } - - let results: lua.Expression[]; - - // Parent function is a TupleReturn function - if (ts.isArrayLiteralExpression(node)) { - // If return expression is an array literal, leave out brackets. - results = node.elements.map(e => context.transformExpression(e)); - } else if (!isTupleReturnCall(context, node) && isArrayType(context, expressionType)) { - // If return expression is an array-type and not another TupleReturn call, unpack it - results = [createUnpackCall(context, context.transformExpression(node), node)]; - } else { - results = [context.transformExpression(node)]; - } - - // Wrap tupleReturn results when returning inside try/catch - if (insideTryCatch) { - results = [wrapInTable(...results)]; + return [createUnpackCall(context, context.transformExpression(innerNode), innerNode)]; } - return results; + return [context.transformExpression(node)]; } export function transformExpressionBodyToReturnStatement( context: TransformationContext, node: ts.Expression ): lua.Statement { - const expressions = transformExpressionsInReturn(context, node, false); - return lua.createReturnStatement(expressions, node); + const expressions = transformExpressionsInReturn(context, node); + return createReturnStatement(context, expressions, node); } -export const transformReturnStatement: FunctionVisitor = (statement, context) => { - // Bubble up explicit return flag and check if we're inside a try/catch block - let insideTryCatch = false; - for (const scope of walkScopesUp(context)) { - scope.functionReturned = true; +function transformReturnExpressionForTryCatch(context: TransformationContext, node: ts.Expression): lua.Expression { + const innerNode = ts.skipOuterExpressions(node, ts.OuterExpressionKinds.Assertions); - if (scope.type === ScopeType.Function) { - break; + if (ts.isCallExpression(innerNode)) { + if (isMultiFunctionCall(context, innerNode)) { + const type = context.checker.getContextualType(node); + if (type && !canBeMultiReturnType(type)) { + context.diagnostics.push(invalidMultiFunctionReturnType(innerNode)); + } + return wrapInTable(...transformArguments(context, innerNode.arguments)); } - insideTryCatch = insideTryCatch || scope.type === ScopeType.Try || scope.type === ScopeType.Catch; + if (returnsMultiType(context, innerNode) && !shouldMultiReturnCallBeWrapped(context, innerNode)) { + return wrapInTable(context.transformExpression(node)); + } } - let results: lua.Expression[]; + return context.transformExpression(node); +} + +export const transformReturnStatement: FunctionVisitor = (statement, context) => { + const asyncTryScope = isInAsyncFunction(statement) ? findAsyncTryScopeInStack(context) : undefined; if (statement.expression) { const expressionType = context.checker.getTypeAtLocation(statement.expression); @@ -102,16 +79,68 @@ export const transformReturnStatement: FunctionVisitor = (st if (returnType) { validateAssignment(context, statement, expressionType, returnType); } + } - results = transformExpressionsInReturn(context, statement.expression, insideTryCatch); - } else { - // Empty return - results = []; + if (asyncTryScope) { + asyncTryScope.asyncTryHasReturn = true; + const stmts: lua.Statement[] = [ + lua.createAssignmentStatement( + lua.createIdentifier("____hasReturned"), + lua.createBooleanLiteral(true), + statement + ), + ]; + if (statement.expression) { + const returnValue = transformReturnExpressionForTryCatch(context, statement.expression); + stmts.push(lua.createAssignmentStatement(lua.createIdentifier("____returnValue"), returnValue, statement)); + } + stmts.push(lua.createReturnStatement([], statement)); + return stmts; } - if (insideTryCatch) { - results.unshift(lua.createBooleanLiteral(true)); + let results: lua.Expression[]; + if (!statement.expression) { + results = []; + } else if (isInTryCatch(context)) { + results = [transformReturnExpressionForTryCatch(context, statement.expression)]; + } else { + results = transformExpressionsInReturn(context, statement.expression); } - return lua.createReturnStatement(results, statement); + return createReturnStatement(context, results, statement); }; + +export function createReturnStatement( + context: TransformationContext, + values: lua.Expression[], + node: ts.Node +): lua.ReturnStatement { + if (isInAsyncFunction(node)) { + return lua.createReturnStatement([ + lua.createCallExpression(lua.createIdentifier("____awaiter_resolve"), [lua.createNilLiteral(), ...values]), + ]); + } + + if (isInTryCatch(context)) { + // Bubble up explicit return flag and check if we're inside a try/catch block + values = [lua.createBooleanLiteral(true), ...values]; + } + + return lua.createReturnStatement(values, node); +} + +function isInTryCatch(context: TransformationContext): boolean { + // Check if context is in a try or catch + let insideTryCatch = false; + for (const scope of walkScopesUp(context)) { + scope.functionReturned = true; + + if (scope.type === ScopeType.Function) { + break; + } + + insideTryCatch = insideTryCatch || scope.type === ScopeType.Try || scope.type === ScopeType.Catch; + } + + return insideTryCatch; +} diff --git a/src/transformation/visitors/sourceFile.ts b/src/transformation/visitors/sourceFile.ts index 604aa0c7e..2fe860f53 100644 --- a/src/transformation/visitors/sourceFile.ts +++ b/src/transformation/visitors/sourceFile.ts @@ -3,8 +3,8 @@ import * as lua from "../../LuaAST"; import { assert } from "../../utils"; import { FunctionVisitor } from "../context"; import { createExportsIdentifier } from "../utils/lua-ast"; -import { getUsedLuaLibFeatures } from "../utils/lualib"; -import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; +import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { performHoisting, ScopeType } from "../utils/scope"; import { hasExportEquals } from "../utils/typescript"; export const transformSourceFileNode: FunctionVisitor = (node, context) => { @@ -13,7 +13,11 @@ export const transformSourceFileNode: FunctionVisitor = (node, co const [statement] = node.statements; if (statement) { assert(ts.isExpressionStatement(statement)); - statements.push(lua.createReturnStatement([context.transformExpression(statement.expression)])); + const { precedingStatements, result: expression } = transformInPrecedingStatementScope(context, () => + context.transformExpression(statement.expression) + ); + statements.push(...precedingStatements); + statements.push(lua.createReturnStatement([expression])); } else { const errorCall = lua.createCallExpression(lua.createIdentifier("error"), [ lua.createStringLiteral("Unexpected end of JSON input"), @@ -22,9 +26,10 @@ export const transformSourceFileNode: FunctionVisitor = (node, co statements.push(lua.createExpressionStatement(errorCall)); } } else { - pushScope(context, ScopeType.File); + context.pushScope(ScopeType.File, node); + statements = performHoisting(context, context.transformStatements(node.statements)); - popScope(context); + context.popScope(); if (context.isModule) { // If export equals was not used. Create the exports table. @@ -41,5 +46,5 @@ export const transformSourceFileNode: FunctionVisitor = (node, co } const trivia = node.getFullText().match(/^#!.*\r?\n/)?.[0] ?? ""; - return lua.createFile(statements, getUsedLuaLibFeatures(context), trivia, node); + return lua.createFile(statements, context.usedLuaLibFeatures, trivia, node); }; diff --git a/src/transformation/visitors/spread.ts b/src/transformation/visitors/spread.ts index d9da3ce44..b10a0ae6e 100644 --- a/src/transformation/visitors/spread.ts +++ b/src/transformation/visitors/spread.ts @@ -1,23 +1,18 @@ import * as ts from "typescript"; +import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; +import { assertNever } from "../../utils"; import { FunctionVisitor, TransformationContext } from "../context"; -import { AnnotationKind, isTupleReturnCall, isVarargType } from "../utils/annotations"; +import { getIterableExtensionKindForNode, IterableExtensionKind } from "../utils/language-extensions"; import { createUnpackCall } from "../utils/lua-ast"; import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; -import { - findScope, - hasReferencedSymbol, - hasReferencedUndefinedLocalFunction, - isFunctionScopeWithDefinition, - ScopeType, -} from "../utils/scope"; -import { isArrayType } from "../utils/typescript"; -import { returnsMultiType } from "./language-extensions/multi"; -import { annotationRemoved } from "../utils/diagnostics"; +import { findScope, hasReferencedSymbol, hasReferencedUndefinedLocalFunction, ScopeType } from "../utils/scope"; +import { findFirstNonOuterParent, isAlwaysArrayType } from "../utils/typescript"; +import { isMultiReturnCall } from "./language-extensions/multi"; import { isGlobalVarargConstant } from "./language-extensions/vararg"; export function isOptimizedVarArgSpread(context: TransformationContext, symbol: ts.Symbol, identifier: ts.Identifier) { - if (!ts.isSpreadElement(identifier.parent)) { + if (!ts.isSpreadElement(findFirstNonOuterParent(identifier))) { return false; } @@ -33,7 +28,15 @@ export function isOptimizedVarArgSpread(context: TransformationContext, symbol: } // Scope must be a function scope associated with a real ts function - if (!isFunctionScopeWithDefinition(scope)) { + if (!ts.isFunctionLike(scope.node)) { + return false; + } + + // Scope cannot be an async function + if ( + ts.canHaveModifiers(scope.node) && + ts.getModifiers(scope.node)?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) + ) { return false; } @@ -58,22 +61,37 @@ export function isOptimizedVarArgSpread(context: TransformationContext, symbol: // TODO: Currently it's also used as an array member export const transformSpreadElement: FunctionVisitor = (node, context) => { - if (ts.isIdentifier(node.expression)) { - if (isVarargType(context, node.expression)) { - context.diagnostics.push(annotationRemoved(node, AnnotationKind.Vararg)); - } - const symbol = context.checker.getSymbolAtLocation(node.expression); - if (symbol && isOptimizedVarArgSpread(context, symbol, node.expression)) { - return lua.createDotsLiteral(node); + const tsInnerExpression = ts.skipOuterExpressions(node.expression); + if (ts.isIdentifier(tsInnerExpression)) { + const symbol = context.checker.getSymbolAtLocation(tsInnerExpression); + if (symbol && isOptimizedVarArgSpread(context, symbol, tsInnerExpression)) { + return context.luaTarget === LuaTarget.Lua50 + ? createUnpackCall(context, lua.createArgLiteral(), node) + : lua.createDotsLiteral(node); } } const innerExpression = context.transformExpression(node.expression); - if (isTupleReturnCall(context, node.expression)) return innerExpression; - if (ts.isCallExpression(node.expression) && returnsMultiType(context, node.expression)) return innerExpression; + if (isMultiReturnCall(context, tsInnerExpression)) return innerExpression; + + const iterableExtensionType = getIterableExtensionKindForNode(context, node.expression); + if (iterableExtensionType) { + if (iterableExtensionType === IterableExtensionKind.Iterable) { + return transformLuaLibFunction(context, LuaLibFeature.LuaIteratorSpread, node, innerExpression); + } else if (iterableExtensionType === IterableExtensionKind.Pairs) { + const objectEntries = transformLuaLibFunction(context, LuaLibFeature.ObjectEntries, node, innerExpression); + return createUnpackCall(context, objectEntries, node); + } else if (iterableExtensionType === IterableExtensionKind.PairsKey) { + const objectKeys = transformLuaLibFunction(context, LuaLibFeature.ObjectKeys, node, innerExpression); + return createUnpackCall(context, objectKeys, node); + } else { + assertNever(iterableExtensionType); + } + } - const type = context.checker.getTypeAtLocation(node.expression); - if (isArrayType(context, type)) { + const type = context.checker.getTypeAtLocation(node.expression); // not ts-inner expression, in case of casts + if (isAlwaysArrayType(context, type)) { + // All union members must be arrays to be able to shortcut to unpack call return createUnpackCall(context, innerExpression, node); } diff --git a/src/transformation/visitors/switch.ts b/src/transformation/visitors/switch.ts index a82ff0bf0..cee8b7f57 100644 --- a/src/transformation/visitors/switch.ts +++ b/src/transformation/visitors/switch.ts @@ -1,61 +1,269 @@ import * as ts from "typescript"; -import { LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; -import { FunctionVisitor } from "../context"; -import { unsupportedForTarget } from "../utils/diagnostics"; -import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope"; +import { FunctionVisitor, TransformationContext } from "../context"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../utils/preceding-statements"; +import { ScopeType, separateHoistedStatements } from "../utils/scope"; +import { createShortCircuitBinaryExpressionPrecedingStatements } from "./binary-expression"; -export const transformSwitchStatement: FunctionVisitor = (statement, context) => { - if (context.luaTarget === LuaTarget.Universal || context.luaTarget === LuaTarget.Lua51) { - context.diagnostics.push(unsupportedForTarget(statement, "Switch statements", LuaTarget.Lua51)); +const containsBreakOrReturn = (nodes: Iterable): boolean => { + for (const s of nodes) { + if (ts.isBreakStatement(s) || ts.isReturnStatement(s)) { + return true; + } else if (ts.isBlock(s) && containsBreakOrReturn(s.statements)) { + return true; + } else if (s.kind === ts.SyntaxKind.SyntaxList) { + // We cannot use getChildren() because that breaks when using synthetic nodes from transformers + // So get children the long way + const children: ts.Node[] = []; + ts.forEachChild(s, c => children.push(c)); + if (containsBreakOrReturn(children)) { + return true; + } + } + } + + return false; +}; + +const createOrExpression = ( + context: TransformationContext, + left: lua.Expression, + right: lua.Expression, + rightPrecedingStatements: lua.Statement[] +): WithPrecedingStatements => { + if (rightPrecedingStatements.length > 0) { + return createShortCircuitBinaryExpressionPrecedingStatements( + context, + left, + right, + rightPrecedingStatements, + ts.SyntaxKind.BarBarToken + ); + } else { + return { + precedingStatements: rightPrecedingStatements, + result: lua.createBinaryExpression(left, right, lua.SyntaxKind.OrOperator), + }; } +}; - const scope = pushScope(context, ScopeType.Switch); +const coalesceCondition = ( + condition: lua.Expression | undefined, + conditionPrecedingStatements: lua.Statement[], + switchVariable: lua.Identifier, + expression: ts.Expression, + context: TransformationContext +): WithPrecedingStatements => { + const { precedingStatements, result: transformedExpression } = transformInPrecedingStatementScope(context, () => + context.transformExpression(expression) + ); - // Give the switch a unique name to prevent nested switches from acting up. + // Coalesce skipped statements + const comparison = lua.createBinaryExpression( + switchVariable, + transformedExpression, + lua.SyntaxKind.EqualityOperator + ); + if (condition) { + return createOrExpression(context, condition, comparison, precedingStatements); + } + + // Next condition + return { precedingStatements: [...conditionPrecedingStatements, ...precedingStatements], result: comparison }; +}; + +export const transformSwitchStatement: FunctionVisitor = (statement, context) => { + const scope = context.pushScope(ScopeType.Switch, statement); + + // Give the switch and condition accumulator a unique name to prevent nested switches from acting up. const switchName = `____switch${scope.id}`; + const conditionName = `____cond${scope.id}`; const switchVariable = lua.createIdentifier(switchName); + const conditionVariable = lua.createIdentifier(conditionName); - let statements: lua.Statement[] = []; + // If the switch only has a default clause, wrap it in a single do. + // Otherwise, we need to generate a set of if statements to emulate the switch. + const statements: lua.Statement[] = []; + const hoistedStatements: lua.Statement[] = []; + const hoistedIdentifiers: lua.Identifier[] = []; + const clauses = statement.caseBlock.clauses; + if (clauses.length === 1 && ts.isDefaultClause(clauses[0])) { + const defaultClause = clauses[0].statements; + if (defaultClause.length) { + const { + statements: defaultStatements, + hoistedStatements: defaultHoistedStatements, + hoistedIdentifiers: defaultHoistedIdentifiers, + } = separateHoistedStatements(context, context.transformStatements(defaultClause)); + hoistedStatements.push(...defaultHoistedStatements); + hoistedIdentifiers.push(...defaultHoistedIdentifiers); + statements.push(lua.createDoStatement(defaultStatements)); + } + } else { + // Build up the condition for each if statement + let defaultTransformed = false; + let isInitialCondition = true; + let condition: lua.Expression | undefined = undefined; + let conditionPrecedingStatements: lua.Statement[] = []; + for (let i = 0; i < clauses.length; i++) { + const clause = clauses[i]; + const previousClause: ts.CaseOrDefaultClause | undefined = clauses[i - 1]; - // Starting from the back, concatenating ifs into one big if/elseif statement - const concatenatedIf = statement.caseBlock.clauses.reduceRight((previousCondition, clause, index) => { - if (ts.isDefaultClause(clause)) { - // Skip default clause here (needs to be included to ensure index lines up with index later) - return previousCondition; + // Skip redundant default clauses, will be handled in final default case + if (i === 0 && ts.isDefaultClause(clause)) continue; + if (ts.isDefaultClause(clause) && previousClause && containsBreakOrReturn(previousClause.statements)) { + continue; + } + + // Compute the condition for the if statement + if (!ts.isDefaultClause(clause)) { + const { precedingStatements, result } = coalesceCondition( + condition, + conditionPrecedingStatements, + switchVariable, + clause.expression, + context + ); + conditionPrecedingStatements = precedingStatements; + condition = result; + + // Skip empty clauses unless final clause (i.e side-effects) + if (i !== clauses.length - 1 && clause.statements.length === 0) continue; + + // Declare or assign condition variable + if (isInitialCondition) { + statements.push( + ...conditionPrecedingStatements, + lua.createVariableDeclarationStatement(conditionVariable, condition) + ); + } else { + const { precedingStatements, result } = createOrExpression( + context, + conditionVariable, + condition, + conditionPrecedingStatements + ); + conditionPrecedingStatements = precedingStatements; + condition = result; + + statements.push( + ...conditionPrecedingStatements, + lua.createAssignmentStatement(conditionVariable, condition) + ); + } + isInitialCondition = false; + } else { + // If the default is proceeded by empty clauses and will be emitted we may need to initialize the condition + if (isInitialCondition) { + statements.push( + ...conditionPrecedingStatements, + lua.createVariableDeclarationStatement( + conditionVariable, + condition ?? lua.createBooleanLiteral(false) + ) + ); + + // Clear condition ot ensure it is not evaluated twice + condition = undefined; + conditionPrecedingStatements = []; + isInitialCondition = false; + } + + // Allow default to fallthrough to final default clause + if (i === clauses.length - 1) { + // Evaluate the final condition that we may be skipping + if (condition) { + const { precedingStatements, result } = createOrExpression( + context, + conditionVariable, + condition, + conditionPrecedingStatements + ); + conditionPrecedingStatements = precedingStatements; + condition = result; + statements.push( + ...conditionPrecedingStatements, + lua.createAssignmentStatement(conditionVariable, condition) + ); + } + continue; + } + } + + // Transform the clause and append the final break statement if necessary + const { + statements: clauseStatements, + hoistedStatements: clauseHoistedStatements, + hoistedIdentifiers: clauseHoistedIdentifiers, + } = separateHoistedStatements(context, context.transformStatements(clause.statements)); + if (i === clauses.length - 1 && !containsBreakOrReturn(clause.statements)) { + clauseStatements.push(lua.createBreakStatement()); + } + hoistedStatements.push(...clauseHoistedStatements); + hoistedIdentifiers.push(...clauseHoistedIdentifiers); + + // Remember that we transformed default clause so we don't duplicate hoisted statements later + if (ts.isDefaultClause(clause)) { + defaultTransformed = true; + } + + // Push if statement for case + statements.push(lua.createIfStatement(conditionVariable, lua.createBlock(clauseStatements))); + + // Clear condition for next clause + condition = undefined; + conditionPrecedingStatements = []; } - // If the clause condition holds, go to the correct label - const condition = lua.createBinaryExpression( - switchVariable, - context.transformExpression(clause.expression), - lua.SyntaxKind.EqualityOperator - ); + // If no conditions above match, we need to create the final default case code-path, + // as we only handle fallthrough into defaults in the previous if statement chain + const start = clauses.findIndex(c => ts.isDefaultClause(c)); + if (start >= 0) { + // Find the last clause that we can fallthrough to + const end = clauses.findIndex( + (clause, index) => index >= start && containsBreakOrReturn(clause.statements) + ); - const goto = lua.createGotoStatement(`${switchName}_case_${index}`); - return lua.createIfStatement(condition, lua.createBlock([goto]), previousCondition); - }, undefined as lua.IfStatement | undefined); + const { + statements: defaultStatements, + hoistedStatements: defaultHoistedStatements, + hoistedIdentifiers: defaultHoistedIdentifiers, + } = separateHoistedStatements(context, context.transformStatements(clauses[start].statements)); - if (concatenatedIf) { - statements.push(concatenatedIf); - } + // Only push hoisted statements if this is the first time we're transforming the default clause + if (!defaultTransformed) { + hoistedStatements.push(...defaultHoistedStatements); + hoistedIdentifiers.push(...defaultHoistedIdentifiers); + } - const hasDefaultCase = statement.caseBlock.clauses.some(ts.isDefaultClause); - statements.push(lua.createGotoStatement(`${switchName}_${hasDefaultCase ? "case_default" : "end"}`)); + // Combine the fallthrough statements + for (const clause of clauses.slice(start + 1, end >= 0 ? end + 1 : undefined)) { + let statements = context.transformStatements(clause.statements); + // Drop hoisted statements as they were already added when clauses were initially transformed above + ({ statements } = separateHoistedStatements(context, statements)); + defaultStatements.push(...statements); + } - for (const [index, clause] of statement.caseBlock.clauses.entries()) { - const labelName = `${switchName}_case_${ts.isCaseClause(clause) ? index : "default"}`; - statements.push(lua.createLabelStatement(labelName)); - statements.push(lua.createDoStatement(context.transformStatements(clause.statements))); + // Add the default clause if it has any statements + // The switch will always break on the final clause and skip execution if valid to do so + if (defaultStatements.length) { + statements.push(lua.createDoStatement(defaultStatements)); + } + } } - statements.push(lua.createLabelStatement(`${switchName}_end`)); + // Hoist the variable, function, and import statements to the top of the switch + statements.unshift(...hoistedStatements); + if (hoistedIdentifiers.length > 0) { + statements.unshift(lua.createVariableDeclarationStatement(hoistedIdentifiers)); + } - statements = performHoisting(context, statements); - popScope(context); + context.popScope(); + // Add the switch expression after hoisting const expression = context.transformExpression(statement.expression); statements.unshift(lua.createVariableDeclarationStatement(switchVariable, expression)); - return statements; + // Wrap the statements in a repeat until true statement to facilitate dynamic break/returns + return lua.createRepeatStatement(lua.createBlock(statements), lua.createBooleanLiteral(true)); }; diff --git a/src/transformation/visitors/template.ts b/src/transformation/visitors/template.ts index 9f9a19b33..291c703d5 100644 --- a/src/transformation/visitors/template.ts +++ b/src/transformation/visitors/template.ts @@ -1,10 +1,11 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor } from "../context"; -import { ContextType, getDeclarationContextType } from "../utils/function-context"; +import { ContextType, getCallContextType } from "../utils/function-context"; import { wrapInToStringForConcat } from "../utils/lua-ast"; -import { isStringType } from "../utils/typescript/types"; +import { isStringType } from "../utils/typescript"; import { transformArguments, transformContextualCallExpression } from "./call"; +import { transformOrderedExpressions } from "./expression-list"; // TODO: Source positions function getRawLiteral(node: ts.LiteralLikeNode): string { @@ -24,8 +25,13 @@ export const transformTemplateExpression: FunctionVisitor parts.push(lua.createStringLiteral(head, node.head)); } - for (const span of node.templateSpans) { - const expression = context.transformExpression(span.expression); + const transformedExpressions = transformOrderedExpressions( + context, + node.templateSpans.map(s => s.expression) + ); + for (let i = 0; i < node.templateSpans.length; ++i) { + const span = node.templateSpans[i]; + const expression = transformedExpressions[i]; const spanType = context.checker.getTypeAtLocation(span.expression); if (isStringType(context, spanType)) { parts.push(expression); @@ -82,17 +88,14 @@ export const transformTaggedTemplateExpression: FunctionVisitor undefined, [ts.SyntaxKind.NonNullExpression]: (node, context) => context.transformExpression(node.expression), + [ts.SyntaxKind.ExpressionWithTypeArguments]: (node, context) => context.transformExpression(node.expression), + [ts.SyntaxKind.SatisfiesExpression]: (node, context) => context.transformExpression(node.expression), [ts.SyntaxKind.AsExpression]: transformAssertionExpression, [ts.SyntaxKind.TypeAssertionExpression]: transformAssertionExpression, [ts.SyntaxKind.NotEmittedStatement]: () => undefined, diff --git a/src/transformation/visitors/unary-expression.ts b/src/transformation/visitors/unary-expression.ts index 5960c2200..88b512757 100644 --- a/src/transformation/visitors/unary-expression.ts +++ b/src/transformation/visitors/unary-expression.ts @@ -7,6 +7,8 @@ import { transformCompoundAssignmentExpression, transformCompoundAssignmentStatement, } from "./binary-expression/compound"; +import { isNumberType } from "../utils/typescript"; +import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib"; export function transformUnaryExpressionStatement( context: TransformationContext, @@ -92,16 +94,29 @@ export const transformPrefixUnaryExpression: FunctionVisitor( + const tableExpression = propertyAccessStack.reduce( (path, property) => lua.createTableIndexExpression(path, transformPropertyName(context, property)), table ); @@ -64,7 +70,11 @@ export function transformBindingPattern( // The identifier of the new variable const variableName = transformIdentifier(context, element.name); // The field to extract - const propertyName = transformPropertyName(context, element.propertyName ?? element.name); + const elementName = element.propertyName ?? element.name; + const { precedingStatements, result: propertyName } = transformInPrecedingStatementScope(context, () => + transformPropertyName(context, elementName) + ); + result.push(...precedingStatements); // Keep property's preceding statements in order let expression: lua.Expression; if (element.dotDotDotToken) { @@ -124,11 +134,15 @@ export function transformBindingPattern( result.push(...createLocalOrExportedOrGlobalDeclaration(context, variableName, expression)); if (element.initializer) { const identifier = addExportToIdentifier(context, variableName); + const tsInitializer = element.initializer; + const { precedingStatements: initializerPrecedingStatements, result: initializer } = + transformInPrecedingStatementScope(context, () => context.transformExpression(tsInitializer)); result.push( lua.createIfStatement( lua.createBinaryExpression(identifier, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator), lua.createBlock([ - lua.createAssignmentStatement(identifier, context.transformExpression(element.initializer)), + ...initializerPrecedingStatements, + lua.createAssignmentStatement(identifier, initializer), ]) ) ); @@ -151,19 +165,21 @@ export function transformBindingVariableDeclaration( ts.isBindingElement(e) && (!ts.isIdentifier(e.name) || e.dotDotDotToken); if (ts.isObjectBindingPattern(bindingPattern) || bindingPattern.elements.some(isComplexBindingElement)) { - let table: lua.Identifier; - if (initializer !== undefined && ts.isIdentifier(initializer)) { - table = transformIdentifier(context, initializer); - } else { + let table: lua.Expression; + if (initializer) { // Contain the expression in a temporary variable - table = lua.createAnonymousIdentifier(); - if (initializer) { - let expression = context.transformExpression(initializer); - if (isTupleReturnCall(context, initializer) || isMultiReturnCall(context, initializer)) { - expression = wrapInTable(expression); - } - statements.push(lua.createVariableDeclarationStatement(table, expression)); + let expression = context.transformExpression(initializer); + if (isMultiReturnCall(context, initializer)) { + expression = wrapInTable(expression); } + const { precedingStatements: moveStatements, result: movedExpr } = transformInPrecedingStatementScope( + context, + () => moveToPrecedingTemp(context, expression, initializer) + ); + statements.push(...moveStatements); + table = movedExpr; + } else { + table = lua.createAnonymousIdentifier(); } statements.push(...transformBindingPattern(context, bindingPattern, table)); return statements; @@ -175,8 +191,8 @@ export function transformBindingVariableDeclaration( : lua.createAnonymousIdentifier(); if (initializer) { - if (isTupleReturnCall(context, initializer) || isMultiReturnCall(context, initializer)) { - // Don't unpack @tupleReturn or LuaMultiReturn functions + if (isMultiReturnCall(context, initializer)) { + // Don't unpack LuaMultiReturn functions statements.push( ...createLocalOrExportedOrGlobalDeclaration( context, @@ -189,14 +205,15 @@ export function transformBindingVariableDeclaration( // Don't unpack array literals const values = initializer.elements.length > 0 - ? initializer.elements.map(e => context.transformExpression(e)) + ? transformExpressionList(context, initializer.elements) : lua.createNilLiteral(); statements.push(...createLocalOrExportedOrGlobalDeclaration(context, vars, values, initializer)); } else { - // local vars = this.transpileDestructingAssignmentValue(node.initializer); - const unpackedInitializer = createUnpackCall( + // use unpack(thing, 1, #bindingItems) to unpack + const unpackedInitializer = createBoundedUnpackCall( context, context.transformExpression(initializer), + bindingPattern.elements.length, initializer ); statements.push( @@ -242,17 +259,32 @@ export function transformVariableDeclaration( // Find variable identifier const identifierName = transformIdentifier(context, statement.name); const value = statement.initializer && context.transformExpression(statement.initializer); - return createLocalOrExportedOrGlobalDeclaration(context, identifierName, value, statement); + + // Wrap functions being assigned to a type that contains additional properties in a callable table + // This catches 'const foo = function() {}; foo.bar = "FOOBAR";' + const wrappedValue = value && shouldWrapInitializerInCallableTable() ? createCallableTable(value) : value; + + return createLocalOrExportedOrGlobalDeclaration(context, identifierName, wrappedValue, statement); } else if (ts.isArrayBindingPattern(statement.name) || ts.isObjectBindingPattern(statement.name)) { return transformBindingVariableDeclaration(context, statement.name, statement.initializer); } else { return assertNever(statement.name); } + + function shouldWrapInitializerInCallableTable() { + assert(statement.initializer); + const initializer = ts.skipOuterExpressions(statement.initializer); + // do not wrap if not a function expression + if (!ts.isFunctionExpression(initializer) && !ts.isArrowFunction(initializer)) return false; + // Skip named function expressions because they will have been wrapped already + if (ts.isFunctionExpression(initializer) && initializer.name) return false; + return isFunctionTypeWithProperties(context, context.checker.getTypeAtLocation(statement.name)); + } } export function checkVariableDeclarationList(context: TransformationContext, node: ts.VariableDeclarationList): void { - if ((node.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) === 0) { - const token = node.getFirstToken(); + if ((node.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const | ts.NodeFlags.Using | ts.NodeFlags.AwaitUsing)) === 0) { + const token = ts.getOriginalNode(node).getFirstToken(); assert(token); context.diagnostics.push(unsupportedVarDeclaration(token)); } diff --git a/src/transformation/visitors/void.ts b/src/transformation/visitors/void.ts new file mode 100644 index 000000000..c942e859c --- /dev/null +++ b/src/transformation/visitors/void.ts @@ -0,0 +1,15 @@ +import * as ts from "typescript"; +import * as lua from "../../LuaAST"; +import { FunctionVisitor } from "../context"; +import { wrapInStatement } from "./expression-statement"; + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void +export const transformVoidExpression: FunctionVisitor = (node, context) => { + // If content is a literal it is safe to replace the entire expression with nil + if (!ts.isLiteralExpression(node.expression)) { + const statements = wrapInStatement(context.transformExpression(node.expression)); + if (statements) context.addPrecedingStatements(statements); + } + + return lua.createNilLiteral(); +}; diff --git a/src/transpilation/bundle.ts b/src/transpilation/bundle.ts index 579e84ee1..b030bddfe 100644 --- a/src/transpilation/bundle.ts +++ b/src/transpilation/bundle.ts @@ -1,28 +1,36 @@ import * as path from "path"; import { SourceNode } from "source-map"; import * as ts from "typescript"; -import { CompilerOptions } from "../CompilerOptions"; +import { CompilerOptions, LuaTarget } from "../CompilerOptions"; import { escapeString, tstlHeader } from "../LuaPrinter"; import { cast, formatPathToLuaPath, isNonNull, trimExtension } from "../utils"; import { couldNotFindBundleEntryPoint } from "./diagnostics"; -import { getEmitOutDir, getEmitPathRelativeToOutDir, getSourceDir } from "./transpiler"; +import { getEmitOutDir, getEmitPathRelativeToOutDir, getProjectRoot } from "./transpiler"; import { EmitFile, ProcessedFile } from "./utils"; const createModulePath = (pathToResolve: string, program: ts.Program) => escapeString(formatPathToLuaPath(trimExtension(getEmitPathRelativeToOutDir(pathToResolve, program)))); // Override `require` to read from ____modules table. -const requireOverride = ` +function requireOverride(options: CompilerOptions) { + const runModule = + options.luaTarget === LuaTarget.Lua50 + ? "if (table.getn(arg) > 0) then value = module(unpack(arg)) else value = module(file) end" + : 'if (select("#", ...) > 0) then value = module(...) else value = module(file) end'; + return ` local ____modules = {} local ____moduleCache = {} local ____originalRequire = require -local function require(file) +local function require(file, ...) if ____moduleCache[file] then - return ____moduleCache[file] + return ____moduleCache[file].value end if ____modules[file] then - ____moduleCache[file] = ____modules[file]() - return ____moduleCache[file] + local module = ____modules[file] + local value = nil + ${runModule} + ____moduleCache[file] = { value = value } + return value else if ____originalRequire then return ____originalRequire(file) @@ -32,6 +40,50 @@ local function require(file) end end `; +} + +export const sourceMapTracebackBundlePlaceholder = "{#SourceMapTracebackBundle}"; + +type SourceMapLineData = number | { line: number; file: string }; + +export function printStackTraceBundleOverride(rootNode: SourceNode): string { + const map: Record = {}; + const getLineNumber = (line: number, fallback: number) => { + const data: SourceMapLineData | undefined = map[line]; + if (data === undefined) { + return fallback; + } + if (typeof data === "number") { + return data; + } + return data.line; + }; + const transformLineData = (data: SourceMapLineData) => { + if (typeof data === "number") { + return data; + } + return `{line = ${data.line}, file = "${data.file}"}`; + }; + + let currentLine = 1; + rootNode.walk((chunk, mappedPosition) => { + if (mappedPosition.line !== undefined && mappedPosition.line > 0) { + const line = getLineNumber(currentLine, mappedPosition.line); + + map[currentLine] = { + line, + file: path.basename(mappedPosition.source), + }; + } + + currentLine += chunk.split("\n").length - 1; + }); + + const mapItems = Object.entries(map).map(([line, original]) => `["${line}"] = ${transformLineData(original)}`); + const mapString = "{" + mapItems.join(",") + "}"; + + return `__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapString});`; +} export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [ts.Diagnostic[], EmitFile] { const diagnostics: ts.Diagnostic[] = []; @@ -41,10 +93,12 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t const entryModule = cast(options.luaBundleEntry, isNonNull); // Resolve project settings relative to project file. - const resolvedEntryModule = path.resolve(getSourceDir(program), entryModule); + const resolvedEntryModule = path.resolve(getProjectRoot(program), entryModule); const outputPath = path.resolve(getEmitOutDir(program), bundleFile); + const entryModuleFilePath = + program.getSourceFile(entryModule)?.fileName ?? program.getSourceFile(resolvedEntryModule)?.fileName; - if (program.getSourceFile(resolvedEntryModule) === undefined && program.getSourceFile(entryModule) === undefined) { + if (entryModuleFilePath === undefined) { diagnostics.push(couldNotFindBundleEntryPoint(entryModule)); } @@ -55,16 +109,27 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t const moduleTable = createModuleTableNode(moduleTableEntries); // return require("") - const entryPoint = `return require(${createModulePath(entryModule, program)})\n`; + const args = options.luaTarget === LuaTarget.Lua50 ? "unpack(arg == nil and {} or arg)" : "..."; + // Avoid producing a tail-call (which removes the bundle's stack frame) by assigning the `require` result to a local and returning it. + const entryPath = createModulePath(entryModuleFilePath ?? entryModule, program); + const entryPoint = `local ____entry = require(${entryPath}, ${args})\nreturn ____entry\n`; + + const footers: string[] = []; + if (options.sourceMapTraceback) { + // Generates SourceMapTraceback for the entire file + footers.push('local __TS__SourceMapTraceBack = require("lualib_bundle").__TS__SourceMapTraceBack\n'); + footers.push(`${sourceMapTracebackBundlePlaceholder}\n`); + } - const sourceChunks = [requireOverride, moduleTable, entryPoint]; + const sourceChunks = [requireOverride(options), moduleTable, ...footers, entryPoint]; if (!options.noHeader) { sourceChunks.unshift(tstlHeader); } const bundleNode = joinSourceChunks(sourceChunks); - const { code, map } = bundleNode.toStringWithSourceMap(); + let { code, map } = bundleNode.toStringWithSourceMap(); + code = code.replace(sourceMapTracebackBundlePlaceholder, printStackTraceBundleOverride(bundleNode)); return [ diagnostics, @@ -78,7 +143,7 @@ export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [t } function moduleSourceNode({ code, sourceMapNode }: ProcessedFile, modulePath: string): SourceNode { - const tableEntryHead = `[${modulePath}] = function() `; + const tableEntryHead = `[${modulePath}] = function(...) \n`; const tableEntryTail = " end,\n"; return joinSourceChunks([tableEntryHead, sourceMapNode ?? code, tableEntryTail]); @@ -92,6 +157,7 @@ function createModuleTableNode(fileChunks: SourceChunk[]): SourceNode { } type SourceChunk = string | SourceNode; + function joinSourceChunks(chunks: SourceChunk[]): SourceNode { return new SourceNode(null, null, null, chunks); } diff --git a/src/transpilation/diagnostics.ts b/src/transpilation/diagnostics.ts index 4b57c329d..1ee589708 100644 --- a/src/transpilation/diagnostics.ts +++ b/src/transpilation/diagnostics.ts @@ -8,7 +8,7 @@ const createDiagnosticFactory = ( export const couldNotResolveRequire = createDiagnosticFactory( (requirePath: string, containingFile: string) => - `Could not resolve require path '${requirePath}' in file ${containingFile}.` + `Could not resolve lua source files for require path '${requirePath}' in file ${containingFile}.` ); export const couldNotReadDependency = createDiagnosticFactory( @@ -51,5 +51,13 @@ export const usingLuaBundleWithInlineMightGenerateDuplicateCode = createSerialDi export const cannotBundleLibrary = createDiagnosticFactory( () => - 'Cannot bundle probjects with"buildmode": "library". Projects including the library can still bundle (which will include external library files).' + 'Cannot bundle projects with "buildmode": "library". Projects including the library can still bundle (which will include external library files).' +); + +export const unsupportedJsxEmit = createDiagnosticFactory(() => 'JSX is only supported with "react" jsx option.'); + +export const emitPathCollision = createDiagnosticFactory( + (outputPath: string, file1: string, file2: string) => + `Output path '${outputPath}' is used by both '${file1}' and '${file2}'. ` + + `Dots in file/directory names are replaced with underscores for Lua module resolution.` ); diff --git a/src/transpilation/find-lua-requires.ts b/src/transpilation/find-lua-requires.ts new file mode 100644 index 000000000..90be465e6 --- /dev/null +++ b/src/transpilation/find-lua-requires.ts @@ -0,0 +1,168 @@ +export interface LuaRequire { + from: number; + to: number; + requirePath: string; +} + +export function findLuaRequires(lua: string): LuaRequire[] { + return findRequire(lua, 0); +} + +function findRequire(lua: string, offset: number): LuaRequire[] { + const result = []; + + while (offset < lua.length) { + const c = lua[offset]; + if ( + c === "r" && + (offset === 0 || + isWhitespace(lua[offset - 1]) || + lua[offset - 1] === "]" || + lua[offset - 1] === "(" || + lua[offset - 1] === "[") + ) { + const m = matchRequire(lua, offset); + if (m.matched) { + offset = m.match.to + 1; + result.push(m.match); + } else { + offset = m.end; + } + } else if (c === '"' || c === "'") { + offset = readString(lua, offset, c).offset; // Skip string and surrounding quotes + } else if (c === "-" && offset + 1 < lua.length && lua[offset + 1] === "-") { + offset = skipComment(lua, offset); + } else { + offset++; + } + } + + return result; +} + +type MatchResult = { matched: true; match: T } | { matched: false; end: number }; + +function matchRequire(lua: string, offset: number): MatchResult { + const start = offset; + for (const c of "require") { + if (offset > lua.length) { + return { matched: false, end: offset }; + } + + if (lua[offset] !== c) { + return { matched: false, end: offset }; + } + offset++; + } + + offset = skipWhitespace(lua, offset); + + let hasParentheses = false; + + if (offset > lua.length) { + return { matched: false, end: offset }; + } else { + if (lua[offset] === "(") { + hasParentheses = true; + offset++; + offset = skipWhitespace(lua, offset); + } else if (lua[offset] === '"' || lua[offset] === "'") { + // require without parentheses + } else { + // otherwise fail match + return { matched: false, end: offset }; + } + } + + if (offset > lua.length || (lua[offset] !== '"' && lua[offset] !== "'")) { + return { matched: false, end: offset }; + } + + const { value: requireString, offset: offsetAfterString } = readString(lua, offset, lua[offset]); + offset = offsetAfterString; // Skip string and surrounding quotes + + if (hasParentheses) { + offset = skipWhitespace(lua, offset); + + if (offset > lua.length || lua[offset] !== ")") { + return { matched: false, end: offset }; + } + + offset++; + } + + return { matched: true, match: { from: start, to: offset - 1, requirePath: requireString } }; +} + +function readString(lua: string, offset: number, delimiter: string): { value: string; offset: number } { + expect(lua, offset, delimiter); + offset++; + + let start = offset; + let result = ""; + + let escaped = false; + while (offset < lua.length && (lua[offset] !== delimiter || escaped)) { + if (lua[offset] === "\\" && !escaped) { + escaped = true; + } else { + if (lua[offset] === delimiter) { + result += lua.slice(start, offset - 1); + start = offset; + } + escaped = false; + } + + offset++; + } + + if (offset < lua.length) { + expect(lua, offset, delimiter); + } + + result += lua.slice(start, offset); + return { value: result, offset: offset + 1 }; +} + +function skipWhitespace(lua: string, offset: number): number { + while (offset < lua.length && isWhitespace(lua[offset])) { + offset++; + } + return offset; +} + +function isWhitespace(c: string): boolean { + return c === " " || c === "\t" || c === "\r" || c === "\n"; +} + +function skipComment(lua: string, offset: number): number { + expect(lua, offset, "-"); + expect(lua, offset + 1, "-"); + offset += 2; + + if (offset + 1 < lua.length && lua[offset] === "[" && lua[offset + 1] === "[") { + return skipMultiLineComment(lua, offset); + } else { + return skipSingleLineComment(lua, offset); + } +} + +function skipMultiLineComment(lua: string, offset: number): number { + while (offset < lua.length && !(lua[offset] === "]" && lua[offset - 1] === "]")) { + offset++; + } + return offset + 1; +} + +function skipSingleLineComment(lua: string, offset: number): number { + while (offset < lua.length && lua[offset] !== "\n") { + offset++; + } + return offset + 1; +} + +function expect(lua: string, offset: number, char: string) { + if (lua[offset] !== char) { + throw new Error(`Expected ${char} at position ${offset} but found ${lua[offset]}`); + } +} diff --git a/src/transpilation/index.ts b/src/transpilation/index.ts index 59e83233a..d4e890719 100644 --- a/src/transpilation/index.ts +++ b/src/transpilation/index.ts @@ -3,6 +3,7 @@ import * as path from "path"; import * as ts from "typescript"; import { parseConfigFileWithSystem } from "../cli/tsconfig"; import { CompilerOptions } from "../CompilerOptions"; +import { normalizeSlashes } from "../utils"; import { createEmitOutputCollector, TranspiledFile } from "./output-collector"; import { EmitResult, Transpiler } from "./transpiler"; @@ -18,11 +19,9 @@ export function transpileFiles( writeFile?: ts.WriteFileCallback ): EmitResult { const program = ts.createProgram(rootNames, options); + const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); const { diagnostics: transpileDiagnostics, emitSkipped } = new Transpiler().emit({ program, writeFile }); - const diagnostics = ts.sortAndDeduplicateDiagnostics([ - ...ts.getPreEmitDiagnostics(program), - ...transpileDiagnostics, - ]); + const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); return { diagnostics: [...diagnostics], emitSkipped }; } @@ -44,8 +43,12 @@ const libCache: { [key: string]: ts.SourceFile } = {}; /** @internal */ export function createVirtualProgram(input: Record, options: CompilerOptions = {}): ts.Program { + const normalizedFiles: Record = {}; + for (const [path, file] of Object.entries(input)) { + normalizedFiles[normalizeSlashes(path)] = file; + } const compilerHost: ts.CompilerHost = { - fileExists: fileName => fileName in input || ts.sys.fileExists(fileName), + fileExists: fileName => fileName in normalizedFiles || ts.sys.fileExists(fileName), getCanonicalFileName: fileName => fileName, getCurrentDirectory: () => "", getDefaultLibFileName: ts.getDefaultLibFileName, @@ -55,8 +58,8 @@ export function createVirtualProgram(input: Record, options: Com writeFile() {}, getSourceFile(fileName) { - if (fileName in input) { - return ts.createSourceFile(fileName, input[fileName], ts.ScriptTarget.Latest, false); + if (fileName in normalizedFiles) { + return ts.createSourceFile(fileName, normalizedFiles[fileName], ts.ScriptTarget.Latest, false); } let filePath: string | undefined; @@ -80,7 +83,7 @@ export function createVirtualProgram(input: Record, options: Com }, }; - return ts.createProgram(Object.keys(input), options, compilerHost); + return ts.createProgram(Object.keys(normalizedFiles), options, compilerHost); } export interface TranspileVirtualProjectResult { @@ -93,12 +96,10 @@ export function transpileVirtualProject( options: CompilerOptions = {} ): TranspileVirtualProjectResult { const program = createVirtualProgram(files, options); + const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); const collector = createEmitOutputCollector(); const { diagnostics: transpileDiagnostics } = new Transpiler().emit({ program, writeFile: collector.writeFile }); - const diagnostics = ts.sortAndDeduplicateDiagnostics([ - ...ts.getPreEmitDiagnostics(program), - ...transpileDiagnostics, - ]); + const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); return { diagnostics: [...diagnostics], transpiledFiles: collector.files }; } diff --git a/src/transpilation/output-collector.ts b/src/transpilation/output-collector.ts index 866c1f79a..1458b2403 100644 --- a/src/transpilation/output-collector.ts +++ b/src/transpilation/output-collector.ts @@ -14,7 +14,7 @@ export interface TranspiledFile { jsSourceMap?: string; } -export function createEmitOutputCollector() { +export function createEmitOutputCollector(luaExtension = ".lua") { const files: TranspiledFile[] = []; const writeFile: ts.WriteFileCallback = (fileName, data, _bom, _onError, sourceFiles = []) => { let file = files.find(f => intersection(f.sourceFiles, sourceFiles).length > 0); @@ -25,9 +25,9 @@ export function createEmitOutputCollector() { file.sourceFiles = union(file.sourceFiles, sourceFiles); } - if (fileName.endsWith(".lua")) { + if (fileName.endsWith(luaExtension)) { file.lua = data; - } else if (fileName.endsWith(".lua.map")) { + } else if (fileName.endsWith(`${luaExtension}.map`)) { file.luaSourceMap = data; } else if (fileName.endsWith(".js")) { file.js = data; diff --git a/src/transpilation/plugins.ts b/src/transpilation/plugins.ts index 0311efbbd..f84af2bc9 100644 --- a/src/transpilation/plugins.ts +++ b/src/transpilation/plugins.ts @@ -1,8 +1,10 @@ import * as ts from "typescript"; +import { EmitHost } from ".."; import { CompilerOptions } from "../CompilerOptions"; import { Printer } from "../LuaPrinter"; import { Visitors } from "../transformation/context"; -import { getConfigDirectory, resolvePlugin } from "./utils"; +import { EmitFile, getConfigDirectory, ProcessedFile, resolvePlugin } from "./utils"; +import * as performance from "../measure-performance"; export interface Plugin { /** @@ -18,29 +20,91 @@ export interface Plugin { * At most one custom printer can be provided across all plugins. */ printer?: Printer; + + /** + * This function is called before transpilation of the TypeScript program starts. + */ + beforeTransform?: (program: ts.Program, options: CompilerOptions, emitHost: EmitHost) => ts.Diagnostic[] | void; + + /** + * This function is called after translating the input program to Lua, but before resolving dependencies or bundling. + */ + afterPrint?: ( + program: ts.Program, + options: CompilerOptions, + emitHost: EmitHost, + result: ProcessedFile[] + ) => ts.Diagnostic[] | void; + + /** + * This function is called after translating the input program to Lua, after resolving dependencies and after bundling. + */ + beforeEmit?: ( + program: ts.Program, + options: CompilerOptions, + emitHost: EmitHost, + result: EmitFile[] + ) => ts.Diagnostic[] | void; + + /** + * This function is called after translating the input program to Lua, after resolving dependencies, after bundling and writing files to disk. + */ + afterEmit?: ( + program: ts.Program, + options: CompilerOptions, + emitHost: EmitHost, + result: EmitFile[] + ) => ts.Diagnostic[] | void; + + /** + * This function is called when trying to resolve the .lua file corresponding to a Lua require statement. Allows you to provide + * your own module resolution logic. If return value is undefined, regular module resolution is done. + */ + moduleResolution?: ( + moduleIdentifier: string, + requiringFile: string, + options: CompilerOptions, + emitHost: EmitHost + ) => string | undefined; } -export function getPlugins(program: ts.Program, diagnostics: ts.Diagnostic[], customPlugins: Plugin[]): Plugin[] { +export function getPlugins(program: ts.Program): { diagnostics: ts.Diagnostic[]; plugins: Plugin[] } { + performance.startSection("getPlugins"); + const diagnostics: ts.Diagnostic[] = []; const pluginsFromOptions: Plugin[] = []; const options = program.getCompilerOptions() as CompilerOptions; for (const [index, pluginOption] of (options.luaPlugins ?? []).entries()) { const optionName = `tstl.luaPlugins[${index}]`; - const { error: resolveError, result: factory } = resolvePlugin( - "plugin", - `${optionName}.name`, - getConfigDirectory(options), - pluginOption.name, - pluginOption.import - ); + const factory = (() => { + if ("plugin" in pluginOption) { + return pluginOption.plugin; + } else { + const { error: resolveError, result: factory } = resolvePlugin( + "plugin", + `${optionName}.name`, + getConfigDirectory(options), + pluginOption.name, + pluginOption.import + ); + + if (resolveError) diagnostics.push(resolveError); + return factory; + } + })(); - if (resolveError) diagnostics.push(resolveError); if (factory === undefined) continue; const plugin = typeof factory === "function" ? factory(pluginOption) : factory; pluginsFromOptions.push(plugin); } - return [...customPlugins, ...pluginsFromOptions]; + if (options.tstlVerbose) { + console.log(`Loaded ${pluginsFromOptions.length} plugins`); + } + + performance.endSection("getPlugins"); + + return { diagnostics, plugins: pluginsFromOptions }; } diff --git a/src/transpilation/resolve.ts b/src/transpilation/resolve.ts index 5334c0ca7..af7981ffc 100644 --- a/src/transpilation/resolve.ts +++ b/src/transpilation/resolve.ts @@ -8,12 +8,17 @@ import { getEmitPathRelativeToOutDir, getProjectRoot, getSourceDir } from "./tra import { formatPathToLuaPath, normalizeSlashes, trimExtension } from "../utils"; import { couldNotReadDependency, couldNotResolveRequire } from "./diagnostics"; import { BuildMode, CompilerOptions } from "../CompilerOptions"; +import { findLuaRequires, LuaRequire } from "./find-lua-requires"; +import { Plugin } from "./plugins"; +import * as picomatch from "picomatch"; const resolver = resolve.ResolverFactory.createResolver({ extensions: [".lua"], enforceExtension: true, // Resolved file must be a lua file - fileSystem: { ...new resolve.CachedInputFileSystem(fs) }, + fileSystem: { ...new resolve.CachedInputFileSystem(fs, 0) }, useSyncFileSystemCalls: true, + conditionNames: ["require", "node", "tstl", "default"], + symlinks: false, // Do not resolve symlinks to their original paths (that breaks node_modules detection) }); interface ResolutionResult { @@ -21,180 +26,398 @@ interface ResolutionResult { diagnostics: ts.Diagnostic[]; } -export function resolveDependencies(program: ts.Program, files: ProcessedFile[], emitHost: EmitHost): ResolutionResult { - const outFiles: ProcessedFile[] = [...files]; - const diagnostics: ts.Diagnostic[] = []; - const options = program.getCompilerOptions() as CompilerOptions; +class ResolutionContext { + private noResolvePaths: picomatch.Glob[]; - // Resolve dependencies for all processed files - for (const file of files) { - if (options.tstlVerbose) { - console.log(`Resolving dependencies for ${normalizeSlashes(file.fileName)}`); - } + public diagnostics: ts.Diagnostic[] = []; + public resolvedFiles = new Map(); - const resolutionResult = resolveFileDependencies(file, program, emitHost); - outFiles.push(...resolutionResult.resolvedFiles); - diagnostics.push(...resolutionResult.diagnostics); + constructor( + public readonly program: ts.Program, + public readonly options: CompilerOptions, + private readonly emitHost: EmitHost, + private readonly plugins: Plugin[] + ) { + this.noResolvePaths = [...new Set(options.noResolvePaths)]; } - return { resolvedFiles: outFiles, diagnostics }; -} - -function resolveFileDependencies(file: ProcessedFile, program: ts.Program, emitHost: EmitHost): ResolutionResult { - const dependencies: ProcessedFile[] = []; - const diagnostics: ts.Diagnostic[] = []; - const options = program.getCompilerOptions() as CompilerOptions; + public addAndResolveDependencies(file: ProcessedFile): void { + if (this.resolvedFiles.has(file.fileName)) return; + this.resolvedFiles.set(file.fileName, file); + + // Do this backwards so the replacements do not mess with the positions of the previous requires + for (const required of findLuaRequires(file.code).reverse()) { + // Do not resolve noResolution paths + if (required.requirePath.startsWith("@NoResolution:")) { + // Remove @NoResolution prefix if not building in library mode + if (!isBuildModeLibrary(this.program)) { + const path = required.requirePath.replace("@NoResolution:", ""); + replaceRequireInCode(file, required, path, this.options.extension); + replaceRequireInSourceMap(file, required, path, this.options.extension); + } - for (const required of findRequiredPaths(file.code)) { - // Do no resolve lualib - if (required === "lualib_bundle") { - continue; + // Skip + continue; + } + // Try to resolve the import starting from the directory `file` is in + this.resolveImport(file, required); } + } - // Do not resolve noResolution paths - if (required.startsWith("@NoResolution:")) { - const path = required.replace("@NoResolution:", ""); - replaceRequireInCode(file, required, path); - replaceRequireInSourceMap(file, required, path); - continue; + public resolveImport(file: ProcessedFile, required: LuaRequire): void { + // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages + if (required.requirePath === "lualib_bundle") { + this.resolvedFiles.set("lualib_bundle", { fileName: "lualib_bundle", code: "" }); + return; } - // Try to resolve the import starting from the directory `file` is in - const fileDir = path.dirname(file.fileName); - const resolvedDependency = resolveDependency(fileDir, required, program, emitHost); - if (resolvedDependency) { - if (options.tstlVerbose) { - console.log(`Resolved ${required} to ${normalizeSlashes(resolvedDependency)}`); + if (this.noResolvePaths.find(glob => picomatch.isMatch(required.requirePath, glob))) { + if (this.options.tstlVerbose) { + console.log( + `Skipping module resolution of ${required.requirePath} as it is in the tsconfig noResolvePaths.` + ); } + return; + } - // Figure out resolved require path and dependency output path - const resolvedRequire = getEmitPathRelativeToOutDir(resolvedDependency, program); + const dependencyPath = + this.resolveDependencyPathsWithPlugins(file, required.requirePath) ?? + this.resolveDependencyPath(file, required.requirePath); - if (shouldRewriteRequires(resolvedDependency, program)) { - replaceRequireInCode(file, required, resolvedRequire); - replaceRequireInSourceMap(file, required, resolvedRequire); - } + if (!dependencyPath) return this.couldNotResolveImport(required, file); + + if (this.options.tstlVerbose) { + console.log(`Resolved ${required.requirePath} to ${normalizeSlashes(dependencyPath)}`); + } - // If dependency is not part of project, add dependency to output and resolve its dependencies recursively - if (shouldIncludeDependency(resolvedDependency, program)) { - // If dependency resolved successfully, read its content - const dependencyContent = emitHost.readFile(resolvedDependency); - if (dependencyContent === undefined) { - diagnostics.push(couldNotReadDependency(resolvedDependency)); - continue; + this.processDependency(dependencyPath); + // Figure out resolved require path and dependency output path + if (shouldRewriteRequires(dependencyPath, this.program)) { + const resolvedRequire = getEmitPathRelativeToOutDir(dependencyPath, this.program); + replaceRequireInCode(file, required, resolvedRequire, this.options.extension); + replaceRequireInSourceMap(file, required, resolvedRequire, this.options.extension); + } + } + + private resolveDependencyPathsWithPlugins(requiringFile: ProcessedFile, dependency: string) { + const requiredFromLuaFile = requiringFile.fileName.endsWith(".lua"); + for (const plugin of this.plugins) { + if (plugin.moduleResolution != null) { + const pluginResolvedPath = plugin.moduleResolution( + dependency, + requiringFile.fileName, + this.options, + this.emitHost + ); + if (pluginResolvedPath !== undefined) { + // If resolved path is absolute no need to further resolve it + if (path.isAbsolute(pluginResolvedPath)) { + return pluginResolvedPath; + } + + // If lua file is in node_module + if (requiredFromLuaFile && isNodeModulesFile(requiringFile.fileName)) { + // If requiring file is in lua module, try to resolve sibling in that file first + const resolvedNodeModulesFile = this.resolveLuaDependencyPathFromNodeModules( + requiringFile, + pluginResolvedPath + ); + if (resolvedNodeModulesFile) { + if (this.options.tstlVerbose) { + console.log( + `Resolved file path for module ${dependency} to path ${pluginResolvedPath} using plugin.` + ); + } + return resolvedNodeModulesFile; + } + } + + const resolvedPath = this.formatPathToFile(pluginResolvedPath, requiringFile); + const fileFromPath = this.getFileFromPath(resolvedPath); + + if (fileFromPath) { + if (this.options.tstlVerbose) { + console.log( + `Resolved file path for module ${dependency} to path ${pluginResolvedPath} using plugin.` + ); + } + return fileFromPath; + } } + } + } + } + + public processedDependencies = new Set(); + + private formatPathToFile(targetPath: string, required: ProcessedFile) { + const isRelative = ["/", "./", "../"].some(p => targetPath.startsWith(p)); + + // // If the import is relative, always resolve it relative to the requiring file + // // If the import is not relative, resolve it relative to options.baseUrl if it is set + const fileDirectory = path.dirname(required.fileName); + const relativeTo = isRelative ? fileDirectory : this.options.baseUrl ?? fileDirectory; + + // // Check if file is a file in the project + const resolvedPath = path.join(relativeTo, targetPath); + return resolvedPath; + } + + private processDependency(dependencyPath: string): void { + if (this.processedDependencies.has(dependencyPath)) return; + this.processedDependencies.add(dependencyPath); + + if (!shouldIncludeDependency(dependencyPath, this.program)) return; + + // If dependency is not part of project, add dependency to output and resolve its dependencies recursively + const dependencyContent = this.emitHost.readFile(dependencyPath); + if (dependencyContent === undefined) { + this.diagnostics.push(couldNotReadDependency(dependencyPath)); + return; + } + + const dependency = { + fileName: dependencyPath, + code: dependencyContent, + }; + this.addAndResolveDependencies(dependency); + } + + private couldNotResolveImport(required: LuaRequire, file: ProcessedFile): void { + const fallbackRequire = fallbackResolve(required, getSourceDir(this.program), path.dirname(file.fileName)); + replaceRequireInCode(file, required, fallbackRequire, this.options.extension); + replaceRequireInSourceMap(file, required, fallbackRequire, this.options.extension); + + this.diagnostics.push( + couldNotResolveRequire(required.requirePath, path.relative(getProjectRoot(this.program), file.fileName)) + ); + } + + private resolveDependencyPath(requiringFile: ProcessedFile, dependency: string): string | undefined { + const fileDirectory = path.dirname(requiringFile.fileName); + if (this.options.tstlVerbose) { + console.log(`Resolving "${dependency}" from ${normalizeSlashes(requiringFile.fileName)}`); + } + + const requiredFromLuaFile = requiringFile.fileName.endsWith(".lua"); + const dependencyPath = requiredFromLuaFile ? luaRequireToPath(dependency) : dependency; + + if (requiredFromLuaFile && isNodeModulesFile(requiringFile.fileName)) { + // If requiring file is in lua module, try to resolve sibling in that file first + const resolvedNodeModulesFile = this.resolveLuaDependencyPathFromNodeModules(requiringFile, dependencyPath); + if (resolvedNodeModulesFile) return resolvedNodeModulesFile; + } + + // Bare specifiers: check paths mappings first, matching TypeScript's resolution order. + // TS never applies paths to relative imports, so skip for those. + if (!ts.isExternalModuleNameRelative(dependencyPath) && this.options.paths) { + // When baseUrl is not set, resolve paths relative to the tsconfig directory (TS 6.0+ behavior) + const pathsBase = + this.options.baseUrl ?? + (this.options.configFilePath ? path.dirname(this.options.configFilePath) : undefined); + if (pathsBase) { + const fileFromPaths = this.tryGetModuleNameFromPaths(dependencyPath, this.options.paths, pathsBase); + if (fileFromPaths) return fileFromPaths; + } + } - const dependency = { - fileName: resolvedDependency, - code: dependencyContent, - }; - const nestedDependencies = resolveFileDependencies(dependency, program, emitHost); - dependencies.push(dependency, ...nestedDependencies.resolvedFiles); - diagnostics.push(...nestedDependencies.diagnostics); + // Check if file is a file in the project + const resolvedPath = this.formatPathToFile(dependencyPath, requiringFile); + const fileFromPath = this.getFileFromPath(resolvedPath); + if (fileFromPath) return fileFromPath; + + // Not a TS file in our project sources, use resolver to check if we can find dependency + try { + const resolveResult = resolver.resolveSync({}, fileDirectory, dependencyPath); + if (resolveResult) return resolveResult; + } catch (e: any) { + // resolveSync errors if it fails to resolve + if (this.options.tstlVerbose && e.details) { + // Output resolver log + console.log(e.details); } - } else { - // Could not resolve dependency, add a diagnostic and make some fallback path - diagnostics.push(couldNotResolveRequire(required, path.relative(getProjectRoot(program), file.fileName))); + } - const fallbackRequire = fallbackResolve(required, getSourceDir(program), fileDir); - replaceRequireInCode(file, required, fallbackRequire); - replaceRequireInSourceMap(file, required, fallbackRequire); + return undefined; + } + + private resolveLuaDependencyPathFromNodeModules( + requiringFile: ProcessedFile, + dependency: string + ): string | undefined { + // We don't know for sure where the lua root is, so guess it is at package root + const splitPath = path.normalize(requiringFile.fileName).split(path.sep); + let packageRootIndex = splitPath.lastIndexOf("node_modules") + 2; + let packageRoot = splitPath.slice(0, packageRootIndex).join(path.sep); + + while (packageRootIndex < splitPath.length) { + // Try to find lua file relative to currently guessed Lua root + const resolvedPath = path.join(packageRoot, dependency); + const fileFromPath = this.getFileFromPath(resolvedPath); + if (fileFromPath) { + return fileFromPath; + } else { + // Did not find file at current root, try again one directory deeper + packageRoot = path.join(packageRoot, splitPath[packageRootIndex++]); + } } + + return undefined; } - return { resolvedFiles: dependencies, diagnostics }; -} -function resolveDependency( - fileDirectory: string, - dependency: string, - program: ts.Program, - emitHost: EmitHost -): string | undefined { - const options = program.getCompilerOptions() as CompilerOptions; - if (options.tstlVerbose) { - console.log(`Resolving "${dependency}" from ${normalizeSlashes(fileDirectory)}`); + // value is false if already searched but not found + private pathToFile = new Map(); + + private getFileFromPath(resolvedPath: string): string | undefined { + const existingFile = this.pathToFile.get(resolvedPath); + if (existingFile) return existingFile; + if (existingFile === false) return undefined; + + const file = this.searchForFileFromPath(resolvedPath); + this.pathToFile.set(resolvedPath, file ?? false); + return file; } - // Check if file is a file in the project - const resolvedPath = path.join(fileDirectory, dependency); + private searchForFileFromPath(resolvedPath: string): string | undefined { + const possibleProjectFiles = [ + resolvedPath, // JSON files need their extension as part of the import path, caught by this branch, + resolvedPath + ".ts", // Regular ts file + path.join(resolvedPath, "index.ts"), // Index ts file, + resolvedPath + ".tsx", // tsx file + path.join(resolvedPath, "index.tsx"), // tsx index + ]; + + for (const possibleFile of possibleProjectFiles) { + if (isProjectFile(possibleFile, this.program)) { + return possibleFile; + } + } - const possibleProjectFiles = [ - resolvedPath, // JSON files need their extension as part of the import path, caught by this branch, - resolvedPath + ".ts", // Regular ts file - path.join(resolvedPath, "index.ts"), // Index ts file, - resolvedPath + ".tsx", // tsx file - path.join(resolvedPath, "index.tsx"), // tsx index - ]; + // Check if this is a lua file in the project sources + const possibleLuaProjectFiles = [ + resolvedPath + ".lua", // lua file in sources + path.join(resolvedPath, "index.lua"), // lua index file in sources + path.join(resolvedPath, "init.lua"), // lua looks for /init.lua if it cannot find .lua + ]; - for (const possibleFile of possibleProjectFiles) { - if (isProjectFile(possibleFile, program)) { - return possibleFile; + for (const possibleFile of possibleLuaProjectFiles) { + if (this.emitHost.fileExists(possibleFile)) { + return possibleFile; + } } } - // Check if this is a sibling of a required lua file - const luaFilePath = path.resolve(fileDirectory, dependency + ".lua"); - if (emitHost.fileExists(luaFilePath)) { - return luaFilePath; + // Taken from TS and modified: https://github.com/microsoft/TypeScript/blob/88a1e3a1dd8d2d86e844ff1c16d5f041cebcfdb9/src/compiler/moduleSpecifiers.ts#L562 + private tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: ts.MapLike, baseUrl: string) { + const relativeImport = removeTrailingDirectorySeparator(normalizeSlashes(relativeToBaseUrl)); + for (const [importPattern, targetPatterns] of Object.entries(paths)) { + const pattern = removeFileExtension(normalizeSlashes(importPattern)); + const indexOfStar = pattern.indexOf("*"); + if (indexOfStar !== -1) { + // Try to match * to relativeImport + const prefix = pattern.substring(0, indexOfStar); + const suffix = pattern.substring(indexOfStar + 1); + if ( + (relativeImport.length >= prefix.length + suffix.length && + relativeImport.startsWith(prefix) && + relativeImport.endsWith(suffix)) || + (!suffix && relativeImport === removeTrailingDirectorySeparator(prefix)) + ) { + // If import matches *, extract the matched * path + const matchedStar = relativeImport.substring(prefix.length, relativeImport.length - suffix.length); + // Try to resolve to the target patterns with filled in * pattern + for (const target of targetPatterns) { + const file = this.getFileFromPath(path.join(baseUrl, target.replace("*", matchedStar))); + if (file) return file; + } + } + } else if (pattern === relativeImport) { + // If there is no * pattern, check for exact matches and try those targets + for (const target of targetPatterns) { + const file = this.getFileFromPath(path.join(baseUrl, target)); + if (file) return file; + } + } + } } +} + +export function resolveDependencies( + program: ts.Program, + files: ProcessedFile[], + emitHost: EmitHost, + plugins: Plugin[] +): ResolutionResult { + const options = program.getCompilerOptions() as CompilerOptions; + + const resolutionContext = new ResolutionContext(program, options, emitHost, plugins); - // Not a TS file in our project sources, use resolver to check if we can find dependency - try { - const resolveResult = resolver.resolveSync({}, fileDirectory, dependency); - if (resolveResult) { - return resolveResult; + // Resolve dependencies for all processed files + for (const file of files) { + if (options.tstlVerbose) { + console.log(`Resolving dependencies for ${normalizeSlashes(file.fileName)}`); } - } catch (e) { - // resolveSync errors if it fails to resolve + resolutionContext.addAndResolveDependencies(file); } - return undefined; + return { resolvedFiles: [...resolutionContext.resolvedFiles.values()], diagnostics: resolutionContext.diagnostics }; } function shouldRewriteRequires(resolvedDependency: string, program: ts.Program) { - return !isNodeModulesFile(resolvedDependency) || !isBuildModeLibrary(program); + return !isBuildModeLibrary(program) || !isNodeModulesFile(resolvedDependency); } function shouldIncludeDependency(resolvedDependency: string, program: ts.Program) { // Never include lua files (again) that are transpiled from project sources - if (!hasSourceFileInProject(resolvedDependency, program)) { - // Always include lua files not in node_modules (internal lua sources) - if (!isNodeModulesFile(resolvedDependency)) { - return true; - } else { - // Only include node_modules files if not in library mode - return !isBuildModeLibrary(program); - } - } - return false; + if (hasSourceFileInProject(resolvedDependency, program)) return false; + // Always include lua files not in node_modules (internal lua sources) + if (!isNodeModulesFile(resolvedDependency)) return true; + // Only include node_modules files if not in library mode + return !isBuildModeLibrary(program); } function isBuildModeLibrary(program: ts.Program) { return program.getCompilerOptions().buildMode === BuildMode.Library; } -function findRequiredPaths(code: string): string[] { - // Find all require("") paths in a lua code string - const paths: string[] = []; - const pattern = /require\("(.+)"\)/g; - // eslint-disable-next-line @typescript-eslint/ban-types - let match: RegExpExecArray | null; - while ((match = pattern.exec(code))) { - paths.push(match[1]); - } - - return paths; +function replaceRequireInCode( + file: ProcessedFile, + originalRequire: LuaRequire, + newRequire: string, + extension: string | undefined +): void { + const requirePath = requirePathForFile(newRequire, extension); + file.code = file.code = + file.code.substring(0, originalRequire.from) + + `require("${requirePath}")` + + file.code.substring(originalRequire.to + 1); } -function replaceRequireInCode(file: ProcessedFile, originalRequire: string, newRequire: string): void { - const requirePath = formatPathToLuaPath(newRequire.replace(".lua", "")); - file.code = file.code.replace(`require("${originalRequire}")`, `require("${requirePath}")`); +function replaceRequireInSourceMap( + file: ProcessedFile, + originalRequire: LuaRequire, + newRequire: string, + extension?: string | undefined +): void { + const requirePath = requirePathForFile(newRequire, extension); + if (file.sourceMapNode) { + replaceInSourceMap( + file.sourceMapNode, + file.sourceMapNode, + `"${originalRequire.requirePath}"`, + `"${requirePath}"` + ); + } } -function replaceRequireInSourceMap(file: ProcessedFile, originalRequire: string, newRequire: string): void { - const requirePath = formatPathToLuaPath(newRequire.replace(".lua", "")); - if (file.sourceMapNode) { - replaceInSourceMap(file.sourceMapNode, file.sourceMapNode, `"${originalRequire}"`, `"${requirePath}"`); +function requirePathForFile(filePath: string, extension = ".lua"): string { + if (!extension.startsWith(".")) { + extension = `.${extension}`; + } + if (filePath.endsWith(extension)) { + return formatPathToLuaPath(filePath.substring(0, filePath.length - extension.length)); + } else { + return formatPathToLuaPath(filePath); } } @@ -236,12 +459,24 @@ function hasSourceFileInProject(filePath: string, program: ts.Program) { } // Transform an import path to a lua require that is probably not correct, but can be used as fallback when regular resolution fails -function fallbackResolve(required: string, sourceRootDir: string, fileDir: string): string { +function fallbackResolve(required: LuaRequire, sourceRootDir: string, fileDir: string): string { return formatPathToLuaPath( path - .normalize(path.join(path.relative(sourceRootDir, fileDir), required)) + .normalize(path.join(path.relative(sourceRootDir, fileDir), required.requirePath)) .split(path.sep) .filter(s => s !== "." && s !== "..") .join(path.sep) ); } + +function luaRequireToPath(requirePath: string): string { + return requirePath.replace(/\./g, path.sep); +} + +function removeFileExtension(path: string) { + return path.includes(".") ? trimExtension(path) : path; +} + +function removeTrailingDirectorySeparator(path: string) { + return path.endsWith("/") || path.endsWith("\\") ? path.substring(0, -1) : path; +} diff --git a/src/transpilation/transformers.ts b/src/transpilation/transformers.ts index e043704b8..0080b6e4e 100644 --- a/src/transpilation/transformers.ts +++ b/src/transpilation/transformers.ts @@ -36,6 +36,7 @@ export function getTransformers( ...(transformersFromOptions.after ?? []), ...(customTransformers.after ?? []), + stripParenthesisExpressionsTransformer, luaTransformer, ], }; @@ -53,6 +54,34 @@ export const noImplicitSelfTransformer: ts.TransformerFactory = context => sourceFile => { + // Remove parenthesis expressions before transforming to Lua, so transpiler is not hindered by extra ParenthesizedExpression nodes + function unwrapParentheses(node: ts.Expression) { + while (ts.isParenthesizedExpression(node) && !ts.isOptionalChain(node.expression)) { + node = node.expression; + } + return node; + } + function visit(node: ts.Node): ts.Node { + // For now only call expressions strip their expressions of parentheses, there could be more cases where this is required + if (ts.isCallExpression(node)) { + return ts.factory.updateCallExpression( + node, + unwrapParentheses(node.expression), + node.typeArguments, + node.arguments + ); + } else if (ts.isVoidExpression(node)) { + return ts.factory.updateVoidExpression(node, unwrapParentheses(node.expression)); + } else if (ts.isDeleteExpression(node)) { + return ts.factory.updateDeleteExpression(node, unwrapParentheses(node.expression)); + } + + return ts.visitEachChild(node, visit, context); + } + return ts.visitEachChild(sourceFile, visit, context); +}; + function loadTransformersFromOptions(program: ts.Program, diagnostics: ts.Diagnostic[]): ts.CustomTransformers { const customTransformers: Required = { before: [], @@ -61,40 +90,53 @@ function loadTransformersFromOptions(program: ts.Program, diagnostics: ts.Diagno }; const options = program.getCompilerOptions() as CompilerOptions; - if (!options.plugins) return customTransformers; - - for (const [index, transformerImport] of options.plugins.entries()) { - if (!("transform" in transformerImport)) continue; - const optionName = `compilerOptions.plugins[${index}]`; - - const { error: resolveError, result: factory } = resolvePlugin( - "transformer", - `${optionName}.transform`, - getConfigDirectory(options), - transformerImport.transform, - transformerImport.import - ); - - if (resolveError) diagnostics.push(resolveError); - if (factory === undefined) continue; - - const { error: loadError, transformer } = loadTransformer(optionName, program, factory, transformerImport); - if (loadError) diagnostics.push(loadError); - if (transformer === undefined) continue; - - if (transformer.before) { - customTransformers.before.push(transformer.before); - } - - if (transformer.after) { - customTransformers.after.push(transformer.after); - } - - if (transformer.afterDeclarations) { - customTransformers.afterDeclarations.push(transformer.afterDeclarations); + if (options.plugins) { + for (const [index, transformerImport] of options.plugins.entries()) { + if (!("transform" in transformerImport)) continue; + const optionName = `compilerOptions.plugins[${index}]`; + + const { error: resolveError, result: factory } = resolvePlugin( + "transformer", + `${optionName}.transform`, + getConfigDirectory(options), + transformerImport.transform, + transformerImport.import + ); + + if (resolveError) diagnostics.push(resolveError); + if (factory === undefined) continue; + + const { error: loadError, transformer } = loadTransformer(optionName, program, factory, transformerImport); + if (loadError) diagnostics.push(loadError); + if (transformer === undefined) continue; + + if (transformer.before) { + customTransformers.before.push(transformer.before); + } + + if (transformer.after) { + customTransformers.after.push(transformer.after); + } + + if (transformer.afterDeclarations) { + customTransformers.afterDeclarations.push(transformer.afterDeclarations); + } } } - + if (options.jsx === ts.JsxEmit.React) { + customTransformers.before.push(context => { + // if target < ES2017, typescript generates some unnecessary additional transformations in transformJSX. + // We can't control the target compiler option, so we override here. + const patchedContext: ts.TransformationContext = { + ...context, + getCompilerOptions: () => ({ + ...context.getCompilerOptions(), + target: ts.ScriptTarget.ESNext, + }), + }; + return ts.transformJsx(patchedContext); + }); + } return customTransformers; } diff --git a/src/transpilation/transpile.ts b/src/transpilation/transpile.ts index d78162fd8..6adfa5fc4 100644 --- a/src/transpilation/transpile.ts +++ b/src/transpilation/transpile.ts @@ -4,9 +4,10 @@ import { CompilerOptions, validateOptions } from "../CompilerOptions"; import { createPrinter } from "../LuaPrinter"; import { createVisitorMap, transformSourceFile } from "../transformation"; import { isNonNull } from "../utils"; -import { getPlugins, Plugin } from "./plugins"; +import { Plugin } from "./plugins"; import { getTransformers } from "./transformers"; import { EmitHost, ProcessedFile } from "./utils"; +import * as performance from "../measure-performance"; export interface TranspileOptions { program: ts.Program; @@ -23,8 +24,10 @@ export interface TranspileResult { export function getProgramTranspileResult( emitHost: EmitHost, writeFileResult: ts.WriteFileCallback, - { program, sourceFiles: targetSourceFiles, customTransformers = {}, plugins: customPlugins = [] }: TranspileOptions + { program, sourceFiles: targetSourceFiles, customTransformers = {}, plugins = [] }: TranspileOptions ): TranspileResult { + performance.startSection("beforeTransform"); + const options = program.getCompilerOptions() as CompilerOptions; if (options.tstlVerbose) { @@ -56,27 +59,35 @@ export function getProgramTranspileResult( } if (preEmitDiagnostics.length > 0) { + performance.endSection("beforeTransform"); return { diagnostics: preEmitDiagnostics, transpiledFiles }; } } - const plugins = getPlugins(program, diagnostics, customPlugins); - - if (options.tstlVerbose) { - console.log(`Successfully loaded ${plugins.length} plugins`); + for (const plugin of plugins) { + if (plugin.beforeTransform) { + const pluginDiagnostics = plugin.beforeTransform(program, options, emitHost) ?? []; + diagnostics.push(...pluginDiagnostics); + } } const visitorMap = createVisitorMap(plugins.map(p => p.visitors).filter(isNonNull)); const printer = createPrinter(plugins.map(p => p.printer).filter(isNonNull)); + const processSourceFile = (sourceFile: ts.SourceFile) => { if (options.tstlVerbose) { console.log(`Transforming ${sourceFile.fileName}`); } - const { file, diagnostics: transformDiagnostics } = transformSourceFile(program, sourceFile, visitorMap); + performance.startSection("transpile"); + const { file, diagnostics: transformDiagnostics } = transformSourceFile(program, sourceFile, visitorMap); diagnostics.push(...transformDiagnostics); + + performance.endSection("transpile"); + if (!options.noEmit && !options.emitDeclarationOnly) { + performance.startSection("print"); if (options.tstlVerbose) { console.log(`Printing ${sourceFile.fileName}`); } @@ -88,6 +99,7 @@ export function getProgramTranspileResult( luaAst: file, ...printResult, }); + performance.endSection("print"); } }; @@ -103,11 +115,13 @@ export function getProgramTranspileResult( options.noEmit = false; const writeFile: ts.WriteFileCallback = (fileName, ...rest) => { - if (!fileName.endsWith(".js") && !fileName.endsWith(".js.map")) { + if (!fileName.endsWith(".js") && !fileName.endsWith(".js.map") && !fileName.endsWith(".json")) { writeFileResult(fileName, ...rest); } }; + performance.endSection("beforeTransform"); + if (targetSourceFiles) { for (const file of targetSourceFiles) { if (isEmittableJsonFile(file)) { @@ -123,11 +137,22 @@ export function getProgramTranspileResult( program.getSourceFiles().filter(isEmittableJsonFile).forEach(processSourceFile); } + performance.startSection("afterPrint"); + options.noEmit = oldNoEmit; if (options.noEmit || (options.noEmitOnError && diagnostics.length > 0)) { transpiledFiles = []; } + for (const plugin of plugins) { + if (plugin.afterPrint) { + const pluginDiagnostics = plugin.afterPrint(program, options, emitHost, transpiledFiles) ?? []; + diagnostics.push(...pluginDiagnostics); + } + } + + performance.endSection("afterPrint"); + return { diagnostics, transpiledFiles }; } diff --git a/src/transpilation/transpiler.ts b/src/transpilation/transpiler.ts index b19790b37..7f79af35d 100644 --- a/src/transpilation/transpiler.ts +++ b/src/transpilation/transpiler.ts @@ -1,12 +1,15 @@ import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions, isBundleEnabled } from "../CompilerOptions"; -import { getLuaLibBundle } from "../LuaLib"; +import { CompilerOptions, isBundleEnabled, LuaLibImportKind, LuaTarget } from "../CompilerOptions"; +import { buildMinimalLualibBundle, findUsedLualibFeatures, getLuaLibBundle } from "../LuaLib"; import { normalizeSlashes, trimExtension } from "../utils"; import { getBundleResult } from "./bundle"; +import { emitPathCollision } from "./diagnostics"; +import { getPlugins, Plugin } from "./plugins"; import { resolveDependencies } from "./resolve"; import { getProgramTranspileResult, TranspileOptions } from "./transpile"; import { EmitFile, EmitHost, ProcessedFile } from "./utils"; +import * as performance from "../measure-performance"; export interface TranspilerOptions { emitHost?: EmitHost; @@ -23,29 +26,62 @@ export interface EmitResult { export class Transpiler { protected emitHost: EmitHost; + constructor({ emitHost = ts.sys }: TranspilerOptions = {}) { this.emitHost = emitHost; } public emit(emitOptions: EmitOptions): EmitResult { - const { program, writeFile = this.emitHost.writeFile } = emitOptions; - const verbose = (program.getCompilerOptions() as CompilerOptions).tstlVerbose; - const { diagnostics, transpiledFiles: freshFiles } = getProgramTranspileResult( + const { program, writeFile = this.emitHost.writeFile, plugins: optionsPlugins = [] } = emitOptions; + + const { diagnostics: getPluginsDiagnostics, plugins: configPlugins } = getPlugins(program); + const plugins = [...optionsPlugins, ...configPlugins]; + + const { diagnostics: transpileDiagnostics, transpiledFiles: freshFiles } = getProgramTranspileResult( this.emitHost, writeFile, - emitOptions + { + ...emitOptions, + plugins, + } ); - const { emitPlan } = this.getEmitPlan(program, diagnostics, freshFiles); + const { emitPlan } = this.getEmitPlan(program, transpileDiagnostics, freshFiles, plugins); + + const emitDiagnostics = this.emitFiles(program, plugins, emitPlan, writeFile); - if (verbose) { + return { + diagnostics: getPluginsDiagnostics.concat(transpileDiagnostics, emitDiagnostics), + emitSkipped: emitPlan.length === 0, + }; + } + + private emitFiles( + program: ts.Program, + plugins: Plugin[], + emitPlan: EmitFile[], + writeFile: ts.WriteFileCallback + ): ts.Diagnostic[] { + performance.startSection("emit"); + + const options = program.getCompilerOptions() as CompilerOptions; + + if (options.tstlVerbose) { console.log("Emitting output"); } - const options = program.getCompilerOptions(); + const diagnostics: ts.Diagnostic[] = []; + + for (const plugin of plugins) { + if (plugin.beforeEmit) { + const beforeEmitPluginDiagnostics = plugin.beforeEmit(program, options, this.emitHost, emitPlan) ?? []; + diagnostics.push(...beforeEmitPluginDiagnostics); + } + } + const emitBOM = options.emitBOM ?? false; for (const { outputPath, code, sourceMap, sourceFiles } of emitPlan) { - if (verbose) { + if (options.tstlVerbose) { console.log(`Emitting ${normalizeSlashes(outputPath)}`); } @@ -55,53 +91,90 @@ export class Transpiler { } } - if (verbose) { + for (const plugin of plugins) { + if (plugin.afterEmit) { + const afterEmitPluginDiagnostics = plugin.afterEmit(program, options, this.emitHost, emitPlan) ?? []; + diagnostics.push(...afterEmitPluginDiagnostics); + } + } + + if (options.tstlVerbose) { console.log("Emit finished!"); } - return { diagnostics, emitSkipped: emitPlan.length === 0 }; + performance.endSection("emit"); + + return diagnostics; } protected getEmitPlan( program: ts.Program, diagnostics: ts.Diagnostic[], - files: ProcessedFile[] + files: ProcessedFile[], + plugins: Plugin[] ): { emitPlan: EmitFile[] } { + performance.startSection("getEmitPlan"); const options = program.getCompilerOptions() as CompilerOptions; if (options.tstlVerbose) { console.log("Constructing emit plan"); } - const lualibRequired = files.some(f => f.code.includes('require("lualib_bundle")')); + // Resolve imported modules and modify output Lua requires + const resolutionResult = resolveDependencies(program, files, this.emitHost, plugins); + diagnostics.push(...resolutionResult.diagnostics); + + const lualibRequired = resolutionResult.resolvedFiles.some(f => f.fileName === "lualib_bundle"); if (lualibRequired) { + // Remove lualib placeholders from resolution result + resolutionResult.resolvedFiles = resolutionResult.resolvedFiles.filter(f => f.fileName !== "lualib_bundle"); + if (options.tstlVerbose) { console.log("Including lualib bundle"); } - // Add lualib bundle to source dir 'virtually', will be moved to correct output dir in emitPlan const fileName = normalizeSlashes(path.resolve(getSourceDir(program), "lualib_bundle.lua")); - files.unshift({ fileName, code: getLuaLibBundle(this.emitHost) }); + const code = this.getLuaLibBundleContent(options, resolutionResult.resolvedFiles); + resolutionResult.resolvedFiles.unshift({ fileName, code }); } - // Resolve imported modules and modify output Lua requires - const resolutionResult = resolveDependencies(program, files, this.emitHost); - diagnostics.push(...resolutionResult.diagnostics); - let emitPlan: EmitFile[]; if (isBundleEnabled(options)) { const [bundleDiagnostics, bundleFile] = getBundleResult(program, resolutionResult.resolvedFiles); diagnostics.push(...bundleDiagnostics); emitPlan = [bundleFile]; } else { - emitPlan = resolutionResult.resolvedFiles.map(file => ({ - ...file, - outputPath: getEmitPath(file.fileName, program), - })); + const outputPathMap = new Map(); + emitPlan = resolutionResult.resolvedFiles.map(file => { + const outputPath = getEmitPath(file.fileName, program); + const existing = outputPathMap.get(outputPath); + if (existing) { + diagnostics.push(emitPathCollision(outputPath, existing, file.fileName)); + } else { + outputPathMap.set(outputPath, file.fileName); + } + return { ...file, outputPath }; + }); } + performance.endSection("getEmitPlan"); + return { emitPlan }; } + + private getLuaLibBundleContent(options: CompilerOptions, resolvedFiles: ProcessedFile[]) { + const luaTarget = options.luaTarget ?? LuaTarget.Universal; + if (options.luaLibImport === LuaLibImportKind.RequireMinimal) { + const usedFeatures = findUsedLualibFeatures( + luaTarget, + this.emitHost, + resolvedFiles.map(f => f.code) + ); + return buildMinimalLualibBundle(usedFeatures, luaTarget, this.emitHost); + } else { + return getLuaLibBundle(luaTarget, this.emitHost); + } + } } export function getEmitPath(file: string, program: ts.Program): string { @@ -124,8 +197,17 @@ export function getEmitPathRelativeToOutDir(fileName: string, program: ts.Progra emitPathSplits[0] = "lua_modules"; } - // Make extension lua - emitPathSplits[emitPathSplits.length - 1] = trimExtension(emitPathSplits[emitPathSplits.length - 1]) + ".lua"; + // Replace dots with underscores in path segments so that Lua's require() + // resolves correctly. Dots are path separators in Lua's module system, so + // "Foo.Bar/index.lua" would be unreachable via require("Foo.Bar.index") + // since Lua interprets it as "Foo/Bar/index.lua". + emitPathSplits[emitPathSplits.length - 1] = trimExtension(emitPathSplits[emitPathSplits.length - 1]); + emitPathSplits = emitPathSplits.map(segment => segment.replace(/\./g, "_")); + + // Set extension + const extension = ((program.getCompilerOptions() as CompilerOptions).extension ?? "lua").trim(); + const trimmedExtension = extension.startsWith(".") ? extension.substring(1) : extension; + emitPathSplits[emitPathSplits.length - 1] += "." + trimmedExtension; return path.join(...emitPathSplits); } @@ -135,7 +217,9 @@ export function getSourceDir(program: ts.Program): string { if (rootDir && rootDir.length > 0) { return path.isAbsolute(rootDir) ? rootDir : path.resolve(getProjectRoot(program), rootDir); } - return program.getCommonSourceDirectory(); + + // If no rootDir is given, source is relative to the project root + return getProjectRoot(program); } export function getEmitOutDir(program: ts.Program): string { diff --git a/src/transpilation/utils.ts b/src/transpilation/utils.ts index a4acdfbb4..ce03fd854 100644 --- a/src/transpilation/utils.ts +++ b/src/transpilation/utils.ts @@ -8,6 +8,7 @@ import * as lua from "../LuaAST"; import * as diagnosticFactories from "./diagnostics"; export interface EmitHost { + directoryExists(path: string): boolean; fileExists(path: string): boolean; getCurrentDirectory(): string; readFile(path: string): string | undefined; @@ -23,7 +24,6 @@ interface BaseFile { export interface ProcessedFile extends BaseFile { fileName: string; luaAst?: lua.File; - /** @internal */ sourceMapNode?: SourceNode; } @@ -34,33 +34,37 @@ export interface EmitFile extends BaseFile { export const getConfigDirectory = (options: ts.CompilerOptions) => options.configFilePath ? path.dirname(options.configFilePath) : process.cwd(); +const getTstlDirectory = () => path.dirname(__dirname); + export function resolvePlugin( kind: string, optionName: string, basedir: string, - query: string, + query: unknown, importName = "default" ): { error?: ts.Diagnostic; result?: unknown } { if (typeof query !== "string") { return { error: cliDiagnostics.compilerOptionRequiresAValueOfType(optionName, "string") }; } + const isModuleNotFoundError = (error: any) => error.code === "MODULE_NOT_FOUND"; + let resolved: string; try { resolved = resolve.sync(query, { basedir, extensions: [".js", ".ts", ".tsx"] }); } catch (err) { - if (err.code !== "MODULE_NOT_FOUND") throw err; + if (!isModuleNotFoundError(err)) throw err; return { error: diagnosticFactories.couldNotResolveFrom(kind, query, basedir) }; } const hasNoRequireHook = require.extensions[".ts"] === undefined; if (hasNoRequireHook && (resolved.endsWith(".ts") || resolved.endsWith(".tsx"))) { try { - const tsNodePath = resolve.sync("ts-node", { basedir }); + const tsNodePath = resolve.sync("ts-node", { basedir: getTstlDirectory() }); const tsNode: typeof import("ts-node") = require(tsNodePath); tsNode.register({ transpileOnly: true }); } catch (err) { - if (err.code !== "MODULE_NOT_FOUND") throw err; + if (!isModuleNotFoundError(err)) throw err; return { error: diagnosticFactories.toLoadItShouldBeTranspiled(kind, query) }; } } diff --git a/src/tstl.ts b/src/tstl.ts index fb011be3c..813347a21 100644 --- a/src/tstl.ts +++ b/src/tstl.ts @@ -7,6 +7,7 @@ import { parseCommandLine } from "./cli/parse"; import { createDiagnosticReporter } from "./cli/report"; import { createConfigFileUpdater, locateConfigFile, parseConfigFileWithSystem } from "./cli/tsconfig"; import { isBundleEnabled } from "./CompilerOptions"; +import * as performance from "./measure-performance"; const shouldBePretty = ({ pretty }: ts.CompilerOptions = {}) => pretty !== undefined ? (pretty as boolean) : ts.sys.writeOutputIsTTY?.() ?? false; @@ -95,23 +96,29 @@ function performCompilation( options: tstl.CompilerOptions, configFileParsingDiagnostics?: readonly ts.Diagnostic[] ): void { + if (options.measurePerformance) performance.enableMeasurement(); + + performance.startSection("createProgram"); + const program = ts.createProgram({ rootNames, options, projectReferences, configFileParsingDiagnostics, }); + const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); - const { diagnostics: transpileDiagnostics, emitSkipped } = new tstl.Transpiler().emit({ program }); + performance.endSection("createProgram"); - const diagnostics = ts.sortAndDeduplicateDiagnostics([ - ...ts.getPreEmitDiagnostics(program), - ...transpileDiagnostics, - ]); + const { diagnostics: transpileDiagnostics, emitSkipped } = new tstl.Transpiler().emit({ program }); + const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); diagnostics.forEach(reportDiagnostic); + + if (options.measurePerformance) reportPerformance(); + const exitCode = - diagnostics.length === 0 + diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error).length === 0 ? ts.ExitStatus.Success : emitSkipped ? ts.ExitStatus.DiagnosticsPresent_OutputsSkipped @@ -159,6 +166,9 @@ function updateWatchCompilationHost( host.afterProgramCreate = builderProgram => { const program = builderProgram.getProgram(); const options = builderProgram.getCompilerOptions() as tstl.CompilerOptions; + + if (options.measurePerformance) performance.enableMeasurement(); + const configFileParsingDiagnostics: ts.Diagnostic[] = updateConfigFile(options); let sourceFiles: ts.SourceFile[] | undefined; @@ -189,6 +199,8 @@ function updateWatchCompilationHost( diagnostics.forEach(reportDiagnostic); + if (options.measurePerformance) reportPerformance(); + const errors = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error); hadErrorLastTime = errors.length > 0; @@ -196,6 +208,17 @@ function updateWatchCompilationHost( }; } +function reportPerformance() { + if (performance.isMeasurementEnabled()) { + console.log("Performance measurements: "); + performance.forEachMeasure((name, duration) => { + console.log(` ${name}: ${duration.toFixed(2)}ms`); + }); + console.log(`Total: ${performance.getTotalDuration().toFixed(2)}ms`); + performance.disableMeasurement(); + } +} + function checkNodeVersion(): void { const [major, minor] = process.version.slice(1).split(".").map(Number); const isValid = major > 12 || (major === 12 && minor >= 13); diff --git a/src/typescript-internal.d.ts b/src/typescript-internal.d.ts index 7bfd309ac..5333df95a 100644 --- a/src/typescript-internal.d.ts +++ b/src/typescript-internal.d.ts @@ -1,5 +1,3 @@ -import { DiagnosticsProducingTypeChecker } from "./transformation/context"; - export {}; declare module "typescript" { @@ -16,7 +14,6 @@ declare module "typescript" { interface Program { getCommonSourceDirectory(): string; - getDiagnosticsProducingTypeChecker(): DiagnosticsProducingTypeChecker; } interface CompilerOptions { @@ -26,5 +23,40 @@ declare module "typescript" { interface TypeChecker { getElementTypeOfArrayType(type: Type): Type | undefined; + getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined; + + isTupleType(type: Type): boolean; + isArrayType(type: Type): boolean; + } + + interface Symbol { + parent?: Symbol; + } + + interface Signature { + compositeSignatures?: Signature[]; } + + function transformJsx(context: TransformationContext): (x: SourceFile) => SourceFile; + + export type OuterExpression = + | ParenthesizedExpression + | TypeAssertion + | AsExpression + | NonNullExpression + | PartiallyEmittedExpression; + + function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression; + export function isOuterExpression(node: Node, kinds?: OuterExpressionKinds): node is OuterExpression; + + export function nodeNextJsonConfigResolver( + moduleName: string, + containingFile: string, + host: ModuleResolutionHost + ): ResolvedModuleWithFailedLookupLocations; + + export function pathIsAbsolute(path: string): boolean; + export function pathIsRelative(path: string): boolean; + + export function setParent(child: T, parent: T["parent"] | undefined): T; } diff --git a/src/utils.ts b/src/utils.ts index 72e6ee168..70cdb2940 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ import * as path from "path"; export function castArray(value: T | T[]): T[]; export function castArray(value: T | readonly T[]): readonly T[]; export function castArray(value: T | readonly T[]): readonly T[] { - return Array.isArray(value) ? value : [value]; + return Array.isArray(value) ? value : [value as T]; } export const intersperse = (values: readonly T[], separator: T): T[] => @@ -50,7 +50,6 @@ export function formatPathToLuaPath(filePath: string): string { type NoInfer = [T][T extends any ? 0 : never]; export function getOrUpdate( - // eslint-disable-next-line @typescript-eslint/ban-types map: Map | (K extends object ? WeakMap : never), key: K, getDefaultValue: () => NoInfer @@ -62,7 +61,6 @@ export function getOrUpdate( return map.get(key)!; } -// eslint-disable-next-line @typescript-eslint/ban-types export function isNonNull(value: T | null | undefined): value is T { return value != null; } @@ -79,7 +77,7 @@ export function cast( } export function assert(value: any, message?: string | Error): asserts value { - nativeAssert(value, message); + nativeAssert.ok(value, message); } export function assertNever(_value: never): never { diff --git a/test/cli/parse.spec.ts b/test/cli/parse.spec.ts index f157c9a21..c33af1208 100644 --- a/test/cli/parse.spec.ts +++ b/test/cli/parse.spec.ts @@ -59,6 +59,14 @@ describe("command line", () => { }); }); + describe("array-of-objects options", () => { + test.each([["{"], ["{}"], ["0"], ["''"]])("should error on invalid value (%s)", value => { + const result = tstl.parseCommandLine(["--luaPlugins", value]); + + expect(result.errors).toHaveDiagnostics(); + }); + }); + describe("boolean options", () => { test.each([true, false])("should parse booleans (%p)", value => { const result = tstl.parseCommandLine(["--noHeader", value.toString()]); @@ -111,7 +119,6 @@ describe("command line", () => { ["buildMode", "library", { buildMode: tstl.BuildMode.Library }], ["luaLibImport", "none", { luaLibImport: tstl.LuaLibImportKind.None }], - ["luaLibImport", "always", { luaLibImport: tstl.LuaLibImportKind.Always }], ["luaLibImport", "inline", { luaLibImport: tstl.LuaLibImportKind.Inline }], ["luaLibImport", "require", { luaLibImport: tstl.LuaLibImportKind.Require }], @@ -123,6 +130,15 @@ describe("command line", () => { ["luaBundle", "foo", { luaBundle: "foo" }], ["luaBundleEntry", "bar", { luaBundleEntry: "bar" }], + + ["extension", ".lua", { extension: ".lua" }], + ["extension", "scar", { extension: "scar" }], + + ["luaPlugins", '[{ "name": "a" }]', { luaPlugins: [{ name: "a" }] }], + ["luaPlugins", '[{ "name": "a" },{ "name": "b" }]', { luaPlugins: [{ name: "a" }, { name: "b" }] }], + + ["noResolvePaths", "path1", { noResolvePaths: ["path1"] }], + ["noResolvePaths", "path1,path2", { noResolvePaths: ["path1", "path2"] }], ])("--%s %s", (optionName, value, expected) => { const result = tstl.parseCommandLine([`--${optionName}`, value]); @@ -222,19 +238,28 @@ describe("tsconfig", () => { ["buildMode", "library", { buildMode: tstl.BuildMode.Library }], ["luaLibImport", "none", { luaLibImport: tstl.LuaLibImportKind.None }], - ["luaLibImport", "always", { luaLibImport: tstl.LuaLibImportKind.Always }], ["luaLibImport", "inline", { luaLibImport: tstl.LuaLibImportKind.Inline }], ["luaLibImport", "require", { luaLibImport: tstl.LuaLibImportKind.Require }], ["luaTarget", "universal", { luaTarget: tstl.LuaTarget.Universal }], + ["luaTarget", "5.0", { luaTarget: tstl.LuaTarget.Lua50 }], ["luaTarget", "5.1", { luaTarget: tstl.LuaTarget.Lua51 }], ["luaTarget", "5.2", { luaTarget: tstl.LuaTarget.Lua52 }], ["luaTarget", "5.3", { luaTarget: tstl.LuaTarget.Lua53 }], ["luaTarget", "5.4", { luaTarget: tstl.LuaTarget.Lua54 }], + ["luaTarget", "5.5", { luaTarget: tstl.LuaTarget.Lua55 }], ["luaTarget", "jit", { luaTarget: tstl.LuaTarget.LuaJIT }], + ["luaTarget", "luau", { luaTarget: tstl.LuaTarget.Luau }], ["luaBundle", "foo", { luaBundle: "foo" }], ["luaBundleEntry", "bar", { luaBundleEntry: "bar" }], + + ["noImplicitSelf", true, { noImplicitSelf: true }], + + ["tstlVerbose", true, { tstlVerbose: true }], + + ["noResolvePaths", [], { noResolvePaths: [] }], + ["noResolvePaths", ["path1", "path2"], { noResolvePaths: ["path1", "path2"] }], ])("{ %p: %p }", (optionName, value, expected) => { const result = parseConfigFileContent({ tstl: { [optionName]: value } }); diff --git a/test/cli/run.ts b/test/cli/run.ts index cee7e19b2..732d71bcb 100644 --- a/test/cli/run.ts +++ b/test/cli/run.ts @@ -1,7 +1,7 @@ import { ChildProcess, fork } from "child_process"; import * as path from "path"; -jest.setTimeout(20000); +jest.setTimeout(30000); const cliPath = path.join(__dirname, "../../src/tstl.ts"); @@ -26,6 +26,6 @@ export async function runCli(args: string[]): Promise { child.stderr!.on("data", (data: Buffer) => (output += data.toString())); return new Promise(resolve => { - child.on("close", exitCode => resolve({ exitCode, output })); + child.on("close", exitCode => resolve({ exitCode: exitCode ?? 1, output })); }); } diff --git a/test/cli/tsconfig.spec.ts b/test/cli/tsconfig.spec.ts index 1608ac973..e5d1b946c 100644 --- a/test/cli/tsconfig.spec.ts +++ b/test/cli/tsconfig.spec.ts @@ -1,7 +1,7 @@ import * as fs from "fs-extra"; import * as os from "os"; import * as path from "path"; -import { locateConfigFile } from "../../src/cli/tsconfig"; +import { locateConfigFile, parseConfigFileWithSystem } from "../../src/cli/tsconfig"; import { normalizeSlashes } from "../../src/utils"; let temp: string; @@ -20,7 +20,7 @@ afterEach(async () => { const locate = (project: string | undefined, fileNames: string[] = []) => locateConfigFile({ errors: [], fileNames, options: { project } }); -const normalize = (name: string) => normalizeSlashes(path.resolve(temp, name)); +const normalize = (name: string) => normalizeSlashes(fs.realpathSync(path.resolve(temp, name))); describe("specified", () => { for (const separator of process.platform === "win32" ? ["/", "\\"] : ["/"]) { @@ -91,3 +91,25 @@ describe("errors", () => { expect([locate("tsconfig.json", [""])]).toHaveDiagnostics(); }); }); + +describe("tsconfig extends", () => { + test("correctly merges extended tsconfig files", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.3", noHeader: true }); + }); + + test("can handle multiple extends", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.multi-extends.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.4", sourceMapTraceback: true }); + }); + + test("can handle cycles in configs", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig-cycle1.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.4" }); + }); + + test("can handle tsconfig files with comments", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.with-comments.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.3" }); + }); +}); diff --git a/test/cli/tsconfig/tsconfig-cycle1.json b/test/cli/tsconfig/tsconfig-cycle1.json new file mode 100644 index 000000000..6383b5ccf --- /dev/null +++ b/test/cli/tsconfig/tsconfig-cycle1.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-cycle2.json", + "tstl": { + "luaTarget": "5.4" + } +} diff --git a/test/cli/tsconfig/tsconfig-cycle2.json b/test/cli/tsconfig/tsconfig-cycle2.json new file mode 100644 index 000000000..14c3edcd1 --- /dev/null +++ b/test/cli/tsconfig/tsconfig-cycle2.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-cycle1.json", + "tstl": { + "luaTarget": "5.3" + } +} diff --git a/test/cli/tsconfig/tsconfig.base.json b/test/cli/tsconfig/tsconfig.base.json new file mode 100644 index 000000000..6b296a8de --- /dev/null +++ b/test/cli/tsconfig/tsconfig.base.json @@ -0,0 +1,6 @@ +{ + "tstl": { + "noHeader": true, + "luaTarget": "jit" + } +} diff --git a/test/cli/tsconfig/tsconfig.json b/test/cli/tsconfig/tsconfig.json new file mode 100644 index 000000000..7e76044a2 --- /dev/null +++ b/test/cli/tsconfig/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.base.json", + "tstl": { + "luaTarget": "5.3" + } +} diff --git a/test/cli/tsconfig/tsconfig.multi-extends.json b/test/cli/tsconfig/tsconfig.multi-extends.json new file mode 100644 index 000000000..7404a6266 --- /dev/null +++ b/test/cli/tsconfig/tsconfig.multi-extends.json @@ -0,0 +1,6 @@ +{ + "extends": ["./tsconfig.json", "./tsconfig2.json"], + "tstl": { + "sourceMapTraceback": true + } +} diff --git a/test/cli/tsconfig/tsconfig.with-comments.json b/test/cli/tsconfig/tsconfig.with-comments.json new file mode 100644 index 000000000..9baf9adda --- /dev/null +++ b/test/cli/tsconfig/tsconfig.with-comments.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "tstl": { + // Can handle comments + /* also of this kind */ + "luaTarget": "5.3" + } +} diff --git a/test/cli/tsconfig/tsconfig2.json b/test/cli/tsconfig/tsconfig2.json new file mode 100644 index 000000000..9cfef77e0 --- /dev/null +++ b/test/cli/tsconfig/tsconfig2.json @@ -0,0 +1,5 @@ +{ + "tstl": { + "luaTarget": "5.4" + } +} diff --git a/test/json.50.lua b/test/json.50.lua new file mode 100644 index 000000000..8e4109c8f --- /dev/null +++ b/test/json.50.lua @@ -0,0 +1,147 @@ +-- +-- json.lua +-- +-- Copyright (c) 2015 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- +-- +-- LICENSE CONTENTS: +-- +-- Copyright (c) 2015 rxi +-- +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. + +local json = { _version = "0.1.0" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\\\", + [ "\"" ] = "\\\"", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local escape_char_map_inv = { [ "\\/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return escape_char_map[c] or string.format("\\u%04x", c:byte()) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if val[1] ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if k ~= "n" then + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + end + if n ~= table.getn(val) then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. string.gsub(val, '[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + if val ~= val then + return "NaN" + elseif val >= 1 / 0 then + return "Infinity" + elseif val <= 0 / 0 then + return "-Infinity" + else + return string.format("%.17g", val) + end +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + +return {stringify = function(val) return ( encode(val) ) end} diff --git a/test/setup.ts b/test/setup.ts index de78ad24b..704c59bed 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -3,7 +3,6 @@ import * as ts from "typescript"; import * as tstl from "../src"; declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace namespace jest { // eslint-disable-next-line @typescript-eslint/naming-convention interface Matchers { @@ -14,7 +13,7 @@ declare global { expect.extend({ toHaveDiagnostics(diagnostics: ts.Diagnostic[], expected?: number[]): jest.CustomMatcherResult { - assert(Array.isArray(diagnostics)); + assert.ok(Array.isArray(diagnostics)); // @ts-ignore const matcherHint = this.utils.matcherHint("toHaveDiagnostics", undefined, "", this); @@ -37,7 +36,9 @@ expect.extend({ const message = this.isNot ? diagnosticMessages : expected - ? `Expected:\n${expected.join("\n")}\nReceived:\n${diagnostics.map(diag => diag.code).join("\n")}\n` + ? `Expected:\n${expected.join("\n")}\nReceived:\n${diagnostics + .map(diag => diag.code) + .join("\n")}\n\n${diagnosticMessages}\n` : `Received: ${this.utils.printReceived([])}\n`; return matcherHint + "\n\n" + message; diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap index 7fd968b00..e9fccb4ae 100644 --- a/test/translation/__snapshots__/transformation.spec.ts.snap +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -1,53 +1,74 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Luau-specific Transformation (luauSpecificTransformations) 1`] = ` +"t = if true then "is true" else "is false" +while false do + continue +end +repeat + do + continue + end +until not false" +`; + exports[`Transformation (blockScopeVariables) 1`] = ` "do local a = 1 local b = 1 - local ____ = {c = 1} - local c = ____.c + local ____temp_0 = {c = 1} + local c = ____temp_0.c end" `; exports[`Transformation (characterEscapeSequence) 1`] = ` -"quoteInDoubleQuotes = \\"' ' '\\" -quoteInTemplateString = \\"' ' '\\" -doubleQuoteInQuotes = \\"\\\\\\" \\\\\\" \\\\\\"\\" -doubleQuoteInDoubleQuotes = \\"\\\\\\" \\\\\\" \\\\\\"\\" -doubleQuoteInTemplateString = \\"\\\\\\" \\\\\\" \\\\\\"\\" -backQuoteInQuotes = \\"\` \` \`\\" -backQuoteInDoubleQuotes = \\"\` \` \`\\" -backQuoteInTemplateString = \\"\` \` \`\\" -escapedCharsInQuotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\" -escapedCharsInDoubleQuotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\" -escapedCharsInTemplateString = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\" -nonEmptyTemplateString = (\\"Level 0: \\\\n\\\\t \\" .. ((\\"Level 1: \\\\n\\\\t\\\\t \\" .. ((\\"Level 3: \\\\n\\\\t\\\\t\\\\t \\" .. \\"Last level \\\\n --\\") .. \\" \\\\n --\\")) .. \\" \\\\n --\\")) .. \\" \\\\n --\\"" +"quoteInDoubleQuotes = "' ' '" +quoteInTemplateString = "' ' '" +doubleQuoteInQuotes = "\\" \\" \\"" +doubleQuoteInDoubleQuotes = "\\" \\" \\"" +doubleQuoteInTemplateString = "\\" \\" \\"" +backQuoteInQuotes = "\` \` \`" +backQuoteInDoubleQuotes = "\` \` \`" +backQuoteInTemplateString = "\` \` \`" +escapedCharsInQuotes = "\\\\ \\0 \\b \\t \\n \\v \\f \\" ' \`" +escapedCharsInDoubleQuotes = "\\\\ \\0 \\b \\t \\n \\v \\f \\" ' \`" +escapedCharsInTemplateString = "\\\\ \\0 \\b \\t \\n \\v \\f \\" ' \`" +nonEmptyTemplateString = ("Level 0: \\n\\t " .. ("Level 1: \\n\\t\\t " .. ("Level 3: \\n\\t\\t\\t " .. "Last level \\n --") .. " \\n --") .. " \\n --") .. " \\n --"" `; +exports[`Transformation (customNameWithExtraComment) 1`] = `"TestNamespace.pass()"`; + +exports[`Transformation (customNameWithNoSelf) 1`] = `"TestNamespace.pass()"`; + exports[`Transformation (exportStatement) 1`] = ` "local ____exports = {} local xyz = 4 ____exports.xyz = xyz ____exports.uwv = xyz do - local ____export = require(\\"xyz\\") + local ____export = require("xyz") for ____exportKey, ____exportValue in pairs(____export) do - if ____exportKey ~= \\"default\\" then + if ____exportKey ~= "default" then ____exports[____exportKey] = ____exportValue end end end do - local ____xyz = require(\\"xyz\\") - local abc = ____xyz.abc - local def = ____xyz.def - ____exports.abc = abc - ____exports.def = def + local ____xyz = require("xyz") + ____exports.abc = ____xyz.abc + ____exports.def = ____xyz.def end do - local ____xyz = require(\\"xyz\\") - local def = ____xyz.abc - ____exports.def = def + local ____xyz = require("xyz") + ____exports.def = ____xyz.abc +end +do + local ____bla = require("bla") + ____exports.bar = ____bla["123"] +end +do + local ____bla = require("bla") + ____exports["123"] = ____bla.foo end return ____exports" `; @@ -58,9 +79,10 @@ return ____exports" `; exports[`Transformation (methodRestArguments) 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class MyClass = __TS__Class() -MyClass.name = \\"MyClass\\" +MyClass.name = "MyClass" function MyClass.prototype.____constructor(self) end function MyClass.prototype.varargsFunction(self, a, ...) @@ -74,22 +96,24 @@ return ____exports" `; exports[`Transformation (modulesClassExport) 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class local ____exports = {} ____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass -TestClass.name = \\"TestClass\\" +TestClass.name = "TestClass" function TestClass.prototype.____constructor(self) end return ____exports" `; exports[`Transformation (modulesClassWithMemberExport) 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class local ____exports = {} ____exports.TestClass = __TS__Class() local TestClass = ____exports.TestClass -TestClass.name = \\"TestClass\\" +TestClass.name = "TestClass" function TestClass.prototype.____constructor(self) end function TestClass.prototype.memberFunc(self) @@ -111,14 +135,14 @@ end" exports[`Transformation (modulesImportAll) 1`] = ` "local ____exports = {} -local Test = require(\\"test\\") +local Test = require("test") local ____ = Test return ____exports" `; exports[`Transformation (modulesImportNamed) 1`] = ` "local ____exports = {} -local ____test = require(\\"test\\") +local ____test = require("test") local TestClass = ____test.TestClass local ____ = TestClass return ____exports" @@ -126,15 +150,15 @@ return ____exports" exports[`Transformation (modulesImportNamedSpecialChars) 1`] = ` "local ____exports = {} -local ____kebab_2Dmodule = require(\\"kebab-module\\") +local ____kebab_2Dmodule = require("kebab-module") local TestClass1 = ____kebab_2Dmodule.TestClass1 -local ____dollar_24module = require(\\"dollar$module\\") +local ____dollar_24module = require("dollar$module") local TestClass2 = ____dollar_24module.TestClass2 -local ____singlequote_27module = require(\\"singlequote'module\\") +local ____singlequote_27module = require("singlequote'module") local TestClass3 = ____singlequote_27module.TestClass3 -local ____hash_23module = require(\\"hash#module\\") +local ____hash_23module = require("hash#module") local TestClass4 = ____hash_23module.TestClass4 -local ____space_20module = require(\\"space module\\") +local ____space_20module = require("space module") local TestClass5 = ____space_20module.TestClass5 local ____ = TestClass1 local ____ = TestClass2 @@ -146,7 +170,7 @@ return ____exports" exports[`Transformation (modulesImportRenamed) 1`] = ` "local ____exports = {} -local ____test = require(\\"test\\") +local ____test = require("test") local RenamedClass = ____test.TestClass local ____ = RenamedClass return ____exports" @@ -154,15 +178,15 @@ return ____exports" exports[`Transformation (modulesImportRenamedSpecialChars) 1`] = ` "local ____exports = {} -local ____kebab_2Dmodule = require(\\"kebab-module\\") +local ____kebab_2Dmodule = require("kebab-module") local RenamedClass1 = ____kebab_2Dmodule.TestClass -local ____dollar_24module = require(\\"dollar$module\\") +local ____dollar_24module = require("dollar$module") local RenamedClass2 = ____dollar_24module.TestClass -local ____singlequote_27module = require(\\"singlequote'module\\") +local ____singlequote_27module = require("singlequote'module") local RenamedClass3 = ____singlequote_27module.TestClass -local ____hash_23module = require(\\"hash#module\\") +local ____hash_23module = require("hash#module") local RenamedClass4 = ____hash_23module.TestClass -local ____space_20module = require(\\"space module\\") +local ____space_20module = require("space module") local RenamedClass5 = ____space_20module.TestClass local ____ = RenamedClass1 local ____ = RenamedClass2 @@ -174,7 +198,7 @@ return ____exports" exports[`Transformation (modulesImportWithoutFromClause) 1`] = ` "local ____exports = {} -require(\\"test\\") +require("test") return ____exports" `; @@ -224,11 +248,35 @@ return ____exports" exports[`Transformation (modulesVariableExport) 1`] = ` "local ____exports = {} -____exports.foo = \\"bar\\" +____exports.foo = "bar" return ____exports" `; -exports[`Transformation (modulesVariableNoExport) 1`] = `"foo = \\"bar\\""`; +exports[`Transformation (modulesVariableNoExport) 1`] = `"foo = "bar""`; + +exports[`Transformation (printFormat) 1`] = ` +"stringConcat = (("a" .. "b" .. "c") .. "d") .. "e" +numbers = 2 * 2 + 3 + 4 * (5 + 6) ~= 7 +function func(...) +end +func(function() + local b = "A function" +end) +func(func()) +array = {func()} +array2 = { + func(), + func() +} +object = {a = 1, b = 2, c = 3} +bigObject = { + a = 1, + b = 2, + c = 3, + d = "value1", + e = "value2" +}" +`; exports[`Transformation (returnDefault) 1`] = ` "function myFunc(self) @@ -242,7 +290,8 @@ value1 = obj.value1 value2 = obj.value2 obj2 = {value3 = 1, value4 = 2} value3 = obj2.value3 -value4 = obj2.value4 +local ____obj2_0 = obj2 +value4 = ____obj2_0.value4 function fun1(self) end fun2 = function() @@ -251,7 +300,7 @@ end" exports[`Transformation (unusedDefaultWithNamespaceImport) 1`] = ` "local ____exports = {} -local x = require(\\"module\\") +local x = require("module") local ____ = x return ____exports" `; diff --git a/test/translation/transformation.spec.ts b/test/translation/transformation.spec.ts index 42a4b4355..5f9df58fe 100644 --- a/test/translation/transformation.spec.ts +++ b/test/translation/transformation.spec.ts @@ -19,3 +19,18 @@ test.each(fixtures)("Transformation (%s)", (_name, content) => { .disableSemanticCheck() .expectLuaToMatchSnapshot(); }); + +const luauFixturesPath = path.join(fixturesPath, "luau"); +const luauFixtures = fs + .readdirSync(luauFixturesPath) + .filter(f => path.extname(f) === ".ts") + .sort() + .map(f => [path.parse(f).name, fs.readFileSync(path.join(luauFixturesPath, f), "utf8")]); + +test.each(luauFixtures)("Luau-specific Transformation (%s)", (_name, content) => { + util.testModule(content) + .setOptions({ luaLibImport: tstl.LuaLibImportKind.Require, luaTarget: tstl.LuaTarget.Luau }) + .ignoreDiagnostics([annotationDeprecated.code, couldNotResolveRequire.code]) + .disableSemanticCheck() + .expectLuaToMatchSnapshot(); +}); diff --git a/test/translation/transformation/customNameWithExtraComment.ts b/test/translation/transformation/customNameWithExtraComment.ts new file mode 100644 index 000000000..459512ded --- /dev/null +++ b/test/translation/transformation/customNameWithExtraComment.ts @@ -0,0 +1,10 @@ +/** @noSelf */ +declare namespace TestNamespace { + /** + * @customName pass + * The first word should not be included. + **/ + function fail(): void; +} + +TestNamespace.fail(); diff --git a/test/translation/transformation/customNameWithNoSelf.ts b/test/translation/transformation/customNameWithNoSelf.ts new file mode 100644 index 000000000..73175ccdc --- /dev/null +++ b/test/translation/transformation/customNameWithNoSelf.ts @@ -0,0 +1,7 @@ +/** @noSelf */ +declare namespace TestNamespace { + /** @customName pass */ + function fail(): void; +} + +TestNamespace.fail(); diff --git a/test/translation/transformation/exportStatement.ts b/test/translation/transformation/exportStatement.ts index 7aa965422..cf227da3d 100644 --- a/test/translation/transformation/exportStatement.ts +++ b/test/translation/transformation/exportStatement.ts @@ -4,3 +4,5 @@ export { xyz as uwv }; export * from "xyz"; export { abc, def } from "xyz"; export { abc as def } from "xyz"; +export { "123" as bar } from "bla"; +export { foo as "123" } from "bla"; diff --git a/test/translation/transformation/luau/luauSpecificTransformations.ts b/test/translation/transformation/luau/luauSpecificTransformations.ts new file mode 100644 index 000000000..b4c9fdec4 --- /dev/null +++ b/test/translation/transformation/luau/luauSpecificTransformations.ts @@ -0,0 +1,9 @@ +const t = true ? "is true" : "is false"; + +while (false) { + continue; +} + +do { + continue; +} while (false); diff --git a/test/translation/transformation/printFormat.ts b/test/translation/transformation/printFormat.ts new file mode 100644 index 000000000..3374952c5 --- /dev/null +++ b/test/translation/transformation/printFormat.ts @@ -0,0 +1,27 @@ +const stringConcat = "a" + ("b" + "c") + "d" + "e"; +const numbers = 2 * 2 + 3 + 4 * (5 + 6) !== 7; + +function func(this: void, ...args: any) {} + +func(() => { + const b = "A function"; +}); + +func(func()); + +const array = [func()]; +const array2 = [func(), func()]; + +const object = { + a: 1, + b: 2, + c: 3, +}; + +const bigObject = { + a: 1, + b: 2, + c: 3, + d: "value1", + e: "value2", +}; diff --git a/test/transpile/__snapshots__/directories.spec.ts.snap b/test/transpile/__snapshots__/directories.spec.ts.snap index eaf179a6c..d214dbba7 100644 --- a/test/transpile/__snapshots__/directories.spec.ts.snap +++ b/test/transpile/__snapshots__/directories.spec.ts.snap @@ -1,33 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should be able to resolve ({"name": "basic", "options": [Object]}) 1`] = ` -Array [ +[ "directories/basic/src/lib/file.lua", - "directories/basic/src/lualib_bundle.lua", "directories/basic/src/main.lua", ] `; exports[`should be able to resolve ({"name": "basic", "options": [Object]}) 2`] = ` -Array [ +[ "directories/basic/out/lib/file.lua", - "directories/basic/out/lualib_bundle.lua", "directories/basic/out/main.lua", ] `; exports[`should be able to resolve ({"name": "basic", "options": [Object]}) 3`] = ` -Array [ +[ "directories/basic/src/lib/file.lua", - "directories/basic/src/lualib_bundle.lua", "directories/basic/src/main.lua", ] `; exports[`should be able to resolve ({"name": "basic", "options": [Object]}) 4`] = ` -Array [ +[ "directories/basic/out/lib/file.lua", - "directories/basic/out/lualib_bundle.lua", "directories/basic/out/main.lua", ] `; diff --git a/test/transpile/__snapshots__/module-resolution.spec.ts.snap b/test/transpile/__snapshots__/module-resolution.spec.ts.snap new file mode 100644 index 000000000..e87569ded --- /dev/null +++ b/test/transpile/__snapshots__/module-resolution.spec.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`supports complicated paths configuration 1`] = ` +[ + "/paths-base-tsconfig/dist/packages/tstl-program/packages/mypackage/src/bar.lua", + "/paths-base-tsconfig/dist/packages/tstl-program/packages/mypackage/src/index.lua", + "/paths-base-tsconfig/dist/packages/tstl-program/packages/myprogram/src/main.lua", +] +`; + +exports[`supports paths configuration 1`] = ` +[ + "/paths-simple/myprogram/dist/mypackage/bar.lua", + "/paths-simple/myprogram/dist/mypackage/index.lua", + "/paths-simple/myprogram/dist/myprogram/main.lua", +] +`; diff --git a/test/transpile/__snapshots__/project.spec.ts.snap b/test/transpile/__snapshots__/project.spec.ts.snap index 1effba209..227e004f8 100644 --- a/test/transpile/__snapshots__/project.spec.ts.snap +++ b/test/transpile/__snapshots__/project.spec.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should give verbose output 1`] = ` -Array [ +[ + "Loaded 0 plugins", "Parsing project settings", - "Successfully loaded 0 plugins", "Transforming /test/transpile/project/otherFile.ts", "Printing /test/transpile/project/otherFile.ts", "Transforming /test/transpile/project/index.ts", @@ -11,7 +11,7 @@ Array [ "Constructing emit plan", "Resolving dependencies for /test/transpile/project/otherFile.ts", "Resolving dependencies for /test/transpile/project/index.ts", - "Resolving \\"./otherFile\\" from /test/transpile/project", + "Resolving "./otherFile" from /test/transpile/project/index.ts", "Resolved ./otherFile to /test/transpile/project/otherFile.ts", "Emitting output", "Emitting /test/transpile/project/otherFile.lua", @@ -21,8 +21,8 @@ Array [ `; exports[`should transpile 1`] = ` -Array [ - Object { +[ + { "filePath": "otherFile.lua", "lua": "local ____exports = {} function ____exports.getNumber(self) @@ -31,10 +31,10 @@ end return ____exports ", }, - Object { + { "filePath": "index.lua", "lua": "local ____exports = {} -local ____otherFile = require(\\"otherFile\\") +local ____otherFile = require("otherFile") local getNumber = ____otherFile.getNumber local myNumber = getNumber(nil) setAPIValue(myNumber * 5) diff --git a/test/transpile/bundle.spec.ts b/test/transpile/bundle.spec.ts index 718e1b112..3834bbb2f 100644 --- a/test/transpile/bundle.spec.ts +++ b/test/transpile/bundle.spec.ts @@ -1,19 +1,132 @@ import * as path from "path"; import * as util from "../util"; +import { TranspileVirtualProjectResult } from "../../src"; +import { lineAndColumnOf } from "../unit/printer/utils"; +import * as fs from "fs"; -const projectDir = path.join(__dirname, "bundle"); -const inputProject = path.join(projectDir, "tsconfig.json"); +describe("bundle two files", () => { + const projectDir = path.join(__dirname, "bundle", "bundle-two-files"); + const inputProject = path.join(projectDir, "tsconfig.json"); -test("should transpile into one file", () => { - const { diagnostics, transpiledFiles } = util.testProject(inputProject).getLuaResult(); + let transpileResult: TranspileVirtualProjectResult = { + transpiledFiles: [], + diagnostics: [], + }; - expect(diagnostics).not.toHaveDiagnostics(); - expect(transpiledFiles).toHaveLength(1); + beforeAll(() => { + transpileResult = util.testProject(inputProject).getLuaResult(); + }); + + test("should transpile into one file (with no errors)", () => { + expect(transpileResult.diagnostics).not.toHaveDiagnostics(); + expect(transpileResult.transpiledFiles).toHaveLength(1); + }); - const { outPath, lua } = transpiledFiles[0]; // Verify the name is as specified in tsconfig - expect(outPath.endsWith(path.join("bundle", "bundle.lua"))).toBe(true); + test("should have name, specified in tsconfig.json", () => { + const { outPath } = transpileResult.transpiledFiles[0]; + expect(outPath.endsWith(path.join(projectDir, "bundle.lua"))).toBe(true); + }); + + // Verify exported module by executing + // Use an empty TS string because we already transpiled the TS project + test("executing should act correctly", () => { + const { lua } = transpileResult.transpiledFiles[0]; + util.testModule("").setLuaHeader(lua!).expectToEqual({ myNumber: 3 }); + }); +}); + +describe("bundle with source maps", () => { + const projectDir = path.join(__dirname, "bundle", "bundle-source-maps"); + const inputProject = path.join(projectDir, "tsconfig.json"); + + let transpileResult: TranspileVirtualProjectResult = { + transpiledFiles: [], + diagnostics: [], + }; + + beforeAll(() => { + transpileResult = util.testProject(inputProject).getLuaResult(); + }); + + // See https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1109 + test('the result file should not contain "{#SourceMapTraceback}" macro-string', () => { + const { lua } = transpileResult.transpiledFiles[0]; + expect(lua).toBeDefined(); + expect(lua!).not.toContain("{#SourceMapTraceback}"); + }); + // Verify exported module by executing // Use an empty TS string because we already transpiled the TS project - util.testModule("").setLuaHeader(lua!).expectToEqual({ myNumber: 3 }); + test("executing should act correctly", () => { + const { lua } = transpileResult.transpiledFiles[0]; + const result = util.testModule("").setLuaHeader(lua!).getLuaExecutionResult(); + + expect(result.myNumber).toEqual(3 * 4 * (5 + 6)); + }); + + test("sourceMapTraceback saves correct sourcemap", () => { + const code = { + index: fs.readFileSync(path.join(projectDir, "index.ts"), "utf8"), + largeFile: fs.readFileSync(path.join(projectDir, "largeFile.ts"), "utf8"), + }; + + const { lua } = transpileResult.transpiledFiles[0]; + const builder = util.testModule("").setLuaHeader(lua!); + const result = builder.getLuaExecutionResult(); + const sourceMap = result.sourceMap; + + expect(sourceMap).toEqual(expect.any(Object)); + const sourceMapFiles = Object.keys(sourceMap); + expect(sourceMapFiles).toHaveLength(1); + const mainSourceMap = sourceMap[sourceMapFiles[0]]; + + const transpiledLua = builder.getMainLuaCodeChunk(); + + const assertPatterns: Array<{ + file: keyof typeof code; + luaPattern: string; + typeScriptPattern: string; + }> = [ + { + file: "index", + luaPattern: "____exports.myNumber = getNumber(", + typeScriptPattern: "const myNumber = getNumber(", + }, + { + file: "largeFile", + luaPattern: "local Calculator = __TS__Class()", + typeScriptPattern: "abstract class Calculator", + }, + { + file: "largeFile", + luaPattern: "local CalculatorMul = __TS__Class()", + typeScriptPattern: "class CalculatorMul extends Calculator {", + }, + { + file: "largeFile", + luaPattern: "local function resolveCalculatorClass(", + typeScriptPattern: "function resolveCalculatorClass(", + }, + { + file: "largeFile", + luaPattern: "function ____exports.getNumber(", + typeScriptPattern: "export function getNumber(", + }, + { + file: "largeFile", + luaPattern: 'Error,\n "Unknown operation "', + typeScriptPattern: "throw new Error(", + }, + ]; + + for (const { file: currentFile, luaPattern, typeScriptPattern } of assertPatterns) { + const luaPosition = lineAndColumnOf(transpiledLua, luaPattern); + const mappedLine: { file: string; line: number } = mainSourceMap[luaPosition.line.toString()]; + + const typescriptPosition = lineAndColumnOf(code[currentFile], typeScriptPattern); + expect(mappedLine.line).toEqual(typescriptPosition.line); + expect(mappedLine.file).toBe(`${currentFile}.ts`); + } + }); }); diff --git a/test/transpile/bundle/bundle-source-maps/index.ts b/test/transpile/bundle/bundle-source-maps/index.ts new file mode 100644 index 000000000..22a2f499e --- /dev/null +++ b/test/transpile/bundle/bundle-source-maps/index.ts @@ -0,0 +1,8 @@ +import { getNumber, Operation } from "./largeFile"; + +// Local variables +const left = getNumber(3, 4, Operation.MUL); +const right = getNumber(5, 6, Operation.SUM); + +export const myNumber = getNumber(left, right, Operation.MUL); +export const sourceMap = (globalThis as any).__TS__sourcemap; diff --git a/test/transpile/bundle/bundle-source-maps/largeFile.ts b/test/transpile/bundle/bundle-source-maps/largeFile.ts new file mode 100644 index 000000000..ae0a9be7a --- /dev/null +++ b/test/transpile/bundle/bundle-source-maps/largeFile.ts @@ -0,0 +1,53 @@ +// Some comments here to check source map correctness +// Some comments here to check source map correctness + +abstract class Calculator { + protected left: number; + protected right: number; + + constructor(left: number, right: number) { + this.left = left; + this.right = right; + } + + public abstract calc(): number; +} + +/** + * Sums two numbers + */ +class CalculatorSum extends Calculator { + public calc(): number { + return this.left + this.right; + } +} + +class CalculatorMul extends Calculator { + public calc(): number { + return this.left * this.right; + } +} + +// Some comments here to check source map correctness + +export const enum Operation { + SUM = "SUM", + MUL = "MUL", +} + +// Local internal function +function resolveCalculatorClass(left: number, right: number, operation: Operation): Calculator { + if (operation === Operation.MUL) { + return new CalculatorMul(left, right); + } + if (operation === Operation.SUM) { + return new CalculatorSum(left, right); + } + + throw new Error(`Unknown operation ${operation}`); +} + +// Some comments here to check source map correctness +export function getNumber(left: number, right: number, operation: Operation): number { + return resolveCalculatorClass(left, right, operation).calc(); +} diff --git a/test/transpile/bundle/bundle-source-maps/tsconfig.json b/test/transpile/bundle/bundle-source-maps/tsconfig.json new file mode 100644 index 000000000..6614ac5d7 --- /dev/null +++ b/test/transpile/bundle/bundle-source-maps/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "target": "esnext", + "lib": ["esnext"], + "types": ["lua-types/5.3"], + "rootDir": "." + }, + "tstl": { + "luaBundle": "bundle.lua", + "luaBundleEntry": "index.ts", + "sourceMapTraceback": true + }, + "include": ["."] +} diff --git a/test/transpile/bundle/index.ts b/test/transpile/bundle/bundle-two-files/index.ts similarity index 100% rename from test/transpile/bundle/index.ts rename to test/transpile/bundle/bundle-two-files/index.ts diff --git a/test/transpile/bundle/otherFile.ts b/test/transpile/bundle/bundle-two-files/otherFile.ts similarity index 100% rename from test/transpile/bundle/otherFile.ts rename to test/transpile/bundle/bundle-two-files/otherFile.ts diff --git a/test/transpile/bundle/tsconfig.json b/test/transpile/bundle/bundle-two-files/tsconfig.json similarity index 100% rename from test/transpile/bundle/tsconfig.json rename to test/transpile/bundle/bundle-two-files/tsconfig.json diff --git a/test/transpile/directories.spec.ts b/test/transpile/directories.spec.ts index 1c0bba994..9572c1e0d 100644 --- a/test/transpile/directories.spec.ts +++ b/test/transpile/directories.spec.ts @@ -19,7 +19,7 @@ test.each([ const config = { compilerOptions: { ...compilerOptions, types: [], skipLibCheck: true }, - tstl: { luaTarget: tstl.LuaTarget.LuaJIT, luaLibImport: tstl.LuaLibImportKind.Always }, + tstl: { luaTarget: tstl.LuaTarget.LuaJIT }, }; const { fileNames, options } = tstl.updateParsedConfigFile( diff --git a/test/transpile/lualib.spec.ts b/test/transpile/lualib.spec.ts new file mode 100644 index 000000000..20288bd8a --- /dev/null +++ b/test/transpile/lualib.spec.ts @@ -0,0 +1,31 @@ +import * as ts from "typescript"; +import { LuaLibFeature, LuaTarget } from "../../src"; +import { readLuaLibFeature } from "../../src/LuaLib"; +import * as util from "../util"; + +test.each(Object.entries(LuaLibFeature))("Lualib does not use ____exports (%p)", (_, feature) => { + const lualibCode = readLuaLibFeature(feature, LuaTarget.Lua54, ts.sys); + + const exportsOccurrences = lualibCode.match(/____exports/g); + expect(exportsOccurrences).toBeNull(); +}); + +test("Lualib bundle does not assign globals", () => { + // language=TypeScript + util.testModule` + declare const _G: LuaTable; + declare const require: (this: void, module: string) => any; + const globalKeys = new LuaTable(); + for (const [key] of _G) { + globalKeys[key] = true; + } + require("lualib_bundle"); + for (const [key] of _G) { + if (!globalKeys[key]) { + error("Global was assigned: " + key); + } + } + ` + .withLanguageExtensions() + .expectNoExecutionError(); +}); diff --git a/test/transpile/module-resolution.spec.ts b/test/transpile/module-resolution.spec.ts index b995e75a5..35e79ed3d 100644 --- a/test/transpile/module-resolution.spec.ts +++ b/test/transpile/module-resolution.spec.ts @@ -2,7 +2,8 @@ import * as path from "path"; import * as tstl from "../../src"; import * as util from "../util"; import * as ts from "typescript"; -import { transpileProject } from "../../src"; +import { BuildMode } from "../../src"; +import { normalizeSlashes } from "../../src/utils"; describe("basic module resolution", () => { const projectPath = path.resolve(__dirname, "module-resolution", "project-with-node-modules"); @@ -49,7 +50,7 @@ describe("basic module resolution", () => { test("can resolve package depencency with a dependency on another package", () => { // Declarations in the node_modules directory - expect(projectWithNodeModules.getLuaExecutionResult().moduleWithDependencyResult).toEqual( + expect(projectWithNodeModules.getLuaExecutionResult().moduleWithDependencyResult).toBe( "Calling dependency: foo from lua module with decls" ); }); @@ -172,6 +173,22 @@ describe("module resolution with sourceDir", () => { .setOptions({ luaBundle: "bundle.lua", luaBundleEntry: mainFile }) .expectToEqual(expectedResult); }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1394 + test("can resolve files with non-standard extension (#1394)", () => { + util.testProject(path.join(projectPath, "tsconfig.json")) + .setMainFileName(path.join(projectPath, "src", "main.ts")) + .setOptions({ outDir: "tstl-out", extension: ".script" }) + .expectToEqual(expectedResult); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1394 + test("can resolve files with non-standard extension without separator (#1394)", () => { + util.testProject(path.join(projectPath, "tsconfig.json")) + .setMainFileName(path.join(projectPath, "src", "main.ts")) + .setOptions({ outDir: "tstl-out", extension: "script" }) + .expectToEqual(expectedResult); + }); }); describe("module resolution project with lua sources", () => { @@ -236,8 +253,8 @@ describe("module resolution project with dependencies built by tstl library mode const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tstl-library-modules"); // First compile dependencies into node_modules. NOTE: Actually writing to disk, very slow - transpileProject(path.join(projectPath, "dependency1-ts", "tsconfig.json")); - transpileProject(path.join(projectPath, "dependency2-ts", "tsconfig.json")); + tstl.transpileProject(path.join(projectPath, "dependency1-ts", "tsconfig.json")); + tstl.transpileProject(path.join(projectPath, "dependency2-ts", "tsconfig.json")); const expectedResult = { dependency1IndexResult: "function in dependency 1 index: dependency1OtherFileFunc in dependency1/d1otherfile", @@ -247,10 +264,18 @@ describe("module resolution project with dependencies built by tstl library mode }; test("can resolve lua dependencies", () => { - util.testProject(path.join(projectPath, "tsconfig.json")) + const transpileResult = util + .testProject(path.join(projectPath, "tsconfig.json")) .setMainFileName(path.join(projectPath, "main.ts")) .setOptions({ outDir: "tstl-out" }) - .expectToEqual(expectedResult); + .expectToEqual(expectedResult) + .getLuaResult(); + + // Assert node_modules file requires the correct lualib_bundle + const requiringLuaFile = path.join("lua_modules", "dependency1", "index.lua"); + const lualibRequiringFile = transpileResult.transpiledFiles.find(f => f.outPath.endsWith(requiringLuaFile)); + expect(lualibRequiringFile).toBeDefined(); + expect(lualibRequiringFile?.lua).toContain('require("lualib_bundle")'); }); test("can resolve dependencies and bundle", () => { @@ -262,6 +287,51 @@ describe("module resolution project with dependencies built by tstl library mode }); }); +describe("module resolution project with dependencies built by tstl library mode and has exports field", () => { + const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tstl-library-has-exports-field"); + + // First compile dependencies into node_modules. NOTE: Actually writing to disk, very slow + const dependency1Path = path.join(projectPath, "node_modules", "dependency1"); + tstl.transpileProject(path.join(dependency1Path, "tsconfig.json")); + + const expectedResult = { + dependency1IndexResult: "function in dependency 1 index: dependency1OtherFileFunc in dependency1/d1otherfile", + dependency1OtherFileFuncResult: "dependency1OtherFileFunc in dependency1/d1otherfile", + }; + + test("can resolve lua dependencies", () => { + const transpileResult = util + .testProject(path.join(projectPath, "tsconfig.json")) + .setMainFileName(path.join(projectPath, "main.ts")) + .setOptions({ + outDir: "tstl-out", + moduleResolution: ts.ModuleResolutionKind.Node16, + module: ts.ModuleKind.Node16, + }) + .expectToEqual(expectedResult) + .getLuaResult(); + + // Assert node_modules file requires the correct lualib_bundle + const requiringLuaFile = path.join("lua_modules", "dependency1", "dist", "index.lua"); + const lualibRequiringFile = transpileResult.transpiledFiles.find(f => f.outPath.endsWith(requiringLuaFile)); + expect(lualibRequiringFile).toBeDefined(); + expect(lualibRequiringFile?.lua).toContain('require("lualib_bundle")'); + }); + + test("can resolve dependencies and bundle", () => { + const mainFile = path.join(projectPath, "main.ts"); + util.testProject(path.join(projectPath, "tsconfig.json")) + .setMainFileName(mainFile) + .setOptions({ + luaBundle: "bundle.lua", + luaBundleEntry: mainFile, + moduleResolution: ts.ModuleResolutionKind.Node16, + module: ts.ModuleKind.Node16, + }) + .expectToEqual(expectedResult); + }); +}); + // Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1037 describe("module resolution with tsx", () => { const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tsx"); @@ -275,3 +345,404 @@ describe("module resolution with tsx", () => { }); }); }); + +describe("dependency with complicated inner structure", () => { + const projectPath = path.resolve(__dirname, "module-resolution", "project-with-complicated-dependency"); + const tsConfigPath = path.join(projectPath, "tsconfig.json"); + const mainFilePath = path.join(projectPath, "main.ts"); + + const expectedResult = { + otherFileResult: "someFunc from otherfile.lua", + otherFileUtil: "util", + subsubresult: "result from subsub dir", + utilResult: "util", + subdirwithInitResult: "a", + }; + + // Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1055 + test("bundle should not contain duplicate files", () => { + const mainFile = path.join(projectPath, "main.ts"); + const { transpiledFiles } = util + .testProject(tsConfigPath) + .setMainFileName(mainFilePath) + .setOptions({ luaBundle: "bundle.lua", luaBundleEntry: mainFile }) + .expectToEqual(expectedResult) + .getLuaResult(); + + expect(transpiledFiles).toHaveLength(1); + const lua = transpiledFiles[0].lua!; + // util is used in 2 places, but should only occur once in the bundle + const utilModuleOccurrences = (lua.match(/\["lua_modules\.dependency1\.util"\]/g) ?? []).length; + expect(utilModuleOccurrences).toBe(1); + }); + + // Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1054 + test("should be able to resolve dependency files in subdirectories", () => { + util.testProject(tsConfigPath).setMainFileName(mainFilePath).expectToEqual(expectedResult); + }); +}); + +test("module resolution should not try to resolve @noResolution annotation", () => { + util.testModule` + import * as json from "json"; + const test = json.decode("{}"); + ` + .addExtraFile( + "json.d.ts", + ` + /** @noResolution */ + declare module "json" { + function encode(this: void, data: unknown): string; + function decode(this: void, data: string): unknown; + } + ` + ) + .expectToHaveNoDiagnostics(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1101 +test("module resolution inline require of environment library workaround", () => { + util.testModule` + declare function require(this: void, module: string): any; + + const test = require("@NoResolution:luasource"); + test.foo(); + `.expectToHaveNoDiagnostics(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1118 +describe("module resolution should not try to resolve modules in noResolvePaths", () => { + test("as used in direct import", () => { + util.testModule` + import * as lua from "directimport"; + lua.foo(); + ` + .addExtraFile( + "directimport.d.ts", + `declare module "directimport" { + export function foo(): void; + }` + ) + .setOptions({ noResolvePaths: ["directimport"] }) + .expectToHaveNoDiagnostics(); + }); + + test("as used in imported lua sources", () => { + util.testModule` + import * as lua from "./luasource"; + lua.foo(); + ` + .addExtraFile("luasource.d.ts", "export function foo(): void;") + .addExtraFile( + "luasource.lua", + ` + require("dontResolveThis") + require("a.b.c.foo") + + return { foo = function() return "bar" end } + ` + ) + .setOptions({ noResolvePaths: ["a.b.c.foo", "somethingExtra", "dontResolveThis"] }) + .expectToHaveNoDiagnostics(); + }); + + test("can ignore specific files with glob pattern", () => { + util.testModule` + // Pre-Load as to not error out at runtime + import "preload"; + + import "ignoreme"; + import * as b from "./actualfile"; + + export const result = b.foo(); + ` + .addExtraFile("preload.d.ts", `declare module "preload" {}`) + .addExtraFile("preload.lua", 'package.preload["ignoreme"] = function() return nil end') + .addExtraFile( + "actualfile.ts", + `export function foo() + { + return 'foo'; + }` + ) + .addExtraFile( + "ignoreme.d.ts", + `declare module "ignoreme" { + export function foo(): void; + }` + ) + .setOptions({ noResolvePaths: ["ignore*"] }) + .expectToHaveNoDiagnostics() + .expectToEqual({ result: "foo" }); + }); + + test("can ignore all files with glob pattern in require", () => { + util.testModule` + declare function require(this: void, module: string): any; + + const a = require("a") + const b = require("b/b") + const c = require("c/c/c") + const d = require("!:?somefile") + ` + .setOptions({ noResolvePaths: ["**"] }) + .expectToHaveNoDiagnostics(); + }); + + test("can ignore all files with glob pattern as used in imported lua sources", () => { + util.testModule` + import * as lua from "./luasource"; + lua.foo(); + ` + .addExtraFile("luasource.d.ts", "export function foo(): void;") + .addExtraFile( + "luasource.lua", + ` + require("ignoreme!") + require("i.g.n.o.r.e") + ` + ) + .setOptions({ noResolvePaths: ["**"] }) + .expectToHaveNoDiagnostics(); + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1062 +test("module resolution should not rewrite @NoResolution requires in library mode", () => { + const { transpiledFiles } = util.testModule` + import * as json from "json"; + const test = json.decode("{}"); + ` + .addExtraFile( + "json.d.ts", + ` + /** @noResolution */ + declare module "json" { + function encode(this: void, data: unknown): string; + function decode(this: void, data: string): unknown; + } + ` + ) + .setOptions({ buildMode: BuildMode.Library }) + .getLuaResult(); + + expect(transpiledFiles).toHaveLength(1); + expect(transpiledFiles[0].lua).toContain('require("@NoResolution:'); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1050 +test("module resolution should not try to resolve require-like functions", () => { + util.testModule` + function custom_require(this: void, value: string) { + return value; + } + + namespace ns { + export function require(this: void, value: string) { + return value; + } + } + + class MyClass { + require(value: string) { + return value; + } + } + const inst = new MyClass(); + + export const result = [ + custom_require("value 1"), + ns.require("value 2"), + inst.require("value 3") + ]; + + ` + .expectToHaveNoDiagnostics() + .expectToEqual({ + result: ["value 1", "value 2", "value 3"], + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1050 +test("module resolution uses baseURL to resolve imported files", () => { + util.testModule` + import { foo } from "dep1"; + import { bar } from "dep2"; + import { baz } from "luadep"; + + export const fooResult = foo(); + export const barResult = bar(); + export const bazResult = baz(); + ` + .addExtraFile( + "myproject/mydeps/dep1.ts", + ` + export function foo() { return "foo"; } + ` + ) + .addExtraFile( + "myproject/mydeps/dep2.ts", + ` + export function bar() { return "bar"; } + ` + ) + .addExtraFile( + "myproject/mydeps/luadep.d.ts", + ` + export function baz(): string; + ` + ) + .addExtraFile( + "myproject/mydeps/luadep.lua", + ` + return { baz = function() return "baz" end } + ` + ) + .setOptions({ baseUrl: "./myproject/mydeps", ignoreDeprecations: "6.0" }) + .expectToEqual({ + fooResult: "foo", + barResult: "bar", + bazResult: "baz", + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1071 +test("includes lualib_bundle when external lua requests it", () => { + util.testModule` + export { foo } from "./lualibuser"; + ` + .addExtraFile( + "lualibuser.d.ts", + ` + export const foo: string[]; + ` + ) + .addExtraFile( + "lualibuser.lua", + ` + local ____lualib = require("lualib_bundle") + local __TS__ArrayPush = ____lualib.__TS__ArrayPush + + local result = {} + __TS__ArrayPush(result, "foo") + __TS__ArrayPush(result, "bar") + + return { foo = result } + ` + ) + .expectToEqual({ + foo: ["foo", "bar"], + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1146 +test("require matches correct pattern", () => { + util.testModule` + declare function require(this: void, module: string): any; + export const addResult = require("a").foo + require("b").foo; + export const callResult = require("c")("foo"); + ` + .addExtraFile("a.lua", "return { foo = 3 }") + .addExtraFile("b.lua", "return { foo = 5 }") + .addExtraFile("c.lua", "return function(self, a) return a end") + .expectToEqual({ addResult: 3 + 5, callResult: "foo" }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1307 +test("lualib_module with parent directory import (#1307)", () => { + const projectDir = path.join(__dirname, "module-resolution", "project-with-dependency-with-same-file-names"); + const inputProject = path.join(projectDir, "tsconfig.json"); + + util.testProject(inputProject).setMainFileName(path.join(projectDir, "index.ts")).expectToEqual({ + // eslint-disable-next-line @typescript-eslint/naming-convention + BASE_CONSTANT: 123, + // eslint-disable-next-line @typescript-eslint/naming-convention + FEATURE_CONSTANT: 456, + }); +}); + +test("supports paths configuration", () => { + // Package root + const baseProjectPath = path.resolve(__dirname, "module-resolution", "paths-simple"); + // myprogram package + const projectPath = path.join(baseProjectPath, "myprogram"); + const projectTsConfig = path.join(projectPath, "tsconfig.json"); + const mainFile = path.join(projectPath, "main.ts"); + + const luaResult = util + .testProject(projectTsConfig) + .setMainFileName(mainFile) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + expect(snapshotPaths(luaResult.transpiledFiles)).toMatchSnapshot(); + + // Bundle to have all files required to execute and check result + util.testProject(projectTsConfig) + .setMainFileName(mainFile) + .setOptions({ luaBundle: "bundle.lua", luaBundleEntry: mainFile }) + .expectToEqual({ foo: 314, bar: 271 }); +}); + +test("supports complicated paths configuration", () => { + // Package root + const baseProjectPath = path.resolve(__dirname, "module-resolution", "paths-base-tsconfig"); + // myprogram package + const projectPath = path.join(baseProjectPath, "packages", "myprogram"); + const projectTsConfig = path.join(projectPath, "tsconfig.json"); + const mainFile = path.join(projectPath, "src", "main.ts"); + + const luaResult = util + .testProject(projectTsConfig) + .setMainFileName(mainFile) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + expect(snapshotPaths(luaResult.transpiledFiles)).toMatchSnapshot(); + + // Bundle to have all files required to execute + util.testProject(projectTsConfig) + .setMainFileName(mainFile) + .setOptions({ luaBundle: "bundle.lua", luaBundleEntry: mainFile }) + .expectToEqual({ foo: 314, bar: 271 }); +}); + +test("paths mapping wins over sibling project file (TS resolution order)", () => { + const baseProjectPath = path.resolve(__dirname, "module-resolution", "paths-vs-project-file"); + const projectPath = path.join(baseProjectPath, "program"); + const projectTsConfig = path.join(projectPath, "tsconfig.json"); + const mainFile = path.join(projectPath, "main.ts"); + + util.testProject(projectTsConfig) + .setMainFileName(mainFile) + .setOptions({ luaBundle: "bundle.lua", luaBundleEntry: mainFile }) + .expectToEqual({ value: "paths-mapped" }); +}); + +test("module resolution using plugin", () => { + const baseProjectPath = path.resolve(__dirname, "module-resolution", "project-with-module-resolution-plugin"); + const projectTsConfig = path.join(baseProjectPath, "tsconfig.json"); + const mainFile = path.join(baseProjectPath, "main.ts"); + + const testBuilder = util + .testProject(projectTsConfig) + .setMainFileName(mainFile) + .setOptions({ + luaPlugins: [ + { + name: path.join(__dirname, "./plugins/moduleResolution.ts"), + }, + ], + }) + .expectToHaveNoDiagnostics(); + + const luaResult = testBuilder.getLuaResult(); + + expect(luaResult.transpiledFiles).toHaveLength(3); + + testBuilder.expectToEqual({ result: ["foo", "absolutefoo"] }); +}); + +function snapshotPaths(files: tstl.TranspiledFile[]) { + return files.map(f => normalizeSlashes(f.outPath).split("module-resolution")[1]).sort(); +} diff --git a/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/bar.ts b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/bar.ts new file mode 100644 index 000000000..fef4e9ed6 --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/bar.ts @@ -0,0 +1 @@ +export const bar = 271; diff --git a/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/index.ts b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/index.ts new file mode 100644 index 000000000..c932fa9f5 --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/src/index.ts @@ -0,0 +1 @@ +export const foo = 314; diff --git a/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/tsconfig.json b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/tsconfig.json new file mode 100644 index 000000000..5ac343336 --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/packages/mypackage/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/packages/tstl-module" + }, + "include": ["./src/**/*.ts"] +} diff --git a/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/src/main.ts b/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/src/main.ts new file mode 100644 index 000000000..973b93922 --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/src/main.ts @@ -0,0 +1,4 @@ +import { foo } from "mypackage"; +import { bar } from "mypackage/bar"; + +export { foo, bar }; diff --git a/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/tsconfig.json b/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/tsconfig.json new file mode 100644 index 000000000..a0ba7c18e --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/packages/myprogram/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/packages/tstl-program" + }, + "include": ["./src/**/*.ts"] +} diff --git a/test/transpile/module-resolution/paths-base-tsconfig/tsconfig.base.json b/test/transpile/module-resolution/paths-base-tsconfig/tsconfig.base.json new file mode 100644 index 000000000..4d3934b0d --- /dev/null +++ b/test/transpile/module-resolution/paths-base-tsconfig/tsconfig.base.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "rootDir": ".", + "baseUrl": ".", + "ignoreDeprecations": "6.0", + "paths": { + "mypackage": ["packages/mypackage/src/index.ts"], + "mypackage/*": ["packages/mypackage/src/*"] + } + } +} diff --git a/test/transpile/module-resolution/paths-simple/mypackage/bar.ts b/test/transpile/module-resolution/paths-simple/mypackage/bar.ts new file mode 100644 index 000000000..fef4e9ed6 --- /dev/null +++ b/test/transpile/module-resolution/paths-simple/mypackage/bar.ts @@ -0,0 +1 @@ +export const bar = 271; diff --git a/test/transpile/module-resolution/paths-simple/mypackage/index.ts b/test/transpile/module-resolution/paths-simple/mypackage/index.ts new file mode 100644 index 000000000..c932fa9f5 --- /dev/null +++ b/test/transpile/module-resolution/paths-simple/mypackage/index.ts @@ -0,0 +1 @@ +export const foo = 314; diff --git a/test/transpile/module-resolution/paths-simple/mypackage/tsconfig.json b/test/transpile/module-resolution/paths-simple/mypackage/tsconfig.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/transpile/module-resolution/paths-simple/mypackage/tsconfig.json @@ -0,0 +1 @@ +{} diff --git a/test/transpile/module-resolution/paths-simple/myprogram/main.ts b/test/transpile/module-resolution/paths-simple/myprogram/main.ts new file mode 100644 index 000000000..e7687877a --- /dev/null +++ b/test/transpile/module-resolution/paths-simple/myprogram/main.ts @@ -0,0 +1,4 @@ +import { foo } from "myOtherPackage"; +import { bar } from "myOtherPackage/bar"; + +export { foo, bar }; diff --git a/test/transpile/module-resolution/paths-simple/myprogram/tsconfig.json b/test/transpile/module-resolution/paths-simple/myprogram/tsconfig.json new file mode 100644 index 000000000..a21584fac --- /dev/null +++ b/test/transpile/module-resolution/paths-simple/myprogram/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "rootDir": "..", + "outDir": "dist", + "paths": { + "myOtherPackage": ["../mypackage"], + "myOtherPackage/*": ["../mypackage/*"] + } + } +} diff --git a/test/transpile/module-resolution/paths-vs-project-file/other/alias.ts b/test/transpile/module-resolution/paths-vs-project-file/other/alias.ts new file mode 100644 index 000000000..b09331910 --- /dev/null +++ b/test/transpile/module-resolution/paths-vs-project-file/other/alias.ts @@ -0,0 +1 @@ +export const value = "paths-mapped"; diff --git a/test/transpile/module-resolution/paths-vs-project-file/program/alias.ts b/test/transpile/module-resolution/paths-vs-project-file/program/alias.ts new file mode 100644 index 000000000..565154b68 --- /dev/null +++ b/test/transpile/module-resolution/paths-vs-project-file/program/alias.ts @@ -0,0 +1 @@ +export const value = "project-file"; diff --git a/test/transpile/module-resolution/paths-vs-project-file/program/main.ts b/test/transpile/module-resolution/paths-vs-project-file/program/main.ts new file mode 100644 index 000000000..7b4bc6587 --- /dev/null +++ b/test/transpile/module-resolution/paths-vs-project-file/program/main.ts @@ -0,0 +1,3 @@ +import { value } from "alias"; + +export { value }; diff --git a/test/transpile/module-resolution/paths-vs-project-file/program/tsconfig.json b/test/transpile/module-resolution/paths-vs-project-file/program/tsconfig.json new file mode 100644 index 000000000..26c1a151f --- /dev/null +++ b/test/transpile/module-resolution/paths-vs-project-file/program/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "rootDir": "..", + "outDir": "dist", + "paths": { + "alias": ["../other/alias"] + } + } +} diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/main.ts b/test/transpile/module-resolution/project-with-complicated-dependency/main.ts new file mode 100644 index 000000000..70d8123fa --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/main.ts @@ -0,0 +1,7 @@ +import * as dependency1 from "dependency1"; + +export const otherFileResult = dependency1.otherFileFromDependency1(); +export const utilResult = dependency1.callUtil(); +export const otherFileUtil = dependency1.otherFileUtil(); +export const subsubresult = dependency1.subsubdirfileResult; +export const subdirwithInitResult = dependency1.subdirWithInitResult; diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.d.ts b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.d.ts new file mode 100644 index 000000000..28f4f5baa --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.d.ts @@ -0,0 +1,6 @@ +/** @noSelfInFile */ +export declare function otherFileFromDependency1(): string; +export declare function callUtil(): string; +export declare function otherFileUtil(): string; +export const subsubdirfileResult: string; +export const subdirWithInitResult: string; \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.lua new file mode 100644 index 000000000..c3838b1f4 --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/index.lua @@ -0,0 +1,18 @@ +local otherfile = require("otherfile") +local util = require("util") +local subdirfile = require("subdir.subdirfile") +local othersubdirfile = require("subdir.othersubdirfile") +local subsubdirfile = require("subdir.subsubdir.subsubdirfile") +local subdirwithinit = require("subdirwithinit") + +return { + otherFileFromDependency1 = otherfile.someFunc, + callUtil = function() + return util.utilf() + end, + otherFileUtil = otherfile.callUtil, + subdirfileResult = subdirfile.subdirfileResult, + othersubdirfileResult = othersubdirfile.othersubdirfileResult, + subsubdirfileResult = subsubdirfile.subsubresult, + subdirWithInitResult = subdirwithinit.a() +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/otherfile.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/otherfile.lua new file mode 100644 index 000000000..0fb8719ac --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/otherfile.lua @@ -0,0 +1,10 @@ +local util = require("util") + +return { + someFunc = function() + return "someFunc from otherfile.lua" + end, + callUtil = function() + return util.utilf() + end +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/othersubdirfile.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/othersubdirfile.lua new file mode 100644 index 000000000..45e5c985f --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/othersubdirfile.lua @@ -0,0 +1,3 @@ +return { + result = "result from other subdirectory file" +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subdirfile.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subdirfile.lua new file mode 100644 index 000000000..fe26400a1 --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subdirfile.lua @@ -0,0 +1,5 @@ +local othersubdirfile = require("subdir.othersubdirfile") +return { + subdirfileResult = "result from subdirectory file!", + othersubdirfileResult = othersubdirfile.result +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subsubdir/subsubdirfile.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subsubdir/subsubdirfile.lua new file mode 100644 index 000000000..581c8f858 --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdir/subsubdir/subsubdirfile.lua @@ -0,0 +1,3 @@ +return { + subsubresult = "result from subsub dir" +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdirwithinit/init.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdirwithinit/init.lua new file mode 100644 index 000000000..f26612a6f --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/subdirwithinit/init.lua @@ -0,0 +1,3 @@ +return { + a = function() return "a" end +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/util.lua b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/util.lua new file mode 100644 index 000000000..e4e812406 --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/node_modules/dependency1/util.lua @@ -0,0 +1,3 @@ +return { + utilf = function() return "util" end, +} \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-complicated-dependency/tsconfig.json b/test/transpile/module-resolution/project-with-complicated-dependency/tsconfig.json new file mode 100644 index 000000000..b76533290 --- /dev/null +++ b/test/transpile/module-resolution/project-with-complicated-dependency/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "strict": true, + "moduleResolution": "Node", + "target": "esnext", + "lib": ["esnext"], + "types": [], + "rootDir": "." + } +} diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/index.ts b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/index.ts new file mode 100644 index 000000000..0ab21dc4e --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/index.ts @@ -0,0 +1 @@ +export * from "mymodule"; diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/constants.lua b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/constants.lua new file mode 100644 index 000000000..de5917dd7 --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/constants.lua @@ -0,0 +1,3 @@ +local ____exports = {} +____exports.BASE_CONSTANT = 123 +return ____exports diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/constants.lua b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/constants.lua new file mode 100644 index 000000000..9d3bd6110 --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/constants.lua @@ -0,0 +1,3 @@ +local ____exports = {} +____exports.FEATURE_CONSTANT = 456 +return ____exports diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/feature.lua b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/feature.lua new file mode 100644 index 000000000..103496eaa --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/feature/feature.lua @@ -0,0 +1,8 @@ +local ____exports = {} +local ____constants = require("constants") +local BASE_CONSTANT = ____constants.BASE_CONSTANT +local ____constants = require("feature.constants") +local FEATURE_CONSTANT = ____constants.FEATURE_CONSTANT +____exports.BASE_CONSTANT = BASE_CONSTANT +____exports.FEATURE_CONSTANT = FEATURE_CONSTANT +return ____exports diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.d.ts b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.d.ts new file mode 100644 index 000000000..90401efad --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.d.ts @@ -0,0 +1,2 @@ +export declare const BASE_CONSTANT: number; +export declare const FEATURE_CONSTANT: number; diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.lua b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.lua new file mode 100644 index 000000000..4e57411d3 --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/node_modules/mymodule/index.lua @@ -0,0 +1,10 @@ +local ____exports = {} +do + local ____export = require("feature.feature") + for ____exportKey, ____exportValue in pairs(____export) do + if ____exportKey ~= "default" then + ____exports[____exportKey] = ____exportValue + end + end +end +return ____exports diff --git a/test/transpile/module-resolution/project-with-dependency-with-same-file-names/tsconfig.json b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/tsconfig.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/transpile/module-resolution/project-with-dependency-with-same-file-names/tsconfig.json @@ -0,0 +1 @@ +{} diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutebar.lua b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutebar.lua new file mode 100644 index 000000000..35718ddea --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutebar.lua @@ -0,0 +1,5 @@ +local ____exports = {} +function ____exports.absolutefoo(self) + return "absolutefoo" +end +return ____exports \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutefoo.d.ts b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutefoo.d.ts new file mode 100644 index 000000000..9df109b2e --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/absolutefoo.d.ts @@ -0,0 +1 @@ +export declare function absolutefoo(): string; diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/bar.lua b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/bar.lua new file mode 100644 index 000000000..b821a15b5 --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/bar.lua @@ -0,0 +1,5 @@ +local ____exports = {} +function ____exports.foo(self) + return "foo" +end +return ____exports \ No newline at end of file diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/foo.d.ts b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/foo.d.ts new file mode 100644 index 000000000..27e069e94 --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/lua_sources/foo.d.ts @@ -0,0 +1 @@ +export declare function foo(): string; diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/main.ts b/test/transpile/module-resolution/project-with-module-resolution-plugin/main.ts new file mode 100644 index 000000000..e3e6bc616 --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/main.ts @@ -0,0 +1,3 @@ +import { foo } from "./lua_sources/foo"; +import { absolutefoo } from "./lua_sources/absolutefoo"; +export const result = [foo(), absolutefoo()]; diff --git a/test/transpile/module-resolution/project-with-module-resolution-plugin/tsconfig.json b/test/transpile/module-resolution/project-with-module-resolution-plugin/tsconfig.json new file mode 100644 index 000000000..06ed18c9f --- /dev/null +++ b/test/transpile/module-resolution/project-with-module-resolution-plugin/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "strict": true, + "target": "esnext", + "lib": ["esnext"], + "types": [] + } +} diff --git a/test/transpile/module-resolution/project-with-node-modules/tsconfig.json b/test/transpile/module-resolution/project-with-node-modules/tsconfig.json index 935b64af6..faa93f0e3 100644 --- a/test/transpile/module-resolution/project-with-node-modules/tsconfig.json +++ b/test/transpile/module-resolution/project-with-node-modules/tsconfig.json @@ -7,6 +7,7 @@ "target": "esnext", "lib": ["esnext"], "types": [], - "rootDir": "." + "rootDir": ".", + "noUncheckedSideEffectImports": false } } diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/main.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/main.ts new file mode 100644 index 000000000..3421911f2 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/main.ts @@ -0,0 +1,5 @@ +import { dependency1IndexFunc } from "dependency1/sub"; +import { dependency1OtherFileFunc } from "dependency1/sub/d1otherfile"; + +export const dependency1IndexResult = dependency1IndexFunc(); +export const dependency1OtherFileFuncResult = dependency1OtherFileFunc(); diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/package.json new file mode 100644 index 000000000..c74b862a1 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/package.json @@ -0,0 +1,14 @@ +{ + "name": "dependency1", + "version": "0.0.1", + "exports": { + "./sub": { + "require": "./dist/index", + "types": "./dist/index.d.ts" + }, + "./sub/*": { + "require": "./dist/*", + "types": "./dist/*.d.ts" + } + } +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/d1otherfile.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/d1otherfile.ts new file mode 100644 index 000000000..3877a1c52 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/d1otherfile.ts @@ -0,0 +1,3 @@ +export function dependency1OtherFileFunc() { + return "dependency1OtherFileFunc in dependency1/d1otherfile"; +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/index.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/index.ts new file mode 100644 index 000000000..03cff47c5 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/index.ts @@ -0,0 +1,10 @@ +import { dependency1OtherFileFunc } from "./d1otherfile"; + +export function dependency1IndexFunc() { + return "function in dependency 1 index: " + dependency1OtherFileFunc(); +} + +export function squares(nums: number[]) { + // Require lualib functionality + return nums.map(n => n * n); +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/tsconfig.json new file mode 100644 index 000000000..d6ffcdc0c --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "composite": true + }, + "tstl": { + "buildMode": "library" + } +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/package.json new file mode 100644 index 000000000..b88dc4bc0 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/package.json @@ -0,0 +1,7 @@ +{ + "name": "app", + "version": "0.0.1", + "dependencies": { + "dependency1": "file:../dependency1-ts" + } +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/tsconfig.json new file mode 100644 index 000000000..7b0969155 --- /dev/null +++ b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "moduleResolution": "node16" + }, + "references": [{ "path": "./node_modules/dependency1" }] +} diff --git a/test/transpile/module-resolution/project-with-tstl-library-modules/dependency1-ts/index.ts b/test/transpile/module-resolution/project-with-tstl-library-modules/dependency1-ts/index.ts index fc1cdddec..03cff47c5 100644 --- a/test/transpile/module-resolution/project-with-tstl-library-modules/dependency1-ts/index.ts +++ b/test/transpile/module-resolution/project-with-tstl-library-modules/dependency1-ts/index.ts @@ -3,3 +3,8 @@ import { dependency1OtherFileFunc } from "./d1otherfile"; export function dependency1IndexFunc() { return "function in dependency 1 index: " + dependency1OtherFileFunc(); } + +export function squares(nums: number[]) { + // Require lualib functionality + return nums.map(n => n * n); +} diff --git a/test/transpile/paths.spec.ts b/test/transpile/paths.spec.ts index 33d4f6258..f98b6e635 100644 --- a/test/transpile/paths.spec.ts +++ b/test/transpile/paths.spec.ts @@ -1,6 +1,6 @@ import * as path from "path"; import * as ts from "typescript"; -import { getSourceDir } from "../../src"; +import { getEmitPath, getSourceDir } from "../../src"; import * as util from "../util"; const cwd = process.cwd(); @@ -12,31 +12,24 @@ describe("getSourceDir", () => { test("with rootDir", () => { const program = ts.createProgram(["main.ts", "src/otherfile.ts"], { configFilePath, rootDir: "src" }); - // getCommonSourceDirectory does not work right so mock it - jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(cwd); - + // If rootdir is specified, rootDir is the sourceDir expect(getSourceDir(program)).toBe(path.join(cwd, "src")); }); test("without rootDir", () => { const program = ts.createProgram(["main.ts", "src/otherfile.ts"], { configFilePath }); - // getCommonSourceDirectory does not work right so mock it - jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(cwd); - - // Common sources directory is project root + // If rootDir is not specified, root dir is where the config file is expect(normalize(getSourceDir(program))).toBe(cwd); }); - test("without rootDir in src dir", () => { - const program = ts.createProgram([path.join(cwd, "src", "main.ts"), path.join(cwd, "src", "otherfile.ts")], { - configFilePath, - }); + test("without config file in src dir", () => { + const program = ts.createProgram([path.join(cwd, "src", "main.ts"), path.join(cwd, "src", "otherfile.ts")], {}); // getCommonSourceDirectory does not work right so mock it jest.spyOn(program, "getCommonSourceDirectory").mockReturnValue(path.join(cwd, "src")); - // Common sources directory is src + // If there is no config file, return the common source directory expect(normalize(getSourceDir(program))).toBe(path.join(cwd, "src")); }); }); @@ -113,6 +106,53 @@ describe("getEmitPath", () => { expect(fileNames).toHaveLength(1); expect(fileNames).toContain(path.join(cwd, "out1", "out2", "bundle.lua")); }); + + test.each([".scar", "scar"])("uses config extension (%p)", extension => { + const { transpiledFiles } = util.testModule`` + .setMainFileName("main.ts") + .addExtraFile("dir/extra.ts", "") + .setOptions({ extension }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toContain("main.scar"); + expect(fileNames).toContain(path.join("dir", "extra.scar")); + }); + + test("bundle with different extension", () => { + const { transpiledFiles } = util.testModule`` + .setMainFileName("src/main.ts") + .addExtraFile("src/extra.ts", "") + .setOptions({ + configFilePath, + rootDir: "src", + outDir: "out1", + luaBundle: "out2/bundle.scar", + luaBundleEntry: "src/main.ts", + }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + const fileNames = transpiledFiles.map(f => f.outPath); + expect(fileNames).toHaveLength(1); + expect(fileNames).toContain(path.join(cwd, "out1", "out2", "bundle.scar")); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1540 + test("puts files next to their source if no config is given (#1540)", () => { + const file1 = path.join("src", "main.ts"); + const file2 = path.join("src", "otherfile.ts"); + const file3 = path.join("src", "nested", "nestedfile.ts"); + const program = ts.createProgram([file1, file2, file3], { configFilePath }); + + // If rootDir is not specified, root dir is where the config file is + const configRoot = path.dirname(configFilePath); + const replaceExtension = (f: string) => f.replace(/\.ts$/, ".lua"); + expect(getEmitPath(file1, program)).toBe(replaceExtension(path.join(configRoot, file1))); + expect(getEmitPath(file2, program)).toBe(replaceExtension(path.join(configRoot, file2))); + expect(getEmitPath(file3, program)).toBe(replaceExtension(path.join(configRoot, file3))); + }); }); function normalize(path: string) { diff --git a/test/transpile/plugins/__snapshots__/plugins.spec.ts.snap b/test/transpile/plugins/__snapshots__/plugins.spec.ts.snap index 9902416ab..7e3be754d 100644 --- a/test/transpile/plugins/__snapshots__/plugins.spec.ts.snap +++ b/test/transpile/plugins/__snapshots__/plugins.spec.ts.snap @@ -5,11 +5,11 @@ exports[`statement comments 1`] = ` function ____exports.__main(self) --This comment on variable declaration was added by a plugin! --- This one too! - local foo = \\"bar\\" + local foo = "bar" -- This trailing comment was also added by a plugin! --- Example luadoc comment ---@param paramName ParamClass - foo = \\"baz\\" + foo = "baz" --[[ This plugin can also (kinda) create multiline comments. -- Line 2 --]] diff --git a/test/transpile/plugins/add-comments.ts b/test/transpile/plugins/add-comments.ts index 9beb01432..2e9c56a5f 100644 --- a/test/transpile/plugins/add-comments.ts +++ b/test/transpile/plugins/add-comments.ts @@ -58,5 +58,4 @@ const plugin: tstl.Plugin = { }, }; -// eslint-disable-next-line import/no-default-export export default plugin; diff --git a/test/transpile/plugins/afterEmit.ts b/test/transpile/plugins/afterEmit.ts new file mode 100644 index 000000000..277258f25 --- /dev/null +++ b/test/transpile/plugins/afterEmit.ts @@ -0,0 +1,23 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + afterEmit(program: ts.Program, options: tstl.CompilerOptions, emitHost: tstl.EmitHost, result: tstl.EmitFile[]) { + void program; + void options; + void emitHost; + void result; + + const diagnostic = { + category: ts.DiagnosticCategory.Message, + messageText: "After emit diagnostic message!", + code: 1234, + file: program.getSourceFiles()[0], + start: undefined, + length: undefined, + } satisfies ts.Diagnostic; + return [diagnostic]; + }, +}; + +export default plugin; diff --git a/test/transpile/plugins/afterPrint.ts b/test/transpile/plugins/afterPrint.ts new file mode 100644 index 000000000..cb548218b --- /dev/null +++ b/test/transpile/plugins/afterPrint.ts @@ -0,0 +1,21 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + afterPrint( + program: ts.Program, + options: tstl.CompilerOptions, + emitHost: tstl.EmitHost, + result: tstl.ProcessedFile[] + ) { + void program; + void options; + void emitHost; + + for (const file of result) { + file.code = "-- Comment added by afterPrint plugin\n" + file.code; + } + }, +}; + +export default plugin; diff --git a/test/transpile/plugins/arguments.ts b/test/transpile/plugins/arguments.ts index f6aa2ba6e..e90afae3b 100644 --- a/test/transpile/plugins/arguments.ts +++ b/test/transpile/plugins/arguments.ts @@ -6,7 +6,6 @@ interface Options { option: boolean; } -// eslint-disable-next-line import/no-default-export export default function plugin(options: Options): tstl.Plugin { return { visitors: { diff --git a/test/transpile/plugins/beforeEmit.ts b/test/transpile/plugins/beforeEmit.ts new file mode 100644 index 000000000..2deb029e4 --- /dev/null +++ b/test/transpile/plugins/beforeEmit.ts @@ -0,0 +1,16 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + beforeEmit(program: ts.Program, options: tstl.CompilerOptions, emitHost: tstl.EmitHost, result: tstl.EmitFile[]) { + void program; + void options; + void emitHost; + + for (const file of result) { + file.code = "-- Comment added by beforeEmit plugin\n" + file.code; + } + }, +}; + +export default plugin; diff --git a/test/transpile/plugins/beforeTransform.ts b/test/transpile/plugins/beforeTransform.ts new file mode 100644 index 000000000..c93c20f91 --- /dev/null +++ b/test/transpile/plugins/beforeTransform.ts @@ -0,0 +1,14 @@ +import * as ts from "typescript"; +import * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + beforeTransform(program: ts.Program, options: tstl.CompilerOptions, emitHost: tstl.EmitHost) { + void program; + void emitHost; + + // Modify settings + options.outDir = "plugin/beforeTransform/outdir"; + }, +}; + +export default plugin; diff --git a/test/transpile/plugins/moduleResolution.ts b/test/transpile/plugins/moduleResolution.ts new file mode 100644 index 000000000..705345a5b --- /dev/null +++ b/test/transpile/plugins/moduleResolution.ts @@ -0,0 +1,22 @@ +import path = require("path"); +import type * as tstl from "../../../src"; + +const plugin: tstl.Plugin = { + moduleResolution(moduleIdentifier) { + if (moduleIdentifier.includes("absolutefoo")) { + return path.join( + path.dirname(__dirname), + "module-resolution", + "project-with-module-resolution-plugin", + "lua_sources", + "absolutebar.lua" + ); + } + + if (moduleIdentifier.includes("foo")) { + return moduleIdentifier.replace("foo", "bar"); + } + }, +}; + +export default plugin; diff --git a/test/transpile/plugins/plugins.spec.ts b/test/transpile/plugins/plugins.spec.ts index eaaee3dca..ed25ae748 100644 --- a/test/transpile/plugins/plugins.spec.ts +++ b/test/transpile/plugins/plugins.spec.ts @@ -1,10 +1,35 @@ import * as path from "path"; import * as util from "../../util"; +import { Plugin } from "../../../src/transpilation/plugins"; +import * as ts from "typescript"; test("printer", () => { util.testModule`` .setOptions({ luaPlugins: [{ name: path.join(__dirname, "printer.ts") }] }) - .tap(builder => expect(builder.getMainLuaCodeChunk()).toMatch("Plugin")); + .tap(builder => expect(builder.getMainLuaCodeChunk()).toMatch("-- Custom printer plugin:")); +}); + +test("printer in bundle", () => { + const { transpiledFiles } = util.testBundle` + import "./otherfile"; + + const foo = "foo"; + ` + .addExtraFile( + "otherfile.ts", + ` + const bar = "bar"; + ` + ) + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "printer.ts") }] }) + .expectToHaveNoDiagnostics() + .getLuaResult(); + + expect(transpiledFiles).toHaveLength(1); + const lua = transpiledFiles[0].lua!; + + expect(lua).toContain("-- Custom printer plugin: main.lua"); + expect(lua).toContain("-- Custom printer plugin: otherfile.lua"); }); test("visitor", () => { @@ -55,8 +80,164 @@ test.each(["namespace", "module"])("%s with TS transformer plugin", moduleOrName return false; } } - ` + ` ) .setOptions({ plugins: [{ transform: path.join(__dirname, "transformer-plugin.ts") }] }) .expectNoExecutionError(); }); + +test("beforeTransform plugin", () => { + const { transpiledFiles } = util.testModule` + console.log("Hello, World!"); + ` + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "beforeTransform.ts") }] }) + .getLuaResult(); + + expect(transpiledFiles).toHaveLength(1); + // Expect emitted to output path set by the plugin + expect(transpiledFiles[0].outPath).toContain(path.join("plugin", "beforeTransform", "outdir")); +}); + +test("afterPrint plugin", () => { + const { transpiledFiles } = util.testModule` + console.log("Hello, World!"); + ` + .addExtraFile( + "extrafile.ts", + ` + console.log("Hello, Mars!"); + ` + ) + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "afterPrint.ts") }] }) + .getLuaResult(); + + expect(transpiledFiles).toHaveLength(2); + for (const f of transpiledFiles) { + // Expect plugin inserted extra lua at start of file + expect(f.lua).toContain("-- Comment added by afterPrint plugin"); + } +}); + +test("beforeEmit plugin", () => { + const { transpiledFiles } = util.testModule` + console.log("Hello, World!"); + [].push(1,2,3); // Use lualib code + ` + .addExtraFile( + "extrafile.ts", + ` + console.log("Hello, Mars!"); + ` + ) + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "beforeEmit.ts") }] }) + .getLuaResult(); + + // 2 input files + 1 lualib_bundle + expect(transpiledFiles).toHaveLength(3); + expect(transpiledFiles.find(f => f.outPath.endsWith("lualib_bundle.lua"))).toBeDefined(); + for (const f of transpiledFiles) { + // Expect plugin inserted extra lua at start of all files including lualib bundle + expect(f.lua).toContain("-- Comment added by beforeEmit plugin"); + } +}); + +test("beforeEmit plugin bundle", () => { + const { transpiledFiles } = util.testBundle` + console.log("Hello, World!"); + [].push(1,2,3); // Use lualib code + ` + .addExtraFile( + "extrafile.ts", + ` + console.log("Hello, Mars!"); + ` + ) + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "beforeEmit.ts") }] }) + .getLuaResult(); + + // 1 lua bundle output + expect(transpiledFiles).toHaveLength(1); + for (const f of transpiledFiles) { + // Expect bundle to be affected by plugin + expect(f.lua).toContain("-- Comment added by beforeEmit plugin"); + } +}); + +test("afterEmit plugin", () => { + const { diagnostics } = util.testModule` + console.log("Hello, World!"); + [].push(1,2,3); // Use lualib code + ` + .addExtraFile( + "extrafile.ts", + ` + console.log("Hello, Mars!"); + ` + ) + .setOptions({ luaPlugins: [{ name: path.join(__dirname, "afterEmit.ts") }] }) + .getLuaResult(); + + // Expect to see the diagnostic returned by the plugin in the output + const diagnostic = diagnostics.find(d => d.code === 1234); + expect(diagnostic).toBeDefined(); + expect(diagnostic?.category).toBe(ts.DiagnosticCategory.Message); + expect(diagnostic?.messageText).toContain("After emit"); +}); + +test("in memory plugin", () => { + const { diagnostics } = util.testModule`` + .setOptions({ + luaPlugins: [ + { + plugin: { + afterEmit(program: ts.Program) { + return [ + { + category: ts.DiagnosticCategory.Message, + messageText: "In memory plugin diagnostic message!", + code: 1234, + file: program.getSourceFiles()[0], + start: undefined, + length: undefined, + } satisfies ts.Diagnostic, + ]; + }, + } satisfies Plugin, + }, + ], + }) + .getLuaResult(); + + expect(diagnostics).toHaveLength(1); + expect(diagnostics[0].code).toBe(1234); +}); + +test("in memory plugin with factory", () => { + const { diagnostics } = util.testModule`` + .setOptions({ + luaPlugins: [ + { + code: 1234, + plugin: options => + ({ + afterEmit(program: ts.Program) { + return [ + { + category: ts.DiagnosticCategory.Message, + messageText: "In memory plugin diagnostic message!", + code: options.code, + file: program.getSourceFiles()[0], + start: undefined, + length: undefined, + } satisfies ts.Diagnostic, + ]; + }, + } satisfies Plugin), + }, + ], + }) + .getLuaResult(); + + expect(diagnostics).toHaveLength(1); + expect(diagnostics[0].code).toBe(1234); +}); diff --git a/test/transpile/plugins/printer.ts b/test/transpile/plugins/printer.ts index 7ae55ca01..37b6d84f7 100644 --- a/test/transpile/plugins/printer.ts +++ b/test/transpile/plugins/printer.ts @@ -1,12 +1,23 @@ +import { SourceNode } from "source-map"; import * as tstl from "../../../src"; +class CustomPrinter extends tstl.LuaPrinter { + /* Override printFile */ + protected printFile(file: tstl.File): SourceNode { + const originalResult = super.printFile(file); + // Add header comment at the top of the file + return this.createSourceNode(file, [`-- Custom printer plugin: ${this.luaFile}\n`, originalResult]); + } + + /* Override printBoolean */ + public printBooleanLiteral(expression: tstl.BooleanLiteral): SourceNode { + // Print any boolean as 'true' + return this.createSourceNode(expression, "true"); + } +} + const plugin: tstl.Plugin = { - printer(program, emitHost, fileName, ...args) { - const result = new tstl.LuaPrinter(emitHost, program, fileName).print(...args); - result.code = `-- Plugin\n${result.code}`; - return result; - }, + printer: (program, emitHost, fileName, file) => new CustomPrinter(emitHost, program, fileName).print(file), }; -// eslint-disable-next-line import/no-default-export export default plugin; diff --git a/test/transpile/plugins/visitor-super.ts b/test/transpile/plugins/visitor-super.ts index 9a8bee5f1..3ece9458b 100644 --- a/test/transpile/plugins/visitor-super.ts +++ b/test/transpile/plugins/visitor-super.ts @@ -15,5 +15,4 @@ const plugin: tstl.Plugin = { }, }; -// eslint-disable-next-line import/no-default-export export default plugin; diff --git a/test/transpile/plugins/visitor.ts b/test/transpile/plugins/visitor.ts index 507b9fa3d..15da18ded 100644 --- a/test/transpile/plugins/visitor.ts +++ b/test/transpile/plugins/visitor.ts @@ -7,5 +7,4 @@ const plugin: tstl.Plugin = { }, }; -// eslint-disable-next-line import/no-default-export export default plugin; diff --git a/test/transpile/resolve-plugin/ts.ts b/test/transpile/resolve-plugin/ts.ts index 60757f0a4..ff3177bab 100644 --- a/test/transpile/resolve-plugin/ts.ts +++ b/test/transpile/resolve-plugin/ts.ts @@ -1,2 +1 @@ -// eslint-disable-next-line import/no-default-export export default true; diff --git a/test/transpile/transformers/fixtures.ts b/test/transpile/transformers/fixtures.ts index dff7667be..4bb890135 100644 --- a/test/transpile/transformers/fixtures.ts +++ b/test/transpile/transformers/fixtures.ts @@ -36,7 +36,7 @@ export const compilerOptions = (options: tstl.CompilerOptions): ts.TransformerFactory => context => file => { - assert(options.plugins?.length === 1); + assert.ok(options.plugins?.length === 1); return visitAndReplace(context, file, node => { if (!ts.isReturnStatement(node)) return; return ts.factory.updateReturnStatement(node, ts.factory.createTrue()); diff --git a/test/transpile/transformers/transformers.spec.ts b/test/transpile/transformers/transformers.spec.ts index 02290d9d1..34dd9dc15 100644 --- a/test/transpile/transformers/transformers.spec.ts +++ b/test/transpile/transformers/transformers.spec.ts @@ -35,3 +35,22 @@ describe("factory types", () => { .expectToEqual(true); }); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1464 +test("transformer with switch does not break (#1464)", () => { + util.testFunction` + const foo: number = 3; + switch (foo) { + case 2: { + return 10; + } + case 3: { + return false; + } + } + ` + .setOptions({ + plugins: [{ transform: path.join(__dirname, "fixtures.ts"), import: "program", value: true }], + }) + .expectToEqual(true); +}); diff --git a/test/transpile/transformers/utils.ts b/test/transpile/transformers/utils.ts index 3e1503ba0..819454530 100644 --- a/test/transpile/transformers/utils.ts +++ b/test/transpile/transformers/utils.ts @@ -2,5 +2,5 @@ import * as ts from "typescript"; export function visitAndReplace(context: ts.TransformationContext, node: T, visitor: ts.Visitor): T { const visit: ts.Visitor = node => visitor(node) ?? ts.visitEachChild(node, visit, context); - return ts.visitNode(node, visit); + return ts.visitEachChild(node, visit, context); } diff --git a/test/unit/__snapshots__/bundle.spec.ts.snap b/test/unit/__snapshots__/bundle.spec.ts.snap index 20d4ec657..852b6a668 100644 --- a/test/unit/__snapshots__/bundle.spec.ts.snap +++ b/test/unit/__snapshots__/bundle.spec.ts.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`LuaLibImportKind.Inline generates a warning: diagnostics 1`] = `"warning TSTL: Using 'luaBundle' with 'luaLibImport: \\"inline\\"' might generate duplicate code. It is recommended to use 'luaLibImport: \\"require\\"'."`; +exports[`LuaLibImportKind.Inline generates a warning: diagnostics 1`] = `"warning TSTL: Using 'luaBundle' with 'luaLibImport: "inline"' might generate duplicate code. It is recommended to use 'luaLibImport: "require"'."`; -exports[`bundling not allowed for buildmode library: diagnostics 1`] = `"error TSTL: Cannot bundle probjects with\\"buildmode\\": \\"library\\". Projects including the library can still bundle (which will include external library files)."`; +exports[`bundling not allowed for buildmode library: diagnostics 1`] = `"error TSTL: Cannot bundle projects with "buildmode": "library". Projects including the library can still bundle (which will include external library files)."`; exports[`luaEntry doesn't exist: diagnostics 1`] = `"error TSTL: Could not find bundle entry point 'entry.ts'. It should be a file in the project."`; diff --git a/test/unit/__snapshots__/comments.spec.ts.snap b/test/unit/__snapshots__/comments.spec.ts.snap new file mode 100644 index 000000000..55052f60e --- /dev/null +++ b/test/unit/__snapshots__/comments.spec.ts.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JSDoc is copied on a function with tags: code 1`] = ` +"--- This is a function comment. +-- It has multiple lines. +-- +-- @param arg1 This is the first argument. +-- @param arg2 This is the second argument. +-- @returns A very powerful string. +function foo(self, arg1, arg2) + return "bar" +end" +`; + +exports[`JSDoc is copied on a function with tags: diagnostics 1`] = `""`; + +exports[`JSDoc is copied on a variable: code 1`] = ` +"--- This is a variable comment. +foo = 123" +`; + +exports[`JSDoc is copied on a variable: diagnostics 1`] = `""`; + +exports[`Multi-line JSDoc with one block is copied on a function: code 1`] = ` +"--- This is a function comment. +-- It has more than one line. +function foo(self) +end" +`; + +exports[`Multi-line JSDoc with one block is copied on a function: diagnostics 1`] = `""`; + +exports[`Multi-line JSDoc with two blocks is copied on a function: code 1`] = ` +"--- This is a function comment. +-- It has more than one line. +-- +-- It also has more than one block. +function foo(self) +end" +`; + +exports[`Multi-line JSDoc with two blocks is copied on a function: diagnostics 1`] = `""`; + +exports[`Single-line JSDoc is copied on a function: code 1`] = ` +"--- This is a function comment. +function foo(self) +end" +`; + +exports[`Single-line JSDoc is copied on a function: diagnostics 1`] = `""`; diff --git a/test/unit/__snapshots__/enum.spec.ts.snap b/test/unit/__snapshots__/enum.spec.ts.snap new file mode 100644 index 000000000..181b66a45 --- /dev/null +++ b/test/unit/__snapshots__/enum.spec.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`enum nested in namespace 1`] = ` +"A = A or ({}) +do + A.TestEnum = A.TestEnum or ({}) + A.TestEnum.B = 0 + A.TestEnum[A.TestEnum.B] = "B" + A.TestEnum.C = 1 + A.TestEnum[A.TestEnum.C] = "C" +end" +`; diff --git a/test/unit/__snapshots__/expressions.spec.ts.snap b/test/unit/__snapshots__/expressions.spec.ts.snap index 03bb46230..7eeb5961a 100644 --- a/test/unit/__snapshots__/expressions.spec.ts.snap +++ b/test/unit/__snapshots__/expressions.spec.ts.snap @@ -14,13 +14,13 @@ return ____exports" exports[`Binary expressions ordering parentheses ("1*(3+4*2)") 1`] = ` "local ____exports = {} -____exports.__result = 1 * (3 + (4 * 2)) +____exports.__result = 1 * (3 + 4 * 2) return ____exports" `; exports[`Binary expressions ordering parentheses ("1*30+4") 1`] = ` "local ____exports = {} -____exports.__result = (1 * 30) + 4 +____exports.__result = 1 * 30 + 4 return ____exports" `; @@ -36,6 +36,116 @@ ____exports.__result = 10 - (4 + 5) return ____exports" `; +exports[`Bitop [5.0] ("~a"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bnot(a) +return ____exports" +`; + +exports[`Bitop [5.0] ("~a"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a&=b"): code 1`] = ` +"local ____exports = {} +a = bit.band(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a&=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a&b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.band(a, b) +return ____exports" +`; + +exports[`Bitop [5.0] ("a&b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a<<=b"): code 1`] = ` +"local ____exports = {} +a = bit.lshift(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a<<=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a<>=b"): code 1`] = ` +"local ____exports = {} +a = bit.arshift(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a>>>=b"): code 1`] = ` +"local ____exports = {} +a = bit.rshift(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a>>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a>>>b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.rshift(a, b) +return ____exports" +`; + +exports[`Bitop [5.0] ("a>>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a>>b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.arshift(a, b) +return ____exports" +`; + +exports[`Bitop [5.0] ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a^=b"): code 1`] = ` +"local ____exports = {} +a = bit.bxor(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a^=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a^b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bxor(a, b) +return ____exports" +`; + +exports[`Bitop [5.0] ("a^b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a|=b"): code 1`] = ` +"local ____exports = {} +a = bit.bor(a, b) +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.0] ("a|=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`Bitop [5.0] ("a|b"): code 1`] = ` +"local ____exports = {} +____exports.__result = bit.bor(a, b) +return ____exports" +`; + +exports[`Bitop [5.0] ("a|b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitwise operations is/are not supported for target Lua 5.0."`; + exports[`Bitop [5.1] ("~a"): code 1`] = ` "local ____exports = {} ____exports.__result = bit.bnot(a) @@ -46,10 +156,8 @@ exports[`Bitop [5.1] ("~a"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bitw exports[`Bitop [5.1] ("a&=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.band(a, b) - return a -end)() +a = bit.band(a, b) +____exports.__result = a return ____exports" `; @@ -65,10 +173,8 @@ exports[`Bitop [5.1] ("a&b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bit exports[`Bitop [5.1] ("a<<=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.lshift(a, b) - return a -end)() +a = bit.lshift(a, b) +____exports.__result = a return ____exports" `; @@ -84,10 +190,8 @@ exports[`Bitop [5.1] ("a<>=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.arshift(a, b) - return a -end)() +a = bit.arshift(a, b) +____exports.__result = a return ____exports" `; @@ -95,10 +199,8 @@ exports[`Bitop [5.1] ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: B exports[`Bitop [5.1] ("a>>>=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.rshift(a, b) - return a -end)() +a = bit.rshift(a, b) +____exports.__result = a return ____exports" `; @@ -122,10 +224,8 @@ exports[`Bitop [5.1] ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bi exports[`Bitop [5.1] ("a^=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.bxor(a, b) - return a -end)() +a = bit.bxor(a, b) +____exports.__result = a return ____exports" `; @@ -141,10 +241,8 @@ exports[`Bitop [5.1] ("a^b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Bit exports[`Bitop [5.1] ("a|=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.bor(a, b) - return a -end)() +a = bit.bor(a, b) +____exports.__result = a return ____exports" `; @@ -166,10 +264,8 @@ return ____exports" exports[`Bitop [5.2] ("a&=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.band(a, b) - return a -end)() +a = bit32.band(a, b) +____exports.__result = a return ____exports" `; @@ -181,10 +277,8 @@ return ____exports" exports[`Bitop [5.2] ("a<<=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.lshift(a, b) - return a -end)() +a = bit32.lshift(a, b) +____exports.__result = a return ____exports" `; @@ -196,19 +290,15 @@ return ____exports" exports[`Bitop [5.2] ("a>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.arshift(a, b) - return a -end)() +a = bit32.arshift(a, b) +____exports.__result = a return ____exports" `; exports[`Bitop [5.2] ("a>>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.rshift(a, b) - return a -end)() +a = bit32.rshift(a, b) +____exports.__result = a return ____exports" `; @@ -226,10 +316,8 @@ return ____exports" exports[`Bitop [5.2] ("a^=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.bxor(a, b) - return a -end)() +a = bit32.bxor(a, b) +____exports.__result = a return ____exports" `; @@ -241,10 +329,8 @@ return ____exports" exports[`Bitop [5.2] ("a|=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit32.bor(a, b) - return a -end)() +a = bit32.bor(a, b) +____exports.__result = a return ____exports" `; @@ -262,10 +348,8 @@ return ____exports" exports[`Bitop [5.3] ("a&=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a & b - return a -end)() +a = a & b +____exports.__result = a return ____exports" `; @@ -277,10 +361,8 @@ return ____exports" exports[`Bitop [5.3] ("a<<=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a << b - return a -end)() +a = a << b +____exports.__result = a return ____exports" `; @@ -292,25 +374,21 @@ return ____exports" exports[`Bitop [5.3] ("a>>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a >> b - return a -end)() +a = (a & 4294967295) >> b +____exports.__result = a return ____exports" `; exports[`Bitop [5.3] ("a>>>b") 1`] = ` "local ____exports = {} -____exports.__result = a >> b +____exports.__result = (a & 4294967295) >> b return ____exports" `; exports[`Bitop [5.3] ("a^=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a ~ b - return a -end)() +a = a ~ b +____exports.__result = a return ____exports" `; @@ -322,10 +400,8 @@ return ____exports" exports[`Bitop [5.3] ("a|=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a | b - return a -end)() +a = a | b +____exports.__result = a return ____exports" `; @@ -343,10 +419,8 @@ return ____exports" exports[`Bitop [5.4] ("a&=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a & b - return a -end)() +a = a & b +____exports.__result = a return ____exports" `; @@ -358,10 +432,8 @@ return ____exports" exports[`Bitop [5.4] ("a<<=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a << b - return a -end)() +a = a << b +____exports.__result = a return ____exports" `; @@ -373,25 +445,21 @@ return ____exports" exports[`Bitop [5.4] ("a>>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a >> b - return a -end)() +a = (a & 4294967295) >> b +____exports.__result = a return ____exports" `; exports[`Bitop [5.4] ("a>>>b") 1`] = ` "local ____exports = {} -____exports.__result = a >> b +____exports.__result = (a & 4294967295) >> b return ____exports" `; exports[`Bitop [5.4] ("a^=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a ~ b - return a -end)() +a = a ~ b +____exports.__result = a return ____exports" `; @@ -403,10 +471,8 @@ return ____exports" exports[`Bitop [5.4] ("a|=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a | b - return a -end)() +a = a | b +____exports.__result = a return ____exports" `; @@ -416,6 +482,77 @@ ____exports.__result = a | b return ____exports" `; +exports[`Bitop [5.5] ("~a") 1`] = ` +"local ____exports = {} +____exports.__result = ~a +return ____exports" +`; + +exports[`Bitop [5.5] ("a&=b") 1`] = ` +"local ____exports = {} +a = a & b +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.5] ("a&b") 1`] = ` +"local ____exports = {} +____exports.__result = a & b +return ____exports" +`; + +exports[`Bitop [5.5] ("a<<=b") 1`] = ` +"local ____exports = {} +a = a << b +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.5] ("a<>>=b") 1`] = ` +"local ____exports = {} +a = (a & 4294967295) >> b +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.5] ("a>>>b") 1`] = ` +"local ____exports = {} +____exports.__result = (a & 4294967295) >> b +return ____exports" +`; + +exports[`Bitop [5.5] ("a^=b") 1`] = ` +"local ____exports = {} +a = a ~ b +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.5] ("a^b") 1`] = ` +"local ____exports = {} +____exports.__result = a ~ b +return ____exports" +`; + +exports[`Bitop [5.5] ("a|=b") 1`] = ` +"local ____exports = {} +a = a | b +____exports.__result = a +return ____exports" +`; + +exports[`Bitop [5.5] ("a|b") 1`] = ` +"local ____exports = {} +____exports.__result = a | b +return ____exports" +`; + exports[`Bitop [JIT] ("~a") 1`] = ` "local ____exports = {} ____exports.__result = bit.bnot(a) @@ -424,10 +561,8 @@ return ____exports" exports[`Bitop [JIT] ("a&=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.band(a, b) - return a -end)() +a = bit.band(a, b) +____exports.__result = a return ____exports" `; @@ -439,10 +574,8 @@ return ____exports" exports[`Bitop [JIT] ("a<<=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.lshift(a, b) - return a -end)() +a = bit.lshift(a, b) +____exports.__result = a return ____exports" `; @@ -454,19 +587,15 @@ return ____exports" exports[`Bitop [JIT] ("a>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.arshift(a, b) - return a -end)() +a = bit.arshift(a, b) +____exports.__result = a return ____exports" `; exports[`Bitop [JIT] ("a>>>=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.rshift(a, b) - return a -end)() +a = bit.rshift(a, b) +____exports.__result = a return ____exports" `; @@ -484,10 +613,8 @@ return ____exports" exports[`Bitop [JIT] ("a^=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.bxor(a, b) - return a -end)() +a = bit.bxor(a, b) +____exports.__result = a return ____exports" `; @@ -499,10 +626,8 @@ return ____exports" exports[`Bitop [JIT] ("a|=b") 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = bit.bor(a, b) - return a -end)() +a = bit.bor(a, b) +____exports.__result = a return ____exports" `; @@ -535,9 +660,11 @@ return ____exports" `; exports[`Unary expressions basic ("+a") 1`] = ` -"local ____exports = {} +"local ____lualib = require("lualib_bundle") +local __TS__Number = ____lualib.__TS__Number +local ____exports = {} function ____exports.__main(self) - local ____ = a + __TS__Number(a) end return ____exports" `; @@ -551,27 +678,31 @@ return ____exports" `; exports[`Unary expressions basic ("-a") 1`] = ` -"local ____exports = {} +"local ____lualib = require("lualib_bundle") +local __TS__Number = ____lualib.__TS__Number +local ____exports = {} function ____exports.__main(self) - local ____ = -a + __TS__Number(-a) end return ____exports" `; exports[`Unary expressions basic ("delete tbl.test") 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Delete = ____lualib.__TS__Delete local ____exports = {} function ____exports.__main(self) - __TS__Delete(tbl, \\"test\\") + __TS__Delete(tbl, "test") end return ____exports" `; exports[`Unary expressions basic ("delete tbl['test']") 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Delete = ____lualib.__TS__Delete local ____exports = {} function ____exports.__main(self) - __TS__Delete(tbl, \\"test\\") + __TS__Delete(tbl, "test") end return ____exports" `; @@ -593,19 +724,21 @@ return ____exports" `; exports[`Unary expressions basic ("let a = delete tbl.test") 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Delete = ____lualib.__TS__Delete local ____exports = {} function ____exports.__main(self) - local a = __TS__Delete(tbl, \\"test\\") + local a = __TS__Delete(tbl, "test") end return ____exports" `; exports[`Unary expressions basic ("let a = delete tbl['test']") 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Delete = ____lualib.__TS__Delete local ____exports = {} function ____exports.__main(self) - local a = __TS__Delete(tbl, \\"test\\") + local a = __TS__Delete(tbl, "test") end return ____exports" `; @@ -618,14 +751,12 @@ return ____exports" exports[`Unsupported bitop 5.3 ("a>>=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a >> b - return a -end)() +a = a >> b +____exports.__result = a return ____exports" `; -exports[`Unsupported bitop 5.3 ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; +exports[`Unsupported bitop 5.3 ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Signed right shift \`>>\` is not supported on Lua 5.3+: Lua's native \`>>\` is logical (zero-fill) on 64-bit integers, with no built-in arithmetic shift. Use \`>>>\` if you don't need sign extension, or write your own helper."`; exports[`Unsupported bitop 5.3 ("a>>b"): code 1`] = ` "local ____exports = {} @@ -633,18 +764,16 @@ ____exports.__result = a >> b return ____exports" `; -exports[`Unsupported bitop 5.3 ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; +exports[`Unsupported bitop 5.3 ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Signed right shift \`>>\` is not supported on Lua 5.3+: Lua's native \`>>\` is logical (zero-fill) on 64-bit integers, with no built-in arithmetic shift. Use \`>>>\` if you don't need sign extension, or write your own helper."`; exports[`Unsupported bitop 5.4 ("a>>=b"): code 1`] = ` "local ____exports = {} -____exports.__result = (function() - a = a >> b - return a -end)() +a = a >> b +____exports.__result = a return ____exports" `; -exports[`Unsupported bitop 5.4 ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; +exports[`Unsupported bitop 5.4 ("a>>=b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Signed right shift \`>>\` is not supported on Lua 5.3+: Lua's native \`>>\` is logical (zero-fill) on 64-bit integers, with no built-in arithmetic shift. Use \`>>>\` if you don't need sign extension, or write your own helper."`; exports[`Unsupported bitop 5.4 ("a>>b"): code 1`] = ` "local ____exports = {} @@ -652,4 +781,4 @@ ____exports.__result = a >> b return ____exports" `; -exports[`Unsupported bitop 5.4 ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Right shift operator is not supported for target Lua 5.3. Use \`>>>\` instead."`; +exports[`Unsupported bitop 5.4 ("a>>b"): diagnostics 1`] = `"main.ts(1,25): error TSTL: Signed right shift \`>>\` is not supported on Lua 5.3+: Lua's native \`>>\` is logical (zero-fill) on 64-bit integers, with no built-in arithmetic shift. Use \`>>>\` if you don't need sign extension, or write your own helper."`; diff --git a/test/unit/__snapshots__/identifiers.spec.ts.snap b/test/unit/__snapshots__/identifiers.spec.ts.snap index d955068e5..cfd11a893 100644 --- a/test/unit/__snapshots__/identifiers.spec.ts.snap +++ b/test/unit/__snapshots__/identifiers.spec.ts.snap @@ -52,18 +52,14 @@ exports[`ambient identifier must be a valid lua identifier ("enum $$ {}"): code exports[`ambient identifier must be a valid lua identifier ("enum $$ {}"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier ("function $$();"): code 1`] = `"local ____ = _____24_24_24"`; +exports[`ambient identifier must be a valid lua identifier ("function $$(): void;"): code 1`] = `"local ____ = _____24_24_24"`; -exports[`ambient identifier must be a valid lua identifier ("function $$();"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; +exports[`ambient identifier must be a valid lua identifier ("function $$(): void;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; exports[`ambient identifier must be a valid lua identifier ("let $$: any;"): code 1`] = `"local ____ = _____24_24_24"`; exports[`ambient identifier must be a valid lua identifier ("let $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier ("module $$ { export const bar: any; }"): code 1`] = `"local ____ = _____24_24_24"`; - -exports[`ambient identifier must be a valid lua identifier ("module $$ { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; - exports[`ambient identifier must be a valid lua identifier ("namespace $$ { export const bar: any; }"): code 1`] = `"local ____ = _____24_24_24"`; exports[`ambient identifier must be a valid lua identifier ("namespace $$ { export const bar: any; }"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; @@ -72,59 +68,59 @@ exports[`ambient identifier must be a valid lua identifier ("var $$: any;"): cod exports[`ambient identifier must be a valid lua identifier ("var $$: any;"): diagnostics 1`] = `"main.ts(3,9): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {[\\"$$$\\"] = _____24_24_24}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {["$$$"] = _____24_24_24}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("$$"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {[\\"_̀ः٠‿\\"] = ______300_903_660_203F}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {["_̀ः٠‿"] = ______300_903_660_203F}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name '_̀ः٠‿'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {[\\"and\\"] = ____and}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {["and"] = ____and}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("and"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'and'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {[\\"elseif\\"] = ____elseif}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {["elseif"] = ____elseif}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("elseif"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'elseif'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {[\\"end\\"] = ____end}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {["end"] = ____end}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("end"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'end'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {[\\"goto\\"] = ____goto}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {["goto"] = ____goto}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("goto"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'goto'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {[\\"local\\"] = ____local}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {["local"] = ____local}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("local"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {[\\"nil\\"] = ____nil}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {["nil"] = ____nil}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("nil"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'nil'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {[\\"not\\"] = ____not}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {["not"] = ____not}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("not"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'not'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {[\\"or\\"] = ____or}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {["or"] = ____or}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("or"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'or'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {[\\"repeat\\"] = ____repeat}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {["repeat"] = ____repeat}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("repeat"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'repeat'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {[\\"then\\"] = ____then}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {["then"] = ____then}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("then"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'then'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {[\\"until\\"] = ____until}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {["until"] = ____until}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("until"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'until'. Ambient identifiers must be valid lua identifiers."`; -exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {[\\"ɥɣɎɌͼƛಠ\\"] = _____265_263_24E_24C_37C_19B_CA0}"`; +exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {["ɥɣɎɌͼƛಠ"] = _____265_263_24E_24C_37C_19B_CA0}"`; exports[`ambient identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(3,27): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; @@ -192,58 +188,253 @@ exports[`undeclared identifier must be a valid lua identifier ("ɥɣɎɌͼƛಠ" exports[`undeclared identifier must be a valid lua identifier ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(2,21): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {[\\"$$$\\"] = _____24_24_24}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("$$"): code 1`] = `"foo = {["$$$"] = _____24_24_24}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("$$"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name '$$$'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {[\\"_̀ः٠‿\\"] = ______300_903_660_203F}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): code 1`] = `"foo = {["_̀ः٠‿"] = ______300_903_660_203F}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("_̀ः٠‿"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name '_̀ः٠‿'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {[\\"and\\"] = ____and}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("and"): code 1`] = `"foo = {["and"] = ____and}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("and"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'and'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {[\\"elseif\\"] = ____elseif}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("elseif"): code 1`] = `"foo = {["elseif"] = ____elseif}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("elseif"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'elseif'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {[\\"end\\"] = ____end}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("end"): code 1`] = `"foo = {["end"] = ____end}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("end"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'end'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {[\\"goto\\"] = ____goto}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("goto"): code 1`] = `"foo = {["goto"] = ____goto}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("goto"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'goto'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {[\\"local\\"] = ____local}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("local"): code 1`] = `"foo = {["local"] = ____local}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("local"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'local'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {[\\"nil\\"] = ____nil}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("nil"): code 1`] = `"foo = {["nil"] = ____nil}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("nil"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'nil'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {[\\"not\\"] = ____not}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("not"): code 1`] = `"foo = {["not"] = ____not}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("not"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'not'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {[\\"or\\"] = ____or}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("or"): code 1`] = `"foo = {["or"] = ____or}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("or"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'or'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {[\\"repeat\\"] = ____repeat}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("repeat"): code 1`] = `"foo = {["repeat"] = ____repeat}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("repeat"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'repeat'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {[\\"then\\"] = ____then}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("then"): code 1`] = `"foo = {["then"] = ____then}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("then"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'then'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {[\\"until\\"] = ____until}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("until"): code 1`] = `"foo = {["until"] = ____until}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("until"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'until'. Ambient identifiers must be valid lua identifiers."`; -exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {[\\"ɥɣɎɌͼƛಠ\\"] = _____265_263_24E_24C_37C_19B_CA0}"`; +exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): code 1`] = `"foo = {["ɥɣɎɌͼƛಠ"] = _____265_263_24E_24C_37C_19B_CA0}"`; exports[`undeclared identifier must be a valid lua identifier (object literal shorthand) ("ɥɣɎɌͼƛಠ"): diagnostics 1`] = `"main.ts(2,27): error TSTL: Invalid ambient identifier name 'ɥɣɎɌͼƛಠ'. Ambient identifiers must be valid lua identifiers."`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring property name ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {foo = "foobar"} + local _̀ः٠‿ = ____temp_0.foo + return _̀ः٠‿ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring property name ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {foo = "foobar"} + local ɥɣɎɌͼƛಠ = ____temp_0.foo + return ɥɣɎɌͼƛಠ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring property name ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {foo = "foobar"} + local 𝛼𝛽𝚫 = ____temp_0.foo + return 𝛼𝛽𝚫 +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring shorthand ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {_̀ः٠‿ = "foobar"} + local _̀ः٠‿ = ____temp_0._̀ः٠‿ + return _̀ः٠‿ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring shorthand ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {ɥɣɎɌͼƛಠ = "foobar"} + local ɥɣɎɌͼƛಠ = ____temp_0.ɥɣɎɌͼƛಠ + return ɥɣɎɌͼƛಠ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) destructuring shorthand ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ____temp_0 = {𝛼𝛽𝚫 = "foobar"} + local 𝛼𝛽𝚫 = ____temp_0.𝛼𝛽𝚫 + return 𝛼𝛽𝚫 +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) function ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function _̀ः٠‿(self, arg) + return "foo" .. arg + end + return _̀ः٠‿(nil, "bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) function ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function ɥɣɎɌͼƛಠ(self, arg) + return "foo" .. arg + end + return ɥɣɎɌͼƛಠ(nil, "bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) function ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function 𝛼𝛽𝚫(self, arg) + return "foo" .. arg + end + return 𝛼𝛽𝚫(nil, "bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) identifier name ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local _̀ः٠‿ = "foobar" + return _̀ः٠‿ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) identifier name ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local ɥɣɎɌͼƛಠ = "foobar" + return ɥɣɎɌͼƛಠ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) identifier name ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local 𝛼𝛽𝚫 = "foobar" + return 𝛼𝛽𝚫 +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) method ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local foo = {_̀ः٠‿ = function(self, arg) + return "foo" .. arg + end} + return foo:_̀ः٠‿("bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) method ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local foo = {ɥɣɎɌͼƛಠ = function(self, arg) + return "foo" .. arg + end} + return foo:ɥɣɎɌͼƛಠ("bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) method ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local foo = {𝛼𝛽𝚫 = function(self, arg) + return "foo" .. arg + end} + return foo:𝛼𝛽𝚫("bar") +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) property name ("_̀ः٠‿") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local x = {_̀ः٠‿ = "foobar"} + return x._̀ः٠‿ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) property name ("ɥɣɎɌͼƛಠ") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local x = {ɥɣɎɌͼƛಠ = "foobar"} + return x.ɥɣɎɌͼƛಠ +end +return ____exports" +`; + +exports[`unicode identifiers in supporting environments (luajit) property name ("𝛼𝛽𝚫") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local x = {𝛼𝛽𝚫 = "foobar"} + return x.𝛼𝛽𝚫 +end +return ____exports" +`; + +exports[`unicode static initialization block (#1645) 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local ____exports = {} +____exports.default = __TS__Class() +local _____81EA_5B9A_4E49_5F02_80FD = ____exports.default +_____81EA_5B9A_4E49_5F02_80FD.name = "自定义异能" +function _____81EA_5B9A_4E49_5F02_80FD.prototype.____constructor(self) +end; +(function(self) + local a = 1 +end)(_____81EA_5B9A_4E49_5F02_80FD) +return ____exports" +`; diff --git a/test/unit/__snapshots__/loops.spec.ts.snap b/test/unit/__snapshots__/loops.spec.ts.snap index e9b6be991..886964ebc 100644 --- a/test/unit/__snapshots__/loops.spec.ts.snap +++ b/test/unit/__snapshots__/loops.spec.ts.snap @@ -3,7 +3,7 @@ exports[`forin[Array]: code 1`] = ` "local ____exports = {} function ____exports.__main(self) - local array = {} + local array = {1, 2, 3} for key in pairs(array) do end end @@ -11,121 +11,3 @@ return ____exports" `; exports[`forin[Array]: diagnostics 1`] = `"main.ts(3,9): error TSTL: Iterating over arrays with 'for ... in' is not allowed."`; - -exports[`loop continue (do { continue; } while (false)) [5.1]: code 1`] = ` -"repeat - do - do - goto __continue2 - end - ::__continue2:: - end -until not false" -`; - -exports[`loop continue (do { continue; } while (false)) [5.1]: diagnostics 1`] = `"main.ts(1,6): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (do { continue; } while (false)) [universal]: code 1`] = ` -"repeat - do - do - goto __continue2 - end - ::__continue2:: - end -until not false" -`; - -exports[`loop continue (do { continue; } while (false)) [universal]: diagnostics 1`] = `"main.ts(1,6): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (;;) { continue; }) [5.1]: code 1`] = ` -"do - while true do - do - goto __continue2 - end - ::__continue2:: - end -end" -`; - -exports[`loop continue (for (;;) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,12): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (;;) { continue; }) [universal]: code 1`] = ` -"do - while true do - do - goto __continue2 - end - ::__continue2:: - end -end" -`; - -exports[`loop continue (for (;;) { continue; }) [universal]: diagnostics 1`] = `"main.ts(1,12): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (const a in {}) { continue; }) [5.1]: code 1`] = ` -"for a in pairs({}) do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (for (const a in {}) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (const a in {}) { continue; }) [universal]: code 1`] = ` -"for a in pairs({}) do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (for (const a in {}) { continue; }) [universal]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (const a of []) { continue; }) [5.1]: code 1`] = ` -"for ____, a in ipairs({}) do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (for (const a of []) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (for (const a of []) { continue; }) [universal]: code 1`] = ` -"for ____, a in ipairs({}) do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (for (const a of []) { continue; }) [universal]: diagnostics 1`] = `"main.ts(1,23): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (while (false) { continue; }) [5.1]: code 1`] = ` -"while false do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (while (false) { continue; }) [5.1]: diagnostics 1`] = `"main.ts(1,17): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; - -exports[`loop continue (while (false) { continue; }) [universal]: code 1`] = ` -"while false do - do - goto __continue2 - end - ::__continue2:: -end" -`; - -exports[`loop continue (while (false) { continue; }) [universal]: diagnostics 1`] = `"main.ts(1,17): error TSTL: Continue statement is/are not supported for target Lua 5.1."`; diff --git a/test/unit/__snapshots__/optionalChaining.spec.ts.snap b/test/unit/__snapshots__/optionalChaining.spec.ts.snap new file mode 100644 index 000000000..19fa2a309 --- /dev/null +++ b/test/unit/__snapshots__/optionalChaining.spec.ts.snap @@ -0,0 +1,276 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Unsupported optional chains Builtin global method: code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__Number = ____lualib.__TS__Number +local ____opt_0 = Number +if ____opt_0 ~= nil then + __TS__Number("3") +end" +`; + +exports[`Unsupported optional chains Builtin global method: diagnostics 1`] = `"main.ts(2,17): error TSTL: Optional calls are not supported for builtin or language extension functions."`; + +exports[`Unsupported optional chains Builtin global property: code 1`] = ` +"local ____opt_0 = console +if ____opt_0 ~= nil then + print("3") +end" +`; + +exports[`Unsupported optional chains Builtin global property: diagnostics 1`] = `"main.ts(2,17): error TSTL: Optional calls are not supported for builtin or language extension functions."`; + +exports[`Unsupported optional chains Builtin prototype method: code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach +local ____opt_0 = ({1, 2, 3, 4}).forEach +if ____opt_0 ~= nil then + __TS__ArrayForEach( + {1, 2, 3, 4}, + function() + end + ) +end" +`; + +exports[`Unsupported optional chains Builtin prototype method: diagnostics 1`] = `"main.ts(2,17): error TSTL: Optional calls are not supported for builtin or language extension functions."`; + +exports[`Unsupported optional chains Compile members only: code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + --- + -- @compileMembersOnly + local A = 0 + --- + -- @compileMembersOnly + local B = 2 + --- + -- @compileMembersOnly + local C = 3 + --- + -- @compileMembersOnly + local D = "D" + local ____opt_0 = TestEnum + if ____opt_0 ~= nil then + local ____ = B + end +end +return ____exports" +`; + +exports[`Unsupported optional chains Compile members only: diagnostics 1`] = `"main.ts(10,17): error TSTL: Optional calls are not supported on enums marked with @compileMembersOnly."`; + +exports[`Unsupported optional chains Language extensions: code 1`] = ` +"local ____opt_0 = ({}).has +if ____opt_0 ~= nil then +end" +`; + +exports[`Unsupported optional chains Language extensions: diagnostics 1`] = ` +"main.ts(2,17): error TSTL: Optional calls are not supported for builtin or language extension functions. +main.ts(2,17): error TSTL: This language extension must be called as a method." +`; + +exports[`long optional chain 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local a = {b = {c = {d = {e = {f = "hello!"}}}}} + local ____opt_2 = a.b + local ____opt_0 = ____opt_2 and ____opt_2.c + return ____opt_0 and ____opt_0.d.e.f +end +return ____exports" +`; + +exports[`optional chaining ("{ foo: \\"foo\\" }") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local obj = {foo = "foo"} + return obj and obj.foo +end +return ____exports" +`; + +exports[`optional chaining ("null") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local obj = nil + return obj and obj.foo +end +return ____exports" +`; + +exports[`optional chaining ("undefined") 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local obj = nil + return obj and obj.foo +end +return ____exports" +`; + +exports[`optional element function calls 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local obj = { + value = "foobar", + foo = function(v) return v + 10 end + } + local fooKey = "foo" + local barKey = "bar" + local ____opt_0 = obj[barKey] + local ____temp_4 = ____opt_0 and ____opt_0(5) + if ____temp_4 == nil then + local ____opt_2 = obj[fooKey] + ____temp_4 = ____opt_2 and ____opt_2(15) + end + return ____temp_4 +end +return ____exports" +`; + +exports[`unused call 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local result + local obj = {foo = function(self) + result = "bar" + end} + if obj ~= nil then + obj:foo() + end + return result +end +return ____exports" +`; + +exports[`unused expression 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local obj = {foo = "bar"} + if obj ~= nil then + local ____ = obj.foo + end +end +return ____exports" +`; + +exports[`unused result with preceding statements on right side 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = nil + if obj ~= nil then + local ____opt_0_foo_2 = obj.foo + local ____i_1 = i + i = ____i_1 + 1 + ____opt_0_foo_2(obj, ____i_1) + end + return i +end +return ____exports" +`; + +exports[`unused result with preceding statements on right side 2`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = {foo = function(self, val) + return val + end} + if obj ~= nil then + local ____opt_0_foo_2 = obj.foo + local ____i_1 = i + i = ____i_1 + 1 + ____opt_0_foo_2(obj, ____i_1) + end + return i +end +return ____exports" +`; + +exports[`with preceding statements on right side 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = nil + local ____opt_result_4 + if obj ~= nil then + local ____opt_0_foo_2 = obj.foo + local ____i_1 = i + i = ____i_1 + 1 + ____opt_result_4 = ____opt_0_foo_2(obj, ____i_1) + end + return {result = ____opt_result_4, i = i} +end +return ____exports" +`; + +exports[`with preceding statements on right side 2`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = {foo = function(____, v) return v end} + local ____opt_result_4 + if obj ~= nil then + local ____opt_0_foo_2 = obj.foo + local ____i_1 = i + i = ____i_1 + 1 + ____opt_result_4 = ____opt_0_foo_2(obj, ____i_1) + end + return {result = ____opt_result_4, i = i} +end +return ____exports" +`; + +exports[`with preceding statements on right side modifying left 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = nil + local function bar(self) + if obj then + obj.foo = nil + end + obj = nil + return 1 + end + local ____opt_0 = obj + if ____opt_0 ~= nil then + local ____opt_0_foo_3 = ____opt_0.foo + local ____bar_result_2 = bar(nil) + local ____i_1 = i + i = ____i_1 + 1 + ____opt_0 = ____opt_0_foo_3(____opt_0, ____bar_result_2, ____i_1) + end + return {result = ____opt_0, obj = obj, i = i} +end +return ____exports" +`; + +exports[`with preceding statements on right side modifying left 2`] = ` +"local ____exports = {} +function ____exports.__main(self) + local i = 0 + local obj = {foo = function(self, v) + return v + end} + local function bar(self) + if obj then + obj.foo = nil + end + obj = nil + return 1 + end + local ____opt_0 = obj + if ____opt_0 ~= nil then + local ____opt_0_foo_3 = ____opt_0.foo + local ____bar_result_2 = bar(nil) + local ____i_1 = i + i = ____i_1 + 1 + ____opt_0 = ____opt_0_foo_3(____opt_0, ____bar_result_2, ____i_1) + end + return {result = ____opt_0, obj = obj, i = i} +end +return ____exports" +`; diff --git a/test/unit/__snapshots__/spread.spec.ts.snap b/test/unit/__snapshots__/spread.spec.ts.snap index 0b49fd80a..c1fba08eb 100644 --- a/test/unit/__snapshots__/spread.spec.ts.snap +++ b/test/unit/__snapshots__/spread.spec.ts.snap @@ -12,164 +12,7 @@ function ____exports.__main(self) multi(nil, ...) ) end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization basic use 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(self, ...) - return pick(nil, ...) - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization block statement 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(self, ...) - local result - do - result = pick(nil, ...) - end - return result - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization body-less arrow function 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(____, ...) - return pick(nil, ...) - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization curry 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function test(self, fn, ...) - return fn(nil, ...) - end - return test( - nil, - function(____, arg) return arg end, - \\"foobar\\" - ) -end -return ____exports" -`; - -exports[`vararg spread optimization curry with indirect type 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function test(self, obj, ...) - local fn = obj.fn - return fn(nil, ...) - end - return test( - nil, - { - fn = function(____, arg) return arg end - }, - \\"foobar\\" - ) -end -return ____exports" -`; - -exports[`vararg spread optimization finally clause 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(self, ...) - do - pcall( - function() - error(\\"foobar\\", 0) - end - ) - do - return pick(nil, ...) - end - end - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization function type declared inside scope 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function test(self, ...) - local function fn(____, ...) - local args = {...} - return args[1] - end - return fn(nil, ...) - end - test(nil, \\"foobar\\") -end -return ____exports" -`; - -exports[`vararg spread optimization if statement 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(self, ...) - if true then - return pick(nil, ...) - end - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") -end -return ____exports" -`; - -exports[`vararg spread optimization loop statement 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local function pick(self, ...) - local args = {...} - return args[2] - end - local function test(self, ...) - repeat - do - return pick(nil, ...) - end - until not false - end - return test(nil, \\"a\\", \\"b\\", \\"c\\") + return test(nil, "a", "b", "c") end return ____exports" `; diff --git a/test/unit/__snapshots__/switch.spec.ts.snap b/test/unit/__snapshots__/switch.spec.ts.snap index e7d003fa5..a64e3f77d 100644 --- a/test/unit/__snapshots__/switch.spec.ts.snap +++ b/test/unit/__snapshots__/switch.spec.ts.snap @@ -1,53 +1,147 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`array 1`] = ` +exports[`switch empty fallthrough to default (0) 1`] = ` "local ____exports = {} function ____exports.__main(self) - local result = -1 - local ____switch3 = 2 - if ____switch3 == 0 then - goto ____switch3_case_0 - elseif ____switch3 == 1 then - goto ____switch3_case_1 - elseif ____switch3 == 2 then - goto ____switch3_case_2 - end - goto ____switch3_end - ::____switch3_case_0:: - do + local out = {} + repeat + local ____switch3 = 0 + local ____cond3 = ____switch3 == 1 do - result = 200 - goto ____switch3_end + out[#out + 1] = "default" end - end - ::____switch3_case_1:: - do + until true + return out +end +return ____exports" +`; + +exports[`switch empty fallthrough to default (1) 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local out = {} + repeat + local ____switch3 = 1 + local ____cond3 = ____switch3 == 1 do - result = 100 - goto ____switch3_end + out[#out + 1] = "default" + end + until true + return out +end +return ____exports" +`; + +exports[`switch hoisting hoisting from default clause is not duplicated when falling through 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local x = 1 + local result = "" + repeat + local ____switch3 = x + local hoisted + function hoisted(self) + return "hoisted" + end + local ____cond3 = ____switch3 == 1 + if ____cond3 then + result = hoisted(nil) + break + end + ____cond3 = ____cond3 or ____switch3 == 2 + if ____cond3 then + result = "2" + end + if ____cond3 then + result = "default" + end + ____cond3 = ____cond3 or ____switch3 == 3 + if ____cond3 then + result = "3" + break end - end - ::____switch3_case_2:: - do do - result = 1 - goto ____switch3_end + result = "default" + result = "3" end - end - ::____switch3_end:: + until true return result end return ____exports" `; -exports[`switch not allowed in 5.1: code 1`] = ` +exports[`switch hoisting hoisting from fallthrough clause after default is not duplicated 1`] = ` "local ____exports = {} function ____exports.__main(self) - local ____switch3 = \\"abc\\" - goto ____switch3_end - ::____switch3_end:: + local x = 1 + local result = "" + repeat + local ____switch3 = x + local hoisted + function hoisted(self) + return "hoisted" + end + local ____cond3 = ____switch3 == 1 + if ____cond3 then + result = hoisted(nil) + break + end + ____cond3 = ____cond3 or ____switch3 == 2 + if ____cond3 then + result = "2" + end + if ____cond3 then + result = "default" + end + ____cond3 = ____cond3 or ____switch3 == 3 + if ____cond3 then + result = "3" + break + end + do + result = "default" + result = "3" + end + until true + return result end return ____exports" `; -exports[`switch not allowed in 5.1: diagnostics 1`] = `"main.ts(2,9): error TSTL: Switch statements is/are not supported for target Lua 5.1."`; +exports[`switch produces optimal output 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local x = 0 + local out = {} + repeat + local ____switch3 = 0 + local ____cond3 = ____switch3 == 0 or ____switch3 == 1 or ____switch3 == 2 + if ____cond3 then + out[#out + 1] = "0,1,2" + break + end + ____cond3 = ____cond3 or ____switch3 == 3 + if ____cond3 then + do + out[#out + 1] = "3" + break + end + end + ____cond3 = ____cond3 or ____switch3 == 4 + if ____cond3 then + break + end + do + x = x + 1 + out[#out + 1] = "default = " .. tostring(x) + do + out[#out + 1] = "3" + break + end + end + until true + out[#out + 1] = tostring(x) + return out +end +return ____exports" +`; diff --git a/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap b/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap index c283485bf..11cab115c 100644 --- a/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap +++ b/test/unit/annotations/__snapshots__/customConstructor.spec.ts.snap @@ -1,11 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`IncorrectUsage: code 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__New = ____lualib.__TS__New local ____exports = {} function ____exports.__main(self) + --- + -- @customConstructor local Point2D = __TS__Class() - Point2D.name = \\"Point2D\\" + Point2D.name = "Point2D" function Point2D.prototype.____constructor(self) end __TS__New(Point2D) diff --git a/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap b/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap deleted file mode 100644 index d612bc478..000000000 --- a/test/unit/annotations/__snapshots__/deprecated.spec.ts.snap +++ /dev/null @@ -1,109 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`LuaTable deprecation warning property access set: code 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - return tbl:set(\\"foo\\", 0) -end -return ____exports" -`; - -exports[`LuaTable deprecation warning property access set: diagnostics 1`] = `"main.ts(12,16): error TSTL: '@luaTable' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#luatable for more information."`; - -exports[`LuaTable removed warning constructor: code 1`] = ` -"require(\\"lualib_bundle\\"); -____table = __TS__New(Table)" -`; - -exports[`LuaTable removed warning constructor: diagnostics 1`] = `"main.ts(11,15): error TSTL: '@luaTable' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#luatable for more information."`; - -exports[`LuaTable removed warning property access get: code 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - return tbl:get(\\"foo\\") -end -return ____exports" -`; - -exports[`LuaTable removed warning property access get: diagnostics 1`] = `"main.ts(12,16): error TSTL: '@luaTable' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#luatable for more information."`; - -exports[`LuaTable removed warning property access length: code 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - return tbl.length -end -return ____exports" -`; - -exports[`LuaTable removed warning property access length: diagnostics 1`] = `"main.ts(12,16): error TSTL: '@luaTable' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#luatable for more information."`; - -exports[`extension removed: code 1`] = ` -"require(\\"lualib_bundle\\"); -B = __TS__Class() -B.name = \\"B\\" -__TS__ClassExtends(B, A)" -`; - -exports[`extension removed: code 2`] = ` -"require(\\"lualib_bundle\\"); -B = __TS__Class() -B.name = \\"B\\" -__TS__ClassExtends(B, A)" -`; - -exports[`extension removed: diagnostics 1`] = `"main.ts(4,9): error TSTL: '@extension' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#extension for more information."`; - -exports[`extension removed: diagnostics 2`] = `"main.ts(4,9): error TSTL: '@metaExtension' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#metaextension for more information."`; - -exports[`forRange removed: code 1`] = `""`; - -exports[`forRange removed: diagnostics 1`] = `"main.ts(4,25): error TSTL: '@forRange' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#forrange for more information."`; - -exports[`luaiterator removed: code 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local arr = {\\"a\\", \\"b\\", \\"c\\"} - local function luaIter(self) - local i = 0 - return function() return arr[(function() - local ____tmp = i - i = ____tmp + 1 - return ____tmp - end)() + 1] end - end - local result = \\"\\" - return result -end -return ____exports" -`; - -exports[`luaiterator removed: diagnostics 1`] = `"main.ts(10,23): error TSTL: '@luaIterator' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#luaiterator for more information."`; - -exports[`phantom removed: code 1`] = ` -"A = A or ({}) -do - local function nsMember(self) - end -end" -`; - -exports[`phantom removed: diagnostics 1`] = `"main.ts(3,9): error TSTL: '@phantom' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#phantom for more information."`; - -exports[`pureAbstract removed: code 1`] = ` -"require(\\"lualib_bundle\\"); -ClassB = __TS__Class() -ClassB.name = \\"ClassB\\" -__TS__ClassExtends(ClassB, ClassA)" -`; - -exports[`pureAbstract removed: diagnostics 1`] = `"main.ts(4,22): error TSTL: '@pureAbstract' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#pureabstract for more information."`; - -exports[`vararg removed: code 1`] = ` -"function foo(self, ...) -end -function vararg(self, ...) - foo(_G, ...) -end" -`; - -exports[`vararg removed: diagnostics 1`] = `"main.ts(6,17): error TSTL: '@vararg' has been removed and will no longer have any effect.See https://typescripttolua.github.io/docs/advanced/compiler-annotations#vararg for more information."`; diff --git a/test/unit/annotations/customConstructor.spec.ts b/test/unit/annotations/customConstructor.spec.ts index 86858f700..c9ddcf739 100644 --- a/test/unit/annotations/customConstructor.spec.ts +++ b/test/unit/annotations/customConstructor.spec.ts @@ -11,8 +11,8 @@ test("CustomCreate", () => { const tsHeader = ` /** @customConstructor Point2DCreate */ class Point2D { - public x: number; - public y: number; + public x!: number; + public y!: number; constructor(x: number, y: number) { // No values assigned } diff --git a/test/unit/annotations/deprecated.spec.ts b/test/unit/annotations/deprecated.spec.ts deleted file mode 100644 index 2f0edb105..000000000 --- a/test/unit/annotations/deprecated.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { annotationRemoved } from "../../../src/transformation/utils/diagnostics"; -import * as util from "../../util"; - -test.each(["extension", "metaExtension"])("extension removed", extensionType => { - util.testModule` - declare class A {} - /** @${extensionType} **/ - class B extends A {} - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("phantom removed", () => { - util.testModule` - /** @phantom **/ - namespace A { - function nsMember() {} - } - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("pureAbstract removed", () => { - util.testModule` - /** @pureAbstract */ - declare class ClassA {} - class ClassB extends ClassA {} - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("forRange removed", () => { - util.testModule` - /** @forRange */ - declare function forRange(start: number, limit: number, step?: number): number[]; - for (const i of forRange(1, 10)) {} - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("vararg removed", () => { - util.testModule` - /** @vararg */ - type VarArg = T & { readonly __brand: unique symbol }; - function foo(...args: any[]) {} - function vararg(...args: VarArg) { - foo(...args); - } - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("luaiterator removed", () => { - util.testFunction` - const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Iterable {} - function luaIter(): Iter { - let i = 0; - return (() => arr[i++]) as any; - } - let result = ""; - for (let e of luaIter()) { result += e; } - return result; - `.expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -const tableLibClass = ` -/** @luaTable */ -declare class Table { - length: number; - constructor(notAllowed?: any); - set(key?: K, value?: V, notAllowed?: any): void; - get(key?: K, notAllowed?: any): V; - other(): void; -} -declare let tbl: Table; -`; - -test("LuaTable removed warning constructor", () => { - util.testModule("const table = new Table();") - .setTsHeader(tableLibClass) - .expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("LuaTable removed warning property access length", () => { - util.testFunction` - return tbl.length; - ` - .setTsHeader(tableLibClass) - .expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("LuaTable removed warning property access get", () => { - util.testFunction` - return tbl.get("foo"); - ` - .setTsHeader(tableLibClass) - .expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); - -test("LuaTable deprecation warning property access set", () => { - util.testFunction` - return tbl.set("foo", 0); - ` - .setTsHeader(tableLibClass) - .expectDiagnosticsToMatchSnapshot([annotationRemoved.code]); -}); diff --git a/test/unit/annotations/tupleReturn.spec.ts b/test/unit/annotations/tupleReturn.spec.ts deleted file mode 100644 index 337e52c37..000000000 --- a/test/unit/annotations/tupleReturn.spec.ts +++ /dev/null @@ -1,431 +0,0 @@ -import * as util from "../../util"; - -const expectNoUnpack: util.TapCallback = builder => expect(builder.getMainLuaCodeChunk()).not.toContain("unpack"); - -test("Tuple Return Access", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number, number] { return [3, 5, 1]; } - return tuple()[2]; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Destruct Declaration", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number, number] { return [3,5,1]; } - const [,b,c] = tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Destruct Assignment", () => { - util.testFunction` - /** @tupleReturn */ - function tuple(): [number, number] { return [3,6]; } - let [a,b] = [1,2]; - [b,a] = tuple(); - return a - b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Static Method Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - static tuple(): [number, number, number] { return [3,5,1]; } - } - const [a,b,c] = Test.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Static Function Property Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - static tuple: () => [number, number, number] = () => [3,5,1]; - } - const [a,b,c] = Test.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Non-Static Method Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - tuple(): [number, number, number] { return [3,5,1]; } - } - const t = new Test(); - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Non-Static Function Property Return Destruct", () => { - util.testFunction` - class Test { - /** @tupleReturn */ - tuple: () => [number, number, number] = () => [3,5,1]; - } - const t = new Test(); - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Interface Method Return Destruct", () => { - util.testFunction` - interface Test { - /** @tupleReturn */ - tuple(): [number, number, number]; - } - const t: Test = { - tuple() { return [3,5,1]; } - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Interface Function Property Return Destruct", () => { - util.testFunction` - interface Test { - /** @tupleReturn */ - tuple: () => [number, number, number]; - } - const t: Test = { - tuple: () => [3,5,1] - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Object Literal Method Return Destruct", () => { - util.testFunction` - const t = { - /** @tupleReturn */ - tuple() { return [3,5,1]; } - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Object Literal Function Property Return Destruct", () => { - util.testFunction` - const t = { - /** @tupleReturn */ - tuple: () => [3,5,1] - }; - const [a,b,c] = t.tuple(); - return b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Arrow Function", () => { - util.testFunction` - const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; - const [a, b] = fn("foo"); - return a + b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - const fn: Fn = s => [s, "bar"]; - const [a, b] = fn("foo"); - return a + b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(fn: Fn) { - const [a, b] = fn("foo"); - return a + b; - } - return foo(s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Elipsis Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(_: number, ...fn: Fn[]) { - const [a, b] = fn[0]("foo"); - return a + b; - } - return foo(0, s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return Inference as Elipsis Tuple Argument", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(_: number, ...fn: [number, Fn]) { - const [a, b] = fn[1]("foo"); - return a + b; - } - return foo(0, 0, s => [s, "bar"]); - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return in Spread", () => { - util.testFunction` - /** @tupleReturn */ function foo(): [string, string] { - return ["foo", "bar"]; - } - function bar(a: string, b: string) { - return a + b; - } - return bar(...foo()); - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Type Alias", () => { - util.testFunction` - /** @tupleReturn */ type Fn = () => [number, number]; - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface", () => { - util.testFunction` - /** @tupleReturn */ interface Fn { (): [number, number]; } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Signature", () => { - util.testFunction` - interface Fn { - /** @tupleReturn */ (): [number, number]; - } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Overload", () => { - util.testFunction` - function fn(a: number): number; - /** @tupleReturn */ function fn(a: string, b: string): [string, string]; - function fn(a: number | string, b?: string): number | [string, string] { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - } - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Overload", () => { - util.testFunction` - interface Fn { - (a: number): number; - /** @tupleReturn */ (a: string, b: string): [string, string]; - } - const fn = ((a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - }) as Fn; - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return on Interface Method Overload", () => { - util.testFunction` - interface Foo { - foo(a: number): number; - /** @tupleReturn */ foo(a: string, b: string): [string, string]; - } - const bar = { - foo: (a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - } - } as Foo; - const a = bar.foo(3); - const [b, c] = bar.foo("foo", "bar"); - return a + b + c; - ` - .tap(expectNoUnpack) - .expectToMatchJsResult(); -}); - -test("Tuple Return vs Non-Tuple Return Overload", () => { - const luaHeader = ` - function fn(a, b) - if type(a) == "number" then - return {a, a + 1} - else - return a, b - end - end - `; - - const tsHeader = ` - declare function fn(this: void, a: number): [number, number]; - /** @tupleReturn */ declare function fn(this: void, a: string, b: string): [string, string]; - `; - - util.testFunction` - const [a, b] = fn(3); - const [c, d] = fn("foo", "bar"); - return (a + b) + c + d; - ` - .setTsHeader(tsHeader) - .setLuaHeader(luaHeader) - .expectToEqual("7foobar"); -}); - -test("TupleReturn assignment", () => { - util.testFunction` - /** @tupleReturn */ - function abc(this: void): number[] { - return [3, 5]; - } - let [a, b] = abc(); - return { a, b }; - `.expectToMatchJsResult(); -}); - -test("TupleReturn Single assignment", () => { - util.testFunction` - /** @tupleReturn */ - function abc(this: void): [number, string] { - return [3, "foo"]; - } - let a = abc(); - a = abc(); - return a; - `.expectToMatchJsResult(); -}); - -test("TupleReturn interface assignment", () => { - const lua = util.testFunction` - interface def { - /** @tupleReturn */ - abc(); - } declare const jkl : def; - let [a,b] = jkl.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = jkl:abc()"); -}); - -test("TupleReturn namespace assignment", () => { - const lua = util.testFunction` - declare namespace def { - /** @tupleReturn */ - function abc(this: void) {} - } - let [a,b] = def.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = def.abc()"); -}); - -test("TupleReturn method assignment", () => { - const lua = util.testFunction` - declare class def { - /** @tupleReturn */ - abc() { return [1,2,3]; } - } const jkl = new def(); - let [a,b] = jkl.abc(); - `.getMainLuaCodeChunk(); - - expect(lua).toContain("local a, b = jkl:abc()"); -}); - -test("TupleReturn functional", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a; - `.expectToMatchJsResult(); -}); - -test("TupleReturn single", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length - `.expectToMatchJsResult(); -}); - -test("TupleReturn in expression", () => { - util.testFunction` - /** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0]; - `.expectToMatchJsResult(); -}); diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 5f9209c41..3ad7da149 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -94,16 +94,17 @@ test.each([ "[x[1], x[0]] = tr()", "x = [y[1], y[0]]", "[x[0], x[1]] = [y[1], y[0]]", -])("Tuple assignment expressions (%p)", expression => { +])("multi return assignment expressions (%p)", expression => { util.testFunction` let x: [string, string] = ["x0", "x1"]; let y: [string, string] = ["y0", "y1"]; function t(): [string, string] { return ["t0", "t1"] }; - /** @tupleReturn */ - function tr(): [string, string] { return ["tr0", "tr1"] }; + function tr(): LuaMultiReturn<[string, string]> { return $multi("tr0", "tr1"); }; const r = ${expression}; return \`\${r[0]},\${r[1]}\` - `.expectToMatchJsResult(); + ` + .withLanguageExtensions() + .expectToMatchJsResult(); }); test.each([ @@ -134,6 +135,17 @@ test.each([ `.expectToMatchJsResult(); }); +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1277 +test("Compound assignment as expression (#1277)", () => { + util.testFunction` + let foo = { + bar: false as any + } + const result = foo.bar ||= true; + return { result, foo }; + `.expectToMatchJsResult(); +}); + test.each([ "++o.p", "o.p++", @@ -330,7 +342,7 @@ test.each([ test("local variable declaration referencing self indirectly", () => { util.testFunction` - let cb: () => void; + let cb: () => void = () => { throw "Expecting this to be overwritten"; }; function foo(newCb: () => void) { cb = newCb; @@ -348,7 +360,7 @@ test("local variable declaration referencing self indirectly", () => { test("local multiple variable declaration referencing self indirectly", () => { util.testFunction` - let cb: () => void; + let cb: () => void = () => { throw "Expecting this to be overwritten"; }; function foo(newCb: () => void) { cb = newCb; @@ -383,7 +395,7 @@ describe.each(["x &&= y", "x ||= y"])("boolean compound assignment (%p)", assign test.each([undefined, 3])("nullish coalescing compound assignment", initialValue => { util.testFunction` - let x: number = ${util.formatCode(initialValue)}; + let x: number | undefined = ${util.formatCode(initialValue)}; x ??= 5; return x; `.expectToMatchJsResult(); @@ -416,7 +428,7 @@ test.each([ * x.y ||= z is translated to x.y || (x.y = z). * x.y &&= z is translated to x.y && (x.y = z). * x.y ||= z is translated to x.y !== undefined && (x.y = z). - + Test if setter in Lua is called same nr of times as in JS. */ util.testModule` @@ -448,7 +460,7 @@ test.each([ * x.y ||= z is translated to x.y || (x.y = z). * x.y &&= z is translated to x.y && (x.y = z). * x.y ||= z is translated to x.y !== undefined && (x.y = z). - + Test if setter in Lua is called same nr of times as in JS. */ util.testModule` @@ -494,3 +506,13 @@ test.each([ return [obj, objGot]; `.expectToMatchJsResult(); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1412 +test("invalid assignment to call expression (#1412)", () => { + util.testFunction` + function foo(): number { + return 3; + } + foo() += 4; + `.expectNoTranspileException(); +}); diff --git a/test/unit/builtins/__snapshots__/console.spec.ts.snap b/test/unit/builtins/__snapshots__/console.spec.ts.snap index f06d99dae..2c9d8578c 100644 --- a/test/unit/builtins/__snapshots__/console.spec.ts.snap +++ b/test/unit/builtins/__snapshots__/console.spec.ts.snap @@ -13,7 +13,7 @@ exports[`console.assert ("console.assert(false, \\"message %%s\\", \\"info\\")") function ____exports.__main(self) assert( false, - string.format(\\"message %%s\\", \\"info\\") + string.format("message %%s", "info") ) end return ____exports" @@ -24,7 +24,7 @@ exports[`console.assert ("console.assert(false, \\"message %s\\", \\"info\\")") function ____exports.__main(self) assert( false, - string.format(\\"message %s\\", \\"info\\") + string.format("message %s", "info") ) end return ____exports" @@ -33,7 +33,7 @@ return ____exports" exports[`console.assert ("console.assert(false, \\"message\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - assert(false, \\"message\\") + assert(false, "message") end return ____exports" `; @@ -41,7 +41,7 @@ return ____exports" exports[`console.assert ("console.assert(false, \\"message\\", \\"more\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - assert(false, \\"message\\", \\"more\\") + assert(false, "message", "more") end return ____exports" `; @@ -57,9 +57,7 @@ return ____exports" exports[`console.error ("console.error(\\"Hello %%s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %%s\\", \\"there\\") - ) + print(string.format("Hello %%s", "there")) end return ____exports" `; @@ -67,9 +65,7 @@ return ____exports" exports[`console.error ("console.error(\\"Hello %s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %s\\", \\"there\\") - ) + print(string.format("Hello %s", "there")) end return ____exports" `; @@ -77,7 +73,7 @@ return ____exports" exports[`console.error ("console.error(\\"Hello\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\") + print("Hello") end return ____exports" `; @@ -85,7 +81,7 @@ return ____exports" exports[`console.error ("console.error(\\"Hello\\", \\"There\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\", \\"There\\") + print("Hello", "There") end return ____exports" `; @@ -101,9 +97,7 @@ return ____exports" exports[`console.info ("console.info(\\"Hello %%s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %%s\\", \\"there\\") - ) + print(string.format("Hello %%s", "there")) end return ____exports" `; @@ -111,9 +105,7 @@ return ____exports" exports[`console.info ("console.info(\\"Hello %s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %s\\", \\"there\\") - ) + print(string.format("Hello %s", "there")) end return ____exports" `; @@ -121,7 +113,7 @@ return ____exports" exports[`console.info ("console.info(\\"Hello\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\") + print("Hello") end return ____exports" `; @@ -129,7 +121,7 @@ return ____exports" exports[`console.info ("console.info(\\"Hello\\", \\"There\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\", \\"There\\") + print("Hello", "There") end return ____exports" `; @@ -145,9 +137,7 @@ return ____exports" exports[`console.log ("console.log(\\"Hello %%s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %%s\\", \\"there\\") - ) + print(string.format("Hello %%s", "there")) end return ____exports" `; @@ -155,9 +145,7 @@ return ____exports" exports[`console.log ("console.log(\\"Hello %s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %s\\", \\"there\\") - ) + print(string.format("Hello %s", "there")) end return ____exports" `; @@ -165,7 +153,7 @@ return ____exports" exports[`console.log ("console.log(\\"Hello\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\") + print("Hello") end return ____exports" `; @@ -173,7 +161,7 @@ return ____exports" exports[`console.log ("console.log(\\"Hello\\", \\"There\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\", \\"There\\") + print("Hello", "There") end return ____exports" `; @@ -181,9 +169,7 @@ return ____exports" exports[`console.trace ("console.trace()") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - debug.traceback() - ) + print(debug.traceback()) end return ____exports" `; @@ -191,11 +177,7 @@ return ____exports" exports[`console.trace ("console.trace(\\"Hello %%s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - debug.traceback( - string.format(\\"Hello %%s\\", \\"there\\") - ) - ) + print(debug.traceback(string.format("Hello %%s", "there"))) end return ____exports" `; @@ -203,11 +185,7 @@ return ____exports" exports[`console.trace ("console.trace(\\"Hello %s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - debug.traceback( - string.format(\\"Hello %s\\", \\"there\\") - ) - ) + print(debug.traceback(string.format("Hello %s", "there"))) end return ____exports" `; @@ -215,9 +193,7 @@ return ____exports" exports[`console.trace ("console.trace(\\"Hello\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - debug.traceback(\\"Hello\\", \\"there\\") - ) + print(debug.traceback("Hello", "there")) end return ____exports" `; @@ -225,9 +201,7 @@ return ____exports" exports[`console.trace ("console.trace(\\"message\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - debug.traceback(\\"message\\") - ) + print(debug.traceback("message")) end return ____exports" `; @@ -243,9 +217,7 @@ return ____exports" exports[`console.warn ("console.warn(\\"Hello %%s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %%s\\", \\"there\\") - ) + print(string.format("Hello %%s", "there")) end return ____exports" `; @@ -253,9 +225,7 @@ return ____exports" exports[`console.warn ("console.warn(\\"Hello %s\\", \\"there\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print( - string.format(\\"Hello %s\\", \\"there\\") - ) + print(string.format("Hello %s", "there")) end return ____exports" `; @@ -263,7 +233,7 @@ return ____exports" exports[`console.warn ("console.warn(\\"Hello\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\") + print("Hello") end return ____exports" `; @@ -271,7 +241,7 @@ return ____exports" exports[`console.warn ("console.warn(\\"Hello\\", \\"There\\")") 1`] = ` "local ____exports = {} function ____exports.__main(self) - print(\\"Hello\\", \\"There\\") + print("Hello", "There") end return ____exports" `; diff --git a/test/unit/builtins/__snapshots__/math.spec.ts.snap b/test/unit/builtins/__snapshots__/math.spec.ts.snap deleted file mode 100644 index cb324c9c9..000000000 --- a/test/unit/builtins/__snapshots__/math.spec.ts.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Math.PI 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local ____ = math.pi -end -return ____exports" -`; - -exports[`Math.cos() 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - math.cos() -end -return ____exports" -`; - -exports[`Math.log1p(3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - math.log(1 + 3) -end -return ____exports" -`; - -exports[`Math.log2(3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local ____ = math.log(3) / 0.6931471805599453 -end -return ____exports" -`; - -exports[`Math.log10(3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local ____ = math.log(3) / 2.302585092994046 -end -return ____exports" -`; - -exports[`Math.min() 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - math.min() -end -return ____exports" -`; - -exports[`Math.round(3.3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - math.floor(3.3 + 0.5) -end -return ____exports" -`; - -exports[`Math.sin() 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - math.sin() -end -return ____exports" -`; - -exports[`const x = Math.log2(3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local x = math.log(3) / 0.6931471805599453 -end -return ____exports" -`; - -exports[`const x = Math.log10(3) 1`] = ` -"local ____exports = {} -function ____exports.__main(self) - local x = math.log(3) / 2.302585092994046 -end -return ____exports" -`; diff --git a/test/unit/builtins/array.spec.ts b/test/unit/builtins/array.spec.ts index 037ebe2a7..5e3cd8887 100644 --- a/test/unit/builtins/array.spec.ts +++ b/test/unit/builtins/array.spec.ts @@ -1,3 +1,7 @@ +import { + undefinedInArrayLiteral, + unsupportedArrayWithLengthConstructor, +} from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("omitted expression", () => { @@ -175,6 +179,23 @@ describe("array.length", () => { `.expectToEqual(new util.ExecutionError(`invalid array length: ${luaSpecialValueString}`)); }); + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1395 + test("in compound assignment (#1395)", () => { + util.testFunction` + const arr = [1,2,3,4]; + const returnVal = arr.length -= 2; + return { arr, returnVal }; + `.expectToMatchJsResult(); + }); + + test("as standalone compound assignment (#1395)", () => { + util.testFunction` + const arr = [1,2,3,4]; + arr.length -= 2; + return arr; + `.expectToMatchJsResult(); + }); + test("in array destructuring", () => { util.testFunction` const array = [0, 1, 2]; @@ -254,6 +275,36 @@ test("tuple.forEach", () => { `.expectToMatchJsResult(); }); +describe("at", () => { + test("valid index", () => { + util.testFunction` + const array = [1, 2, 3, 4]; + return array.at(2); + `.expectToMatchJsResult(); + }); + + test("invalid index", () => { + util.testFunction` + const array = [1, 2, 3, 4]; + return array.at(10); + `.expectToMatchJsResult(); + }); + + test("valid negative index", () => { + util.testFunction` + const array = [1, 2, 3, 4]; + return array.at(-2); + `.expectToMatchJsResult(); + }); + + test("invalid negative index", () => { + util.testFunction` + const array = [1, 2, 3, 4]; + return array.at(-10); + `.expectToMatchJsResult(); + }); +}); + test("array.forEach (%p)", () => { util.testFunction` const array = [0, 1, 2, 3]; @@ -274,7 +325,7 @@ test.each([ { array: [0, 2, 4, 8], predicate: "false" }, ])("array.find (%p)", ({ array, predicate }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: number[] = ${util.formatCode(array)}; return array.find((elem, index, arr) => ${predicate} && arr[index] === elem); `.expectToMatchJsResult(); }); @@ -286,7 +337,7 @@ test.each([ { array: [0, 2, 4, 8], searchElement: 8 }, ])("array.findIndex (%p)", ({ array, searchElement }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: number[] = ${util.formatCode(array)}; return array.findIndex((elem, index, arr) => elem === ${searchElement} && arr[index] === elem); `.expectToMatchJsResult(); }); @@ -370,9 +421,16 @@ test.each([ { array: [0, 1, 2, 3], start: 1, deleteCount: undefined }, { array: [0, 1, 2, 3], start: 1, deleteCount: null }, ])("array.splice (%p)", ({ array, start, deleteCount, newElements = [] }) => { + const deleteCountCode = + deleteCount === undefined + ? "undefined as any" + : deleteCount === null + ? "null as any" + : util.formatCode(deleteCount); + const newElementsCode = newElements.length > 0 ? ", " + util.formatCode(...newElements) : ""; util.testFunction` - const array = ${util.formatCode(array)}; - array.splice(${util.formatCode(start, deleteCount, ...newElements)}); + const array: number[] = ${util.formatCode(array)}; + array.splice(${util.formatCode(start)}, ${deleteCountCode}${newElementsCode}); return array; `.expectToMatchJsResult(); }); @@ -459,8 +517,11 @@ test("array.join without separator argument", () => { util.testExpression`["test1", "test2"].join()`.expectToMatchJsResult(); }); +test("array.indexOf empty array", () => { + util.testExpression`([] as string[]).indexOf("test1")`.expectToMatchJsResult(); +}); + test.each([ - { array: [], args: ["test1"] }, { array: ["test1"], args: ["test1"] }, { array: ["test1", "test2"], args: ["test2"] }, { array: ["test1", "test2", "test3"], args: ["test3", 1] }, @@ -471,14 +532,40 @@ test.each([ util.testExpression`${util.formatCode(array)}.indexOf(${util.formatCode(...args)})`.expectToMatchJsResult(); }); -test.each([{ args: [1] }, { args: [1, 2, 3] }])("array.push (%p)", ({ args }) => { +test.each([ + { args: "1" }, + { args: "1, 2, 3" }, + { args: "...[1, 2, 3]" }, + { args: "1, 2, ...[3, 4]" }, + { args: "1, 2, ...[3, 4], 5" }, +])("array.push (%p)", ({ args }) => { util.testFunction` const array = [0]; - const value = array.push(${util.formatCode(...args)}); + const value = array.push(${args}); return { array, value }; `.expectToMatchJsResult(); }); +test("array.push(...)", () => { + util.testFunction` + const array = [0]; + function push(...args: any[]) { + return array.push(...args); + } + const value = push(1, 2, 3); + return { array, value }; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1256 +test.each(["[1, 2, 3]", "undefined"])("array push on optional array", value => { + util.testFunction` + const arr = ${value} as number[] | undefined; + arr?.push(4); + return arr + `.expectToMatchJsResult(); +}); + test.each([ { array: [1, 2, 3], expected: [3, 2] }, { array: [1, 2, 3, null], expected: [3, 2] }, @@ -494,7 +581,7 @@ test.each([{ array: [1, 2, 3] }, { array: [1, 2, 3, 4] }, { array: [1] }, { arra "array.reverse (%p)", ({ array }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: number[] = ${util.formatCode(array)}; array.reverse(); return array; `.expectToMatchJsResult(); @@ -503,7 +590,7 @@ test.each([{ array: [1, 2, 3] }, { array: [1, 2, 3, 4] }, { array: [1] }, { arra test.each([{ array: [1, 2, 3] }, { array: [1] }, { array: [] }])("array.shift (%p)", ({ array }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: number[] = ${util.formatCode(array)}; const value = array.shift(); return { array, value }; `.expectToMatchJsResult(); @@ -516,7 +603,7 @@ test.each([ { array: [], args: [1] }, ])("array.unshift (%p)", ({ array, args }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: number[] = ${util.formatCode(array)}; const value = array.unshift(${util.formatCode(...args)}); return { array, value }; `.expectToMatchJsResult(); @@ -524,7 +611,7 @@ test.each([ test.each([{ array: [4, 5, 3, 2, 1] }, { array: [1] }, { array: [] }])("array.sort (%p)", ({ array }) => { util.testFunctionTemplate` - const array = ${array}; + const array: number[] = ${array}; array.sort(); return array; `.expectToMatchJsResult(); @@ -582,7 +669,7 @@ describe.each(["reduce", "reduceRight"])("array.%s", reduce => { }); test("empty no initial", () => { - util.testExpression`[].${reduce}(() => {})`.expectToMatchJsResult(true); + util.testExpression`([] as any[]).${reduce}(() => {})`.expectToMatchJsResult(true); }); test("undefined returning callback", () => { @@ -598,7 +685,7 @@ test.each([{ array: [] }, { array: ["a", "b", "c"] }, { array: [{ foo: "foo" }, "array.entries (%p)", ({ array }) => { util.testFunction` - const array = ${util.formatCode(array)}; + const array: any[] = ${util.formatCode(array)}; const result = []; for (const [i, v] of array.entries()) { result.push([i, v]); @@ -670,7 +757,186 @@ test("Array.isArray returns true for empty objects", () => { util.testExpression`Array.isArray({})`.expectToEqual(true); }); +test.each([ + "[1, 2, 3]", + "(new Set([1, 2, 3])).values()", + "[1, 2, 3], value => value * 2", + "{ length: 3 }, (_, index) => index + 1", +])("Array.from(%p)", valueString => { + util.testExpression`Array.from(${valueString})`.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1576 +test("array.from with non-array iterable (#1576)", () => { + util.testFunction` + const map = new Map().set(1, 2); + return Array.from(map, ([v,k]) => ({k,v})); + `.expectToMatchJsResult(); +}); + +// Array.of +test.each(["1, 2, 3", "", "...[1, 2, 3], 4, 5, 6"])("Array.of(%p)", valueString => { + util.testExpression`Array.of(${valueString})`.expectToMatchJsResult(); +}); + // Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/738 test("array.prototype.concat issue #738", () => { util.testExpression`([] as any[]).concat(13, 323, {x: 3}, [2, 3])`.expectToMatchJsResult(); }); + +test.each(["[1, undefined, 3]", "[1, null, 3]", "[1, undefined, 2, null]"])( + "not allowed to use null or undefined in array literals (%p)", + literal => { + util.testExpression(literal).expectToHaveDiagnostics([undefinedInArrayLiteral.code]); + } +); + +test("not allowed to use null or undefined in array literals ([undefined, null, 1])", () => { + util.testExpression`[undefined, null, 1]`.expectToHaveDiagnostics([ + undefinedInArrayLiteral.code, + undefinedInArrayLiteral.code, + ]); +}); + +test.each([ + "[]", + "[1, 2, undefined]", + "[1, 2, null]", + "[1, undefined, undefined, null]", + "[undefined]", + "[undefined, null]", +])("trailing undefined or null are allowed in array literal (%p)", literal => { + util.testExpression(literal).expectToHaveNoDiagnostics(); +}); + +describe("array.fill", () => { + test.each(["([] as number[])", "[1]", "[1,2,3,4]"])( + "Fills full length of array without other parameters (%p)", + arr => { + util.testExpression`${arr}.fill(5)`.expectToMatchJsResult(); + } + ); + + test.each(["[1,2,3]", "[1,2,3,4,5,6]"])("Fills starting from start parameter (%p)", arr => { + util.testExpression`${arr}.fill(5, 3)`.expectToMatchJsResult(); + }); + + test("handles negative start parameter", () => { + util.testExpression`[1,2,3,4,5,6,7].fill(8, -3)`.expectToMatchJsResult(); + }); + + test("handles negative end parameter", () => { + util.testExpression`[1,2,3,4,5,6,7].fill(8, -5, -2)`.expectToMatchJsResult(); + }); + + test("Fills starting from start parameter, up to ending parameter", () => { + util.testExpression`[1,2,3,4,5,6,7,8].fill(5, 2, 6)`.expectToMatchJsResult(); + }); + + // NOTE: This is different from the default ECMAScript specification for the behavior, but for Lua this is much more useful + test("Extends size of the array if ending size is larger than array", () => { + util.testExpression`[1,2,3].fill(5, 0, 6)`.expectToEqual([5, 5, 5, 5, 5, 5]); + }); +}); + +// Issue #1218: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1218 +test.each(["[1, 2, 3]", "undefined"])("prototype call on nullable array (%p)", value => { + util.testFunction` + function find(arr?: number[]) { + return arr?.indexOf(2); + } + return find(${value}); + ` + .setOptions({ strictNullChecks: true }) + .expectToMatchJsResult(); +}); + +describe("copying array methods", () => { + test("toReversed", () => { + util.testFunction` + const original = [1,2,3,4,5]; + const reversed = original.toReversed(); + + return {original, reversed}; + `.expectToEqual({ + original: [1, 2, 3, 4, 5], + reversed: [5, 4, 3, 2, 1], + }); + }); + + test("toSorted", () => { + util.testFunction` + const original = [5,2,1,4,3]; + const sorted = original.toSorted(); + + return {original, sorted}; + `.expectToEqual({ + original: [5, 2, 1, 4, 3], + sorted: [1, 2, 3, 4, 5], + }); + }); + + test("toSpliced", () => { + util.testFunction` + const original = [1,2,3,4,5]; + const spliced = original.toSpliced(2, 2, 10, 11); + + return {original, spliced}; + `.expectToEqual({ + original: [1, 2, 3, 4, 5], + spliced: [1, 2, 10, 11, 5], + }); + }); + + test("with", () => { + util.testFunction` + const original = [1,2,3,4,5]; + const updated = original.with(2, 10); + + return {original, updated}; + `.expectToEqual({ + original: [1, 2, 3, 4, 5], + updated: [1, 2, 10, 4, 5], + }); + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1605 +test("array indexing in optional chain (#1605)", () => { + util.testModule` + interface Foo extends Array {} + const b: {arr?: Foo} = {arr:[1,2]}; + export const t = b.arr?.[1]; + + const c: Foo | undefined = b.arr; + export const u = c?.[1]; + ` + .setOptions({ strict: true }) // crucial to reproducing for some reason + .expectToMatchJsResult(); +}); + +test("new Array()", () => { + util.testFunction` + const arr = new Array(); + arr.push(1,2,3); + return arr; + `.expectToMatchJsResult(); +}); + +test("new Array()", () => { + util.testFunction` + const arr = new Array(); + arr.push(1,2,3); + return arr; + `.expectToMatchJsResult(); +}); + +test("new Array(length)", () => { + util.testFunction` + const arr = new Array(10); + `.expectToHaveDiagnostics([unsupportedArrayWithLengthConstructor.code]); +}); + +test("new Array(...items)", () => { + util.testExpression`new Array(1,2,3,4,5) `.expectToMatchJsResult(); +}); diff --git a/test/unit/builtins/async-await.spec.ts b/test/unit/builtins/async-await.spec.ts new file mode 100644 index 000000000..1c5d23018 --- /dev/null +++ b/test/unit/builtins/async-await.spec.ts @@ -0,0 +1,1252 @@ +import { ModuleKind, ScriptTarget } from "typescript"; +import { LuaTarget } from "../../../src"; +import { + awaitMustBeInAsyncFunction, + unsupportedAsyncGenerator, + unsupportedForAwaitOf, + unsupportedForTargetButOverrideAvailable, +} from "../../../src/transformation/utils/diagnostics"; +import * as util from "../../util"; + +const promiseTestLib = ` +// Some logging utility, useful for asserting orders of operations + +const allLogs: any[] = []; +function log(...values: any[]) { + allLogs.push(...values); +} + +// Create a promise and store its resolve and reject functions, useful for creating pending promises + +function defer() { + let resolve: (data: any) => void = () => {}; + let reject: (reason: string) => void = () => {}; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; +}`; + +test("high amount of chained awaits doesn't cause stack overflow", () => { + util.testFunction` + let result = "not executed"; + + async function delay() { + return; + } + + async function loop() { + try { + for (let i = 0; i < 500000; ++i) { + await delay(); + } + result = "success"; + } catch (e: any) { + result = e; + } + } + + loop(); + + return result; + `.expectToEqual("success"); +}); + +test("can await already resolved promise", () => { + util.testFunction` + const result: unknown[] = []; + async function abc() { + return await Promise.resolve(30); + } + abc().then(value => result.push(value)); + + return result; + `.expectToEqual([30]); +}); + +test("can await already rejected promise", () => { + util.testFunction` + const result: unknown[] = []; + async function abc() { + return await Promise.reject("test rejection"); + } + abc().catch(reason => result.push(reason)); + + return result; + `.expectToEqual(["test rejection"]); +}); + +test("can await pending promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(data => log("resolving original promise", data)); + + async function abc() { + return await promise; + } + + const awaitingPromise = abc(); + awaitingPromise.then(data => log("resolving awaiting promise", data)); + + resolve("resolved data"); + + return allLogs; + + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolving original promise", "resolved data", "resolving awaiting promise", "resolved data"]); +}); + +test("can await non-promise values", () => { + util.testFunction` + async function foo() { + return await "foo"; + } + + async function bar() { + return await { foo: await foo(), bar: "bar" }; + } + + async function baz() { + return (await bar()).foo + (await bar()).bar; + } + + const { state, value } = baz() as any; + return { state, value }; + `.expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "foobar", + }); +}); + +test.each(["async function abc() {", "const abc = async () => {"])( + "can return non-promise from async function (%p)", + functionHeader => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(data => log("resolving original promise", data)); + + ${functionHeader} + await promise; + return "abc return data" + } + + const awaitingPromise = abc(); + awaitingPromise.then(data => log("resolving awaiting promise", data)); + + resolve("resolved data"); + + return allLogs; + + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "resolving original promise", + "resolved data", + "resolving awaiting promise", + "abc return data", + ]); + } +); + +test.each(["async function abc() {", "const abc = async () => {"])( + "can have multiple awaits in async function (%p)", + functionHeader => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + promise1.then(data => log("resolving promise1", data)); + promise2.then(data => log("resolving promise2", data)); + promise3.then(data => log("resolving promise3", data)); + + ${functionHeader} + const result1 = await promise1; + const result2 = await promise2; + const result3 = await promise3; + return [result1, result2, result3]; + } + + const awaitingPromise = abc(); + awaitingPromise.then(data => log("resolving awaiting promise", data)); + + resolve1("data1"); + resolve2("data2"); + resolve3("data3"); + + return allLogs; + + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "resolving promise1", + "data1", + "resolving promise2", + "data2", + "resolving promise3", + "data3", + "resolving awaiting promise", + ["data1", "data2", "data3"], + ]); + } +); + +test("can make inline async functions", () => { + util.testFunction` + const foo = async function() { return "foo"; }; + const bar = async function() { return await foo(); }; + + const { state, value } = bar() as any; + return { state, value }; + `.expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "foo", + }); +}); + +test("can make async lambdas with expression body", () => { + util.testFunction` + const foo = async () => "foo"; + const bar = async () => await foo(); + + const { state, value } = bar() as any; + return { state, value }; + `.expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "foo", + }); +}); + +test("can await async function from async function", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(data => log("resolving original promise", data)); + + async function abc() { + return await promise; + } + + async function def() { + return await abc(); + } + + const awaitingPromise = def(); + awaitingPromise.then(data => log("resolving awaiting promise", data)); + + resolve("resolved data"); + + return allLogs; + + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolving original promise", "resolved data", "resolving awaiting promise", "resolved data"]); +}); + +test("async function returning value is same as non-async function returning promise", () => { + util.testFunction` + function f(): Promise { + return Promise.resolve(42); + } + + async function fAsync(): Promise { + return 42; + } + + const { state: state1, value: value1 } = f() as any; + const { state: state2, value: value2 } = fAsync() as any; + + return { + state1, value1, + state2, value2 + }; + `.expectToEqual({ + state1: 1, // __TS__PromiseState.Fulfilled + value1: 42, + state2: 1, // __TS__PromiseState.Fulfilled + value2: 42, + }); +}); + +test("correctly handles awaited functions rejecting", () => { + util.testFunction` + const { promise: promise1, reject } = defer(); + const { promise: promise2 } = defer(); + + promise1.then(data => log("resolving promise1", data), reason => log("rejecting promise1", reason)); + promise2.then(data => log("resolving promise2", data)); + + async function abc() { + const result1 = await promise1; + const result2 = await promise2; + return [result1, result2]; + } + + const awaitingPromise = abc(); + awaitingPromise.catch(reason => log("awaiting promise was rejected because:", reason)); + + reject("test reject"); + + return allLogs; + + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["rejecting promise1", "test reject", "awaiting promise was rejected because:", "test reject"]); +}); + +test("can call async function at top-level", () => { + util.testModule` + export let aStarted = false; + async function a() { + aStarted = true; + return 42; + } + + a(); // Call async function (but cannot await) + ` + .setOptions({ module: ModuleKind.ESNext, target: ScriptTarget.ES2017 }) + .expectToEqual({ + aStarted: true, + }); +}); + +test("async function throws error", () => { + util.testFunction` + async function a() { + throw "test throw"; + } + + const { state, rejectionReason } = a() as any; + return { state, rejectionReason }; + `.expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "test throw", + }); +}); + +test("async lambda throws error", () => { + util.testFunction` + const a = async () => { + throw "test throw"; + } + + const { state, rejectionReason } = a() as any; + return { state, rejectionReason }; + `.expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "test throw", + }); +}); + +test("async function throws object", () => { + util.testFunction` + async function a() { + throw new Error("test throw"); + } + + const { state, rejectionReason } = a() as any; + return { state, rejectionReason }; + `.expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: { + message: "test throw", + name: "Error", + stack: expect.stringContaining("stack traceback"), + }, + }); +}); + +test.each([ + "await a();", + "const b = await a();", + "export const b = await a();", + "declare function foo(n: number): number; foo(await a());", + "declare function foo(n: number): number; const b = foo(await a());", + "const b = [await a()];", + "const b = [4, await a()];", + "const b = true ? 4 : await a();", +])("cannot await at top-level (%p)", awaitUsage => { + util.testModule` + async function a() { + return 42; + } + + ${awaitUsage} + export {} // Required to make TS happy, cannot await without import/exports + ` + .setOptions({ module: ModuleKind.ESNext, target: ScriptTarget.ES2017 }) + .expectToHaveDiagnostics([awaitMustBeInAsyncFunction.code]); +}); + +test("async function can access varargs", () => { + util.testFunction` + const { promise, resolve } = defer(); + + async function a(...args: string[]) { + log(await promise); + log(args[1]); + } + + const awaitingPromise = a("A", "B", "C"); + resolve("resolved"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolved", "B"]); +}); + +test("async function can forward varargs", () => { + util.testFunction` + const { promise, resolve } = defer(); + + async function a(...args: string[]) { + log(await promise); + log(...args); + } + + const awaitingPromise = a("A", "B", "C"); + resolve("resolved"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolved", "A", "B", "C"]); +}); + +test("async function adopts pending promise", () => { + util.testFunction` + let resolve: (v: string) => void = () => {}; + async function receive(): Promise { + return new Promise(res => { + resolve = res; + }); + } + + receive().then(v => { + log(v); + }); + + resolve("delayed resolve"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["delayed resolve"]); +}); + +test("async function adopts resolved promise", () => { + util.testFunction` + async function receive(): Promise { + return new Promise(resolve => { + resolve("resolved!"); + }); + } + + receive().then(v => { + log(v); + }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolved!"]); +}); + +test("async function adopts rejected promise", () => { + util.testFunction` + async function receive(): Promise { + return new Promise((_, reject) => { + reject("rejected"); + }); + } + + receive().catch(err => { + log(err); + }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["rejected"]); +}); + +test("return in catch aborts async method", () => { + util.testFunction` + async function asyncFunc() { + try { + await Promise.reject("rejection"); + log("Should not be seen"); + } catch { + log("C"); + return "result"; + } + log("Should also not be seen"); + } + + asyncFunc().then(v => log("resolved", v)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["C", "resolved", "result"]); +}); + +test.each(["async function abc() {", "const abc = async () => {"])( + "can throw error after await in async function (%p)", + functionHeader => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(data => log("resolving first promise", data)); + + ${functionHeader} + await promise; + log("run abc"); + throw "test throw"; + } + + const awaitingPromise = abc(); + awaitingPromise.catch(error => log("caught error", error)); + + resolve("resolved data"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["resolving first promise", "resolved data", "run abc", "caught error", "test throw"]); + } +); + +test.each(["async function abc() {", "const abc = async () => {"])( + "can throw object after await in async function (%p)", + functionHeader => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(data => log("resolving first promise", data)); + + ${functionHeader} + await promise; + log("run abc"); + throw new Error("test throw"); + } + + const awaitingPromise = abc(); + awaitingPromise.catch(error => log("caught error", error)); + + resolve("resolved data"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "resolving first promise", + "resolved data", + "run abc", + "caught error", + { + message: "test throw", + name: "Error", + stack: expect.stringContaining("stack traceback"), + }, + ]); + } +); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1105 +describe("try/catch in async function", () => { + util.testEachVersion( + "await inside try/catch returns inside async function", + () => util.testModule` + export let result = 0; + async function foo(): Promise { + try { + return await new Promise(resolve => resolve(4)); + } catch { + throw "an error occurred in the async function" + } + } + foo().then(value => { + result = value; + }); + `, + // Cannot execute LuaJIT with test runner + { + ...util.expectEachVersionExceptJit(builder => builder.expectToEqual({ result: 4 })), + [LuaTarget.Lua50]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + [LuaTarget.Lua51]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + } + ); + + util.testEachVersion( + "await inside try/catch throws inside async function", + () => util.testModule` + export let reason = ""; + async function foo(): Promise { + try { + return await new Promise((resolve, reject) => reject("test error")); + } catch (e) { + throw "an error occurred in the async function: " + e; + } + } + foo().catch(e => { + reason = e; + }); + `, + { + ...util.expectEachVersionExceptJit(builder => + builder.expectToEqual({ reason: "an error occurred in the async function: test error" }) + ), + [LuaTarget.Lua50]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + [LuaTarget.Lua51]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + } + ); + + util.testEachVersion( + "await inside try/catch deferred rejection uses catch clause", + () => + util.testModule` + export let reason = ""; + let reject: (reason: string) => void = () => { throw "should be overridden!"; } + + async function foo(): Promise { + try { + return await new Promise((res, rej) => { reject = rej; }); + } catch (e) { + throw "an error occurred in the async function: " + e; + } + } + foo().catch(e => { + reason = e; + }); + reject("test error"); + `, + { + ...util.expectEachVersionExceptJit(builder => + builder.expectToEqual({ reason: "an error occurred in the async function: test error" }) + ), + [LuaTarget.Lua50]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + [LuaTarget.Lua51]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + } + ); + + test("try/finally in async function", () => { + util.testModule` + const foo = async () => { + throw "foo error"; + }; + + let finallyCalled = false; + + const run = async () => { + try { + await foo(); + } finally { + finallyCalled = true; + } + return 10; + }; + + let succeeded: any = false; + let rejected: any = false; + + run() + .then(_ => { succeeded = true }) + .catch(e => { rejected = e }); + + export const result = { finallyCalled, succeeded, rejected }; + `.expectToEqual({ + result: { + finallyCalled: true, + succeeded: false, + rejected: "foo error", + }, + }); + }); + + test("async function adopts pending promise in try", () => { + util.testFunction` + let resolve: (v: string) => void = () => {}; + async function receive(): Promise { + try + { + return new Promise(res => { + resolve = res; + }); + } + catch + { + return "catch"; + } + } + + receive().then(v => { + log(v); + }); + + resolve("delayed resolve"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["delayed resolve"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1272 + test("Awaiting a rejected promise should halt function execution (#1272)", () => { + util.testModule` + const foo = async () => { + throw new Error('foo error'); + }; + + let halted = true; + let caught = ""; + + const run = async () => { + try { + await foo(); + halted = false; + } catch (err) { + caught = 'catch err: ' + err; + } + }; + + let succeeded: any = false; + let rejected: any = false; + + run() + .then(_ => { succeeded = true }, + e => { rejected = e }); + + export const result = { halted, caught, succeeded, rejected }; + `.expectToEqual({ + result: { + halted: true, + caught: "catch err: Error: foo error", + succeeded: true, + rejected: false, + }, + }); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1272 + test("Awaiting a rejecting promise should halt function execution (#1272)", () => { + util.testModule` + let rej: (error: any) => void = () => {}; + const foo = () => new Promise((_, reject) => { + rej = reject; + }); + + let halted = true; + let caught = ""; + + const run = async () => { + try { + await foo(); + halted = false; + } catch (err) { + caught = 'catch err: ' + err; + } + }; + + let succeeded: any = false; + let rejected: any = false; + + run() + .then(_ => { succeeded = true }, + e => { rejected = e }); + + rej("rejection message"); + + export const result = { halted, caught, succeeded, rejected }; + `.expectToEqual({ + result: { + halted: true, + caught: "catch err: rejection message", + succeeded: true, + rejected: false, + }, + }); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1272 + test("Async try/catch complicated case (#1272)", () => { + util.testModule` + const foo = async () => { + throw new Error('foo error'); + }; + + let halted = true; + let caught = ""; + + const run = async () => { + try { + await foo(); // This throws + } catch (err) { + caught = 'catch err: ' + err; // This catches the async thrown error, function continues + } + try { + throw "throw 2"; // Another throw + } catch (err) { + try { + await foo(); + } catch (err2) { + return \`caught: \${err}, then: \${err2}\`; // Async function should exit here + } + } + halted = false; // This code should not be called + return 10; + }; + + let succeeded: any = false; + let rejected: any = false; + let value: any = undefined; + + run() + .then(v => { succeeded = true; value = v }, + e => { rejected = e }); + + export const result = { halted, caught, succeeded, rejected, value }; + `.expectToEqual({ + result: { + halted: true, + caught: "catch err: Error: foo error", + succeeded: true, + rejected: false, + value: "caught: throw 2, then: Error: foo error", + }, + }); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1659 + test("await inside catch handler resolves correctly (#1659)", () => { + util.testFunction` + let reject: (reason: string) => void = () => {}; + + async function failing() { + return new Promise((_, rej) => { reject = rej; }); + } + + async function run() { + try { + await failing(); + } catch (e) { + log("catch"); + const a = await Promise.resolve(true); + log("a", a); + } + } + + run(); + reject("error"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["catch", "a", true]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1659 + test("await inside finally handler resolves correctly (#1659)", () => { + util.testFunction` + let reject: (reason: string) => void = () => {}; + + async function failing() { + return new Promise((_, rej) => { reject = rej; }); + } + + async function run() { + try { + await failing(); + } finally { + log("finally"); + const a = await Promise.resolve(true); + log("a", a); + } + } + + run().catch(() => {}); + reject("error"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["finally", "a", true]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1659 + test("await inside both catch and finally handlers (#1659)", () => { + util.testFunction` + let reject: (reason: string) => void = () => {}; + + async function failing() { + return new Promise((_, rej) => { reject = rej; }); + } + + async function run() { + try { + await failing(); + } catch (e) { + log("catch"); + const a = await Promise.resolve("caught"); + log("a", a); + } finally { + log("finally"); + const b = await Promise.resolve("done"); + log("b", b); + } + } + + run(); + reject("error"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["catch", "a", "caught", "finally", "b", "done"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1659 + test("awaited value in catch is returned from async function (#1659)", () => { + util.testFunction` + const failing = defer(); + const recovery = defer(); + + async function run() { + try { + await failing.promise; + return "succeeded"; + } catch (e) { + return await recovery.promise; + } + } + + run().then(value => log("result", value)); + + failing.reject("error"); + recovery.resolve("recovered"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["result", "recovered"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + test("return inside try with deferred promise (#1706)", () => { + util.testFunction` + let resolveLater!: (value: string) => void; + + function deferredPromise(): Promise { + return new Promise(resolve => { + resolveLater = (v) => resolve(v); + }); + } + + async function fn(): Promise { + try { + return await deferredPromise(); + } catch { + return 'caught'; + } + log('unreachable!'); + } + + const promise = fn(); + resolveLater('ok'); + promise.then(v => log(v)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["ok"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + test("return inside try in loop with deferred promise (#1706)", () => { + util.testFunction` + let resolveLater!: (value: string) => void; + + function deferredPromise(): Promise { + return new Promise(resolve => { + resolveLater = (v) => resolve(v); + }); + } + + async function fn(): Promise { + while (true) { + try { + return await deferredPromise(); + } catch { + return 'caught'; + } + log('unreachable!'); + } + } + + const promise = fn(); + resolveLater('ok'); + promise.then(v => log(v)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["ok"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + test("return from catch with deferred promise (#1706)", () => { + util.testFunction` + let rejectLater!: (reason: string) => void; + + function deferredPromise(): Promise { + return new Promise((_, reject) => { + rejectLater = (r) => reject(r); + }); + } + + async function fn(): Promise { + try { + return await deferredPromise(); + } catch (e) { + return 'caught: ' + e; + } + log('unreachable!'); + } + + const promise = fn(); + rejectLater('oops'); + promise.then(v => log(v)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["caught: oops"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + util.testEachVersion( + "break inside try in async loop (#1706)", + () => util.testModule` + export let result = "not set"; + async function fn(): Promise { + while (true) { + try { + await Promise.resolve(); + break; + } catch {} + } + result = "done"; + } + fn(); + `, + { + ...util.expectEachVersionExceptJit(builder => builder.expectToEqual({ result: "done" })), + [LuaTarget.Lua50]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + [LuaTarget.Lua51]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + } + ); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + util.testEachVersion( + "continue inside try in async loop (#1706)", + () => util.testModule` + export const results: number[] = []; + async function fn(): Promise { + for (let i = 0; i < 3; i++) { + try { + await Promise.resolve(); + if (i === 1) continue; + } catch {} + results.push(i); + } + } + fn(); + `, + { + ...util.expectEachVersionExceptJit(builder => builder.expectToEqual({ results: [0, 2] })), + [LuaTarget.Lua50]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + [LuaTarget.Lua51]: builder => + builder.expectToHaveDiagnostics([unsupportedForTargetButOverrideAvailable.code]), + } + ); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + test("multi return from try in async function (#1706)", () => { + util.testFunction` + async function fn(): Promise> { + try { + await Promise.resolve(); + return $multi("foo", "bar"); + } catch { + return $multi("err", "err"); + } + } + + let result: string[] = []; + fn().then(v => { const [a, b] = v; result = [a, b]; }); + + return result; + ` + .withLanguageExtensions() + .expectToEqual(["foo", "bar"]); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1706 + test("return inside try with finally (#1706)", () => { + util.testFunction` + let resolveLater!: (value: string) => void; + + function deferredPromise(): Promise { + return new Promise(resolve => { + resolveLater = (v) => resolve(v); + }); + } + + async function fn(): Promise { + try { + return await deferredPromise(); + } finally { + log('finally'); + } + } + + const promise = fn(); + resolveLater('ok'); + promise.then(v => log(v)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["finally", "ok"]); + }); + + test.each([0, 1, 2])("async re-throw (%p)", i => { + util.testModule` + const i: number = ${i}; + async function foo() { + try { + try { + if (i === 0) { throw "z"; } + } catch (e) { + throw "a"; + } finally { + if (i === 1) { throw "b"; } + } + } catch (e) { + throw (e as string).toUpperCase(); + } finally { + throw "C"; + } + } + export let result: string = "x"; + async function run() { + try { + await foo(); + } catch (e) { + result = (e as string)[(e as string).length - 1]; + } + } + run(); + `.expectToEqual({ result: "C" }); + }); + + test("async: catch re-throws, finally still runs", () => { + util.testModule` + const foo = async () => { + throw "original"; + }; + + let finallyCalled = false; + let caughtError: any = false; + + const run = async () => { + try { + await foo(); + } catch (e) { + throw "re-thrown: " + e; + } finally { + finallyCalled = true; + } + }; + + run().catch(e => { caughtError = e; }); + + export const result = { finallyCalled, caughtError }; + `.expectToEqual({ + result: { + finallyCalled: true, + caughtError: "re-thrown: original", + }, + }); + }); + + test("async: finally throw overrides catch throw", () => { + util.testModule` + const run = async () => { + try { + throw "try-error"; + } catch (e) { + throw "catch-error"; + } finally { + throw "finally-error"; + } + }; + + let caughtError: any = false; + run().catch(e => { caughtError = e; }); + + export const result = caughtError; + `.expectToEqual({ result: "finally-error" }); + }); + + test("async: finally return overrides catch throw", () => { + util.testFunction` + async function run() { + try { + throw "try-error"; + } catch (e) { + throw "catch-error"; + } finally { + return "finally-return"; + } + } + + let result: any; + run().then(v => { result = v; }).catch(e => { result = "rejected: " + e; }); + + return result; + `.expectToEqual("finally-return"); + }); +}); + +describe("async generators are unsupported", () => { + test.each([ + "async function* gen() { yield 1; }", + "const gen = async function*() { yield 1; };", + "const gen = { async *m() { yield 1; } };", + "class C { async *m() { yield 1; } }", + ])("diagnoses %p", source => { + util.testModule` + ${source} + export {} + `.expectToHaveDiagnostics([unsupportedAsyncGenerator.code]); + }); +}); + +test("for-await-of is unsupported", () => { + util.testModule` + async function run(items: AsyncIterable) { + for await (const x of items) { + void x; + } + } + export {} + `.expectToHaveDiagnostics([unsupportedForAwaitOf.code]); +}); diff --git a/test/unit/builtins/loading.spec.ts b/test/unit/builtins/loading.spec.ts index fa213d03f..563870f6d 100644 --- a/test/unit/builtins/loading.spec.ts +++ b/test/unit/builtins/loading.spec.ts @@ -4,40 +4,80 @@ import * as util from "../../util"; describe("luaLibImport", () => { test("inline", () => { - util.testExpression`[0].push(1)` + util.testExpression`[0].indexOf(1)` .setOptions({ luaLibImport: tstl.LuaLibImportKind.Inline }) .tap(builder => expect(builder.getMainLuaCodeChunk()).not.toContain('require("lualib_bundle")')) .expectToMatchJsResult(); }); test("require", () => { - util.testExpression`[0].push(1)` + util.testExpression`[0].indexOf(1)` .setOptions({ luaLibImport: tstl.LuaLibImportKind.Require }) .tap(builder => expect(builder.getMainLuaCodeChunk()).toContain('require("lualib_bundle")')) .expectToMatchJsResult(); }); - test("always", () => { - util.testModule`` - .setOptions({ luaLibImport: tstl.LuaLibImportKind.Always }) + function testLualibOnlyHasArrayIndexOf(builder: util.TestBuilder) { + const lualibBundle = builder.getLuaResult().transpiledFiles.find(f => f.outPath.endsWith("lualib_bundle.lua"))!; + expect(lualibBundle).toBeDefined(); + expect(lualibBundle.lua).toEqual(expect.stringMatching("^local function __TS__ArrayIndexOf")); + expect(lualibBundle.lua).not.toContain("__TS__ArrayConcat"); + expect(lualibBundle.lua).not.toContain("Error"); + } + + test("require-minimal", () => { + util.testExpression`[0].indexOf(1)` + .setOptions({ luaLibImport: tstl.LuaLibImportKind.RequireMinimal }) .tap(builder => expect(builder.getMainLuaCodeChunk()).toContain('require("lualib_bundle")')) - .expectToEqual(undefined); + .tap(testLualibOnlyHasArrayIndexOf) + .expectToMatchJsResult(); + }); + + test("require-minimal with lualib in another file", () => { + util.testModule` + import "./other"; + ` + .setOptions({ luaLibImport: tstl.LuaLibImportKind.RequireMinimal }) + .addExtraFile( + "other.lua", + ` +local ____lualib = require("lualib_bundle") +local __TS__ArrayIndexOf = ____lualib.__TS__ArrayIndexOf +__TS__ArrayIndexOf({}, 1) + ` + ) + // note: indent matters in above code, because searching for lualib checks for start & end of line + .tap(testLualibOnlyHasArrayIndexOf) + .expectNoExecutionError(); }); }); -test.each([tstl.LuaLibImportKind.Inline, tstl.LuaLibImportKind.None, tstl.LuaLibImportKind.Require])( - "should not include lualib without code (%p)", - luaLibImport => { - util.testModule``.setOptions({ luaLibImport }).tap(builder => expect(builder.getMainLuaCodeChunk()).toBe("")); - } -); +test.each([ + tstl.LuaLibImportKind.Inline, + tstl.LuaLibImportKind.None, + tstl.LuaLibImportKind.Require, + tstl.LuaLibImportKind.RequireMinimal, +])("should not include lualib without code (%p)", luaLibImport => { + util.testModule``.setOptions({ luaLibImport }).tap(builder => expect(builder.getMainLuaCodeChunk()).toBe("")); +}); test("lualib should not include tstl header", () => { - util.testExpression`[0].push(1)`.tap(builder => + util.testExpression`[0].indexOf(1)`.tap(builder => expect(builder.getMainLuaCodeChunk()).not.toContain("Generated with") ); }); +test("using lualib does not crash when coroutine is not defined", () => { + util.testModule` + declare const _G: any; + declare function require(this: void, name: string): any + + _G.coroutine = undefined; + require("lualib_bundle"); + export const result = 1 + `.expectToEqual({ result: 1 }); +}); + describe("Unknown builtin property", () => { test("access", () => { util.testExpression`Math.unknownProperty` diff --git a/test/unit/builtins/map.spec.ts b/test/unit/builtins/map.spec.ts index 7eec8844d..c9f6c1a2b 100644 --- a/test/unit/builtins/map.spec.ts +++ b/test/unit/builtins/map.spec.ts @@ -209,3 +209,85 @@ describe.each(iterationMethods)("map.%s() preserves insertion order", iterationM `.expectToMatchJsResult(); }); }); + +describe.each(iterationMethods)("map.%s() handles mutation", iterationMethod => { + test("iterator persists after delete", () => { + util.testFunction` + const map = new Map([[1, "a"], [2, "b"]]); + const iter = map.${iterationMethod}(); + map.delete(1); + return iter.next().value; + `.expectToMatchJsResult(); + }); + + test("iterator with delete and add between iterations", () => { + util.testFunction` + const map = new Map([[1, "a"], [2, "b"], [3, "c"]]); + const iter = map.${iterationMethod}(); + iter.next(); // 1 + map.delete(2); + map.set(4, "d"); + const results: IteratorResult[] = []; + let r = iter.next(); + while (!r.done) { results.push({ done: r.done, value: r.value }); r = iter.next(); } + return results; + `.expectToMatchJsResult(); + }); + + test("iterator does not restart after exhaustion", () => { + util.testFunction` + const map = new Map([[1, "a"], [2, "b"]]); + const iter = map.${iterationMethod}(); + const results: boolean[] = []; + results.push(iter.next().done!); + results.push(iter.next().done!); + results.push(iter.next().done!); // should be done + results.push(iter.next().done!); // should still be done, not restart + return results; + `.expectToMatchJsResult(); + }); +}); + +describe("Map.groupBy", () => { + test("empty", () => { + util.testFunction` + const array: number[] = []; + + const map = Map.groupBy(array, (num, index) => { + return num % 2 === 0 ? "even": "odd"; + }); + + return Object.fromEntries(map.entries()); + `.expectToEqual([]); + }); + + test("groupBy", () => { + util.testFunction` + const array = [0, 1, 2, 3, 4, 5]; + + const map = Map.groupBy(array, (num, index) => { + return num % 2 === 0 ? "even": "odd"; + }); + + return Object.fromEntries(map.entries()); + `.expectToEqual({ + even: [0, 2, 4], + odd: [1, 3, 5], + }); + }); + + test("groupBy index", () => { + util.testFunction` + const array = [0, 1, 2, 3, 4, 5]; + + const map = Map.groupBy(array, (num, index) => { + return index < 3 ? "low": "high"; + }); + + return Object.fromEntries(map.entries()); + `.expectToEqual({ + low: [0, 1, 2], + high: [3, 4, 5], + }); + }); +}); diff --git a/test/unit/builtins/math.spec.ts b/test/unit/builtins/math.spec.ts index dd928c68d..d09b331cd 100644 --- a/test/unit/builtins/math.spec.ts +++ b/test/unit/builtins/math.spec.ts @@ -1,28 +1,88 @@ import * as tstl from "../../../src"; import * as util from "../../util"; +// These test are kept to a minimum, +// because we just want to confirm translation is correct +// and not test Lua's built in math functions. +// Differences in math implementations between JS & Lua cause inaccuracies +// therefore test input numbers are "carefully" selected to always match accuratly. +// Lualib implementations are tested separately. test.each([ - "Math.cos()", - "Math.sin()", - "Math.min()", - "Math.log2(3)", - "Math.log10(3)", - "const x = Math.log2(3)", - "const x = Math.log10(3)", - "Math.log1p(3)", - "Math.round(3.3)", + // log + "Math.log(42)", + "Math.log10(10)", + "Math.log2(42)", + "Math.log1p(42)", + // round + "Math.round(0.1)", + "Math.round(0.9)", + "Math.round(0.5)", + // abs + "Math.abs(-42)", + "Math.abs(42)", + // trigometric + "Math.acos(0.42)", + "Math.asin(0.42)", + "Math.atan(0.42)", + "Math.cos(42)", + "Math.sin(42)", + "Math.tan(42)", "Math.PI", + // ceil & floor + "Math.ceil(42.42)", + "Math.floor(42.42)", + // exp + "Math.exp(42)", + // max & min + "Math.max(-42, 42)", + "Math.max(42, -42)", + "Math.max(42, 42)", + "Math.max(-42, -42)", + "Math.min(42, -42)", + "Math.min(-42, 42)", + "Math.min(42, 42)", + "Math.min(-42, -42)", + // pow + "Math.pow(4.2, 4.2)", + "Math.pow(4.2, -4.2)", + "Math.pow(-4.2, -4.2)", + // random + // "Math.random()", + // sqrt + "Math.sqrt(2)", + "Math.sqrt(-2)", + // trunc + "Math.trunc(42.42)", + "Math.trunc(-42.42)", + "Math.trunc(0)", + "Math.trunc(Infinity)", + "Math.trunc(-Infinity)", ])("%s", code => { - // TODO: Remove? - util.testFunction(code).disableSemanticCheck().expectLuaToMatchSnapshot(); + util.testExpression(code).expectToMatchJsResult(); }); +// Hard to test properly +util.testExpression("Math.random()").expectNoExecutionError(); + test.each(["E", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"])("Math.%s", constant => { util.testExpression`Math.${constant}`.tap(builder => { expect(builder.getLuaExecutionResult()).toBeCloseTo(builder.getJsExecutionResult()); }); }); +// LuaLib MathSign +test.each([ + "Math.sign(-42)", + "Math.sign(42)", + "Math.sign(-4.2)", + "Math.sign(4.2)", + "Math.sign(0)", + "Math.sign(-Infinity)", +])("%s", code => { + util.testExpression(code).expectToMatchJsResult(); +}); + +// LuaLib Atan2 const expectMathAtan2: util.TapCallback = builder => expect(builder.getMainLuaCodeChunk()).toContain("math.atan2("); const expectMathAtan: util.TapCallback = builder => expect(builder.getMainLuaCodeChunk()).toContain("math.atan("); const expectLualibMathAtan2: util.TapCallback = builder => @@ -31,17 +91,23 @@ const expectLualibMathAtan2: util.TapCallback = builder => util.testEachVersion("Math.atan2", () => util.testExpression`Math.atan2(4, 5)`, { [tstl.LuaTarget.Universal]: builder => builder.tap(expectLualibMathAtan2), [tstl.LuaTarget.LuaJIT]: builder => builder.tap(expectMathAtan2), + [tstl.LuaTarget.Lua50]: builder => builder.tap(expectMathAtan2), [tstl.LuaTarget.Lua51]: builder => builder.tap(expectMathAtan2), [tstl.LuaTarget.Lua52]: builder => builder.tap(expectMathAtan2), [tstl.LuaTarget.Lua53]: builder => builder.tap(expectMathAtan), - [tstl.LuaTarget.Lua54]: builder => builder.tap(expectMathAtan2), + [tstl.LuaTarget.Lua54]: builder => builder.tap(expectMathAtan), + [tstl.LuaTarget.Lua55]: builder => builder.tap(expectMathAtan), + [tstl.LuaTarget.Luau]: builder => builder.tap(expectMathAtan2), }); -util.testEachVersion("Math.atan2(4, 5)", () => util.testExpression`Math.atan2(4, 5)`, { - [tstl.LuaTarget.Universal]: builder => builder.expectToMatchJsResult(), - [tstl.LuaTarget.LuaJIT]: false, - [tstl.LuaTarget.Lua51]: builder => builder.expectToMatchJsResult(), - [tstl.LuaTarget.Lua52]: builder => builder.expectToMatchJsResult(), - [tstl.LuaTarget.Lua53]: builder => builder.expectToMatchJsResult(), - [tstl.LuaTarget.Lua54]: builder => builder.expectToMatchJsResult(), -}); +util.testEachVersion( + "Math.atan2(4, 5)", + () => util.testExpression`Math.atan2(4, 5)`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); + +util.testEachVersion( + "Math.pow(3, 5)", + () => util.testExpression`Math.pow(3, 5)`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); diff --git a/test/unit/builtins/numbers.spec.ts b/test/unit/builtins/numbers.spec.ts index f58209c31..9570e4af2 100644 --- a/test/unit/builtins/numbers.spec.ts +++ b/test/unit/builtins/numbers.spec.ts @@ -1,8 +1,6 @@ import * as util from "../../util"; test.each([ - "NaN === NaN", - "NaN !== NaN", "NaN + NaN", "NaN - NaN", "NaN * NaN", @@ -22,6 +20,8 @@ test.each([ util.testExpression(code).expectToMatchJsResult(); }); +// Current implementation does not allow this +// eslint-disable-next-line jest/no-disabled-tests test.skip.each(["NaN", "Infinity"])("%s reassignment", name => { util.testFunction` const ${name} = 1; @@ -46,6 +46,10 @@ describe("Number", () => { test.each(cases)("isFinite(%p)", value => { util.testExpressionTemplate`Number.isFinite(${value} as any)`.expectToMatchJsResult(); }); + + test.each(cases)("isInteger(%p)", value => { + util.testExpressionTemplate`Number.isInteger(${value} as any)`.expectToMatchJsResult(); + }); }); const toStringRadixes = [undefined, 10, 2, 8, 9, 16, 17, 36, 36.9]; @@ -69,6 +73,26 @@ test.each([ util.testExpressionTemplate`(${value}).toString(2)`.expectToEqual(luaNativeSpecialNumString); }); +const toFixedFractions = [undefined, 0, 1, 2, Math.PI, 5, 99]; +// 1.5, 1.25 and 1.125 fails as rounding differ +const toFixedValues = [-1, 0, 1, Math.PI, -1.1234, -9.99e19, 1e22]; +const toFixedPairs = toFixedValues.flatMap(value => toFixedFractions.map(frac => [value, frac] as const)); +test.each(toFixedPairs)("(%p).toFixed(%p)", (value, frac) => { + util.testExpressionTemplate`(${value}).toFixed(${frac})`.expectToMatchJsResult(); +}); + +test.each([ + [NaN, "(0/0)"], + [Infinity, "(1/0)"], + [-Infinity, "(-(1/0))"], +])("%p.toFixed(2)", (value, luaNativeSpecialNum) => { + // Need to get the actual lua tostring version of inf/nan + // this is platform dependent so we can/should not hardcode it + const luaNativeSpecialNumString = util.testExpression`${luaNativeSpecialNum}.toString()`.getLuaExecutionResult(); + // Cannot use expectToMatchJsResult because this actually wont be the same in JS in Lua + util.testExpressionTemplate`(${value}).toFixed(2)`.expectToEqual(luaNativeSpecialNumString); +}); + test.each(cases)("isNaN(%p)", value => { util.testExpressionTemplate`isNaN(${value} as any)`.expectToMatchJsResult(); }); @@ -88,29 +112,32 @@ test("numbers overflowing the float limit become math.huge", () => { util.testExpression`1e309`.expectToMatchJsResult(); }); -describe.each(["parseInt", "parseFloat"])("parse numbers with %s", parseFunction => { - const numberStrings = ["3", "3.0", "9", "42", "239810241", "-20391", "3.1415", "2.7182", "-34910.3"]; +describe.each(["parseInt", "parseFloat", "Number.parseInt", "Number.parseFloat"])( + "parse numbers with %s", + parseFunction => { + const numberStrings = ["3", "3.0", "9", "42", "239810241", "-20391", "3.1415", "2.7182", "-34910.3"]; - test.each(numberStrings)("parses (%s)", numberString => { - util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); - }); + test.each(numberStrings)("parses (%s)", numberString => { + util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); + }); - test("empty string", () => { - util.testExpression`${parseFunction}("")`.expectToMatchJsResult(); - }); + test("empty string", () => { + util.testExpression`${parseFunction}("")`.expectToMatchJsResult(); + }); - test("invalid string", () => { - util.testExpression`${parseFunction}("bla")`.expectToMatchJsResult(); - }); + test("invalid string", () => { + util.testExpression`${parseFunction}("bla")`.expectToMatchJsResult(); + }); - test.each(["1px", "2300m", "3,4", "452adkfl"])("trailing text (%s)", numberString => { - util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); - }); + test.each(["1px", "2300m", "3,4", "452adkfl"])("trailing text (%s)", numberString => { + util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); + }); - test.each([" 3", " 4", " -231", " 1px"])("leading whitespace (%s)", numberString => { - util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); - }); -}); + test.each([" 3", " 4", " -231", " 1px"])("leading whitespace (%s)", numberString => { + util.testExpression`${parseFunction}("${numberString}")`.expectToMatchJsResult(); + }); + } +); test.each(["Infinity", "-Infinity", " -Infinity"])("parseFloat handles Infinity", numberString => { util.testExpression`parseFloat("${numberString}")`.expectToMatchJsResult(); @@ -141,3 +168,80 @@ test.each([ ])("parseInt with base and trailing text (%p)", ({ numberString, base }) => { util.testExpression`parseInt("${numberString}", ${base})`.expectToMatchJsResult(); }); + +test.each(["Infinity", "-Infinity", " -Infinity"])("Number.parseFloat handles Infinity", numberString => { + util.testExpression`Number.parseFloat("${numberString}")`.expectToMatchJsResult(); +}); + +test.each([ + { numberString: "36", base: 8 }, + { numberString: "-36", base: 8 }, + { numberString: "100010101101", base: 2 }, + { numberString: "-100010101101", base: 2 }, + { numberString: "3F", base: 16 }, +])("Number.parseInt with base (%p)", ({ numberString, base }) => { + util.testExpression`Number.parseInt("${numberString}", ${base})`.expectToMatchJsResult(); +}); + +test.each(["0x4A", "-0x42", "0X42", " 0x391", " -0x8F"])("Number.parseInt detects hexadecimal", numberString => { + util.testExpression`Number.parseInt("${numberString}")`.expectToMatchJsResult(); +}); + +test.each([1, 37, -100])("Number.parseInt with invalid base (%p)", base => { + util.testExpression`Number.parseInt("11111", ${base})`.expectToMatchJsResult(); +}); + +test.each([ + { numberString: "36px", base: 8 }, + { numberString: "10001010110231", base: 2 }, + { numberString: "3Fcolor", base: 16 }, +])("Number.parseInt with base and trailing text (%p)", ({ numberString, base }) => { + util.testExpression`Number.parseInt("${numberString}", ${base})`.expectToMatchJsResult(); +}); + +// Issue #1218: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1218 +test.each(["42", "undefined"])("prototype call on nullable number (%p)", value => { + util.testFunction` + function toString(n?: number) { + return n?.toString(); + } + return toString(${value}); + ` + .setOptions({ strictNullChecks: true }) + .expectToMatchJsResult(); +}); + +test.each([ + // Full ordering: NEG_INF < MIN_SAFE < 0 < MIN_VALUE < EPSILON < MAX_SAFE < MAX_VALUE < POS_INF + "Number.NEGATIVE_INFINITY < Number.MIN_SAFE_INTEGER", + "Number.MIN_SAFE_INTEGER < 0", + "0 < Number.MIN_VALUE", + "Number.MIN_VALUE < Number.EPSILON", + "Number.EPSILON < Number.MAX_SAFE_INTEGER", + "Number.MAX_SAFE_INTEGER < Number.MAX_VALUE", + "Number.MAX_VALUE < Number.POSITIVE_INFINITY", + + // Verify specific values + "Number.MIN_VALUE > 0", + "Number.MIN_SAFE_INTEGER === -(2**53 - 1)", + "Number.MAX_SAFE_INTEGER === 2**53 - 1", + "Number.MAX_SAFE_INTEGER + 1 !== Number.MAX_SAFE_INTEGER", + "Number.MIN_SAFE_INTEGER - 1 !== Number.MIN_SAFE_INTEGER", +])("Number constants have correct relative sizes (%p)", comparison => { + util.testExpression(comparison).expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1629 +test("unary + casting to number (#1629)", () => { + util.testFunction` + let abc = "123"; + return [+abc, +"456"]; + `.expectToEqual([123, 456]); +}); + +test("unary - casting to number", () => { + util.testFunction` + let abc = "123"; + return [-abc, -"456"]; + `.expectToEqual([-123, -456]); +}); diff --git a/test/unit/builtins/object.spec.ts b/test/unit/builtins/object.spec.ts index fb0fe26ba..411da903b 100644 --- a/test/unit/builtins/object.spec.ts +++ b/test/unit/builtins/object.spec.ts @@ -10,6 +10,16 @@ test.each([ util.testExpression`Object.assign(${util.formatCode(initial)}, ${argsString})`.expectToMatchJsResult(); }); +test.each([ + "Object.assign({}, false)", + "Object.assign({}, null)", + "Object.assign({}, undefined)", + "Object.assign({}, null, undefined)", + "Object.assign({ a: 1 }, false, { b: 2 })", +])("Object.assign skips non-object sources (%p)", expression => { + util.testExpression(expression).expectToMatchJsResult(); +}); + test.each([{}, { abc: 3 }, { abc: 3, def: "xyz" }])("Object.entries (%p)", obj => { const testBuilder = util.testExpressionTemplate`Object.entries(${obj})`; // Need custom matcher because order is not guaranteed in neither JS nor Lua @@ -147,7 +157,7 @@ describe("Object.defineProperty", () => { test.each(trueFalseTests)("configurable (%p)", value => { util.testFunction` - const foo = { bar: true }; + const foo: { bar?: boolean } = { bar: true }; Object.defineProperty(foo, "bar", { configurable: ${value} }); try { delete foo.bar } catch {}; return foo.bar; @@ -196,6 +206,81 @@ describe("Object.defineProperty", () => { return { prop: foo.bar, err }; `.expectToMatchJsResult(); }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1625 + test("instance isolation", () => { + util.testFunction` + class Test { + declare obj: object; + constructor() { + Object.defineProperty(this, "obj", { value: {}, writable: true, configurable: true }); + } + } + const t1 = new Test(); + const t2 = new Test(); + return t1.obj === t2.obj; + `.expectToMatchJsResult(); + }); + + test("instance isolation with three instances", () => { + util.testFunction` + class Test { + declare obj: object; + constructor() { + Object.defineProperty(this, "obj", { value: {}, writable: true, configurable: true }); + } + } + const t1 = new Test(); + const t2 = new Test(); + const t3 = new Test(); + return [t1.obj === t2.obj, t1.obj === t3.obj, t2.obj === t3.obj]; + `.expectToMatchJsResult(); + }); + + test("instance isolation with mutation", () => { + util.testFunction` + class Test { + declare value: number; + constructor(v: number) { + Object.defineProperty(this, "value", { value: v, writable: true, configurable: true }); + } + } + const t1 = new Test(1); + const t2 = new Test(2); + return [t1.value, t2.value]; + `.expectToMatchJsResult(); + }); + + test("instance isolation with multiple properties", () => { + util.testFunction` + class Test { + declare a: string; + declare b: string; + constructor(a: string, b: string) { + Object.defineProperty(this, "a", { value: a, writable: true, configurable: true }); + Object.defineProperty(this, "b", { value: b, writable: true, configurable: true }); + } + } + const t1 = new Test("x", "y"); + const t2 = new Test("p", "q"); + return [t1.a, t1.b, t2.a, t2.b]; + `.expectToMatchJsResult(); + }); + + test("instance isolation preserves prototype methods", () => { + util.testFunction` + class Test { + declare val: number; + constructor(v: number) { + Object.defineProperty(this, "val", { value: v, writable: true, configurable: true }); + } + getVal() { return this.val; } + } + const t1 = new Test(10); + const t2 = new Test(20); + return [t1.getVal(), t2.getVal()]; + `.expectToMatchJsResult(); + }); }); describe("Object.getOwnPropertyDescriptor", () => { @@ -221,23 +306,84 @@ describe("Object.getOwnPropertyDescriptors", () => { describe("delete from object", () => { test("delete from object", () => { util.testFunction` - const obj = { foo: "bar", bar: "baz" }; - delete obj["foo"]; - return obj; - ` - .setTsHeader("declare function setmetatable(this: void, table: T, metatable: any): T;") - .expectToEqual({ bar: "baz" }); + const obj: { foo?: string, bar: string } = { foo: "bar", bar: "baz" }; + return [delete obj["foo"], obj]; + `.expectToMatchJsResult(); + }); + + test("delete nonexistent property", () => { + util.testFunction` + const obj = {} as any + return [delete obj["foo"], obj]; + `.expectToMatchJsResult(); }); // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/993 test("delete from object with metatable", () => { util.testFunction` - const obj = { foo: "bar", bar: "baz" }; + const obj: { foo?: string, bar: string } = { foo: "bar", bar: "baz" }; setmetatable(obj, {}); - delete obj["foo"]; - return obj; + return [delete obj["foo"], obj]; ` .setTsHeader("declare function setmetatable(this: void, table: T, metatable: any): T;") - .expectToEqual({ bar: "baz" }); + .expectToEqual([true, { bar: "baz" }]); + }); + + test("delete nonconfigurable own property", () => { + util.testFunction` + const obj = {} as any + Object.defineProperty(obj, "foo", { + configurable: false, + value: true + }) + try { + delete obj["foo"] + return "deleted" + } catch (e) { + return e instanceof TypeError + } + ` + .setOptions({ + strict: true, + }) + .expectToMatchJsResult(); + }); +}); + +describe("Object.groupBy", () => { + test("empty", () => { + util.testFunction` + const array: number[] = []; + + return Object.groupBy(array, (num, index) => { + return num % 2 === 0 ? "even": "odd"; + }); + `.expectToEqual([]); + }); + + test("groupBy", () => { + util.testFunction` + const array = [0, 1, 2, 3, 4, 5]; + + return Object.groupBy(array, (num, index) => { + return num % 2 === 0 ? "even": "odd"; + }); + `.expectToEqual({ + even: [0, 2, 4], + odd: [1, 3, 5], + }); + }); + + test("groupBy index", () => { + util.testFunction` + const array = [0, 1, 2, 3, 4, 5]; + + return Object.groupBy(array, (num, index) => { + return index < 3 ? "low": "high"; + }); + `.expectToEqual({ + low: [0, 1, 2], + high: [3, 4, 5], + }); }); }); diff --git a/test/unit/builtins/promise.spec.ts b/test/unit/builtins/promise.spec.ts new file mode 100644 index 000000000..63272c8ab --- /dev/null +++ b/test/unit/builtins/promise.spec.ts @@ -0,0 +1,1413 @@ +import * as util from "../../util"; + +const promiseTestLib = ` +// Some logging utility, useful for asserting orders of operations + +const allLogs: any[] = []; +function log(...values: any[]) { + allLogs.push(...values); +} + +// Create a promise and store its resolve and reject functions, useful for creating pending promises + +function defer() { + let resolve: (data: any) => void = () => {}; + let reject: (reason: string) => void = () => {}; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; +}`; + +test("can create resolved promise", () => { + util.testFunction` + const { state, value } = Promise.resolve(42) as any; + return { state, value }; + `.expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: 42, + }); +}); + +test("can create rejected promise", () => { + util.testFunction` + const { state, rejectionReason } = Promise.reject("test rejection") as any; + return { state, rejectionReason }; + `.expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "test rejection", + }); +}); + +test("promise constructor executor throwing rejects promise", () => { + util.testFunction` + const { state, rejectionReason } = new Promise(() => { throw "executor exception"; }) as any; + return { state, rejectionReason }; + `.expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "executor exception", + }); +}); + +test("promise can be resolved", () => { + util.testFunction` + const { promise, resolve } = defer(); + + let result: string | undefined; + let rejectResult: string | undefined; + + promise.then( + data => { result = data; }, + reason => { rejectResult = reason; } + ); + + const beforeResolve = result; + + resolve("Hello!"); + + const afterResolve = result; + + return { beforeResolve, afterResolve, rejectResult }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + beforeResolve: undefined, + afterResolve: "Hello!", + rejectResult: undefined, + }); +}); + +test("promise can be rejected", () => { + util.testFunction` + const { promise, reject } = defer(); + + let resolveResult: string | undefined; + let rejectResult: string | undefined; + + promise.then( + data => { resolveResult = data; }, + reason => { rejectResult = reason; } + ); + + const beforeReject = rejectResult; + + reject("Hello!"); + + const afterReject = rejectResult; + + return { beforeReject, afterReject, resolveResult }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + beforeReject: undefined, + afterReject: "Hello!", + resolveResult: undefined, + }); +}); + +test("promise cannot be resolved more than once", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise.then( + data => { log(data); } + ); + + resolve("Hello!"); + resolve("World!"); // Second resolve should be ignored + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["Hello!"]); +}); + +test("promise cannot be rejected more than once", () => { + util.testFunction` + const { promise, reject } = defer(); + + promise.then( + _ => {}, + reason => { log(reason); } + ); + + reject("Hello!"); + reject("World!"); // Second reject should be ignored + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["Hello!"]); +}); + +test("promise cannot be rejected after resolving", () => { + util.testFunction` + const { promise, resolve, reject } = defer(); + + promise.then( + data => { log(data); }, + reason => { log(reason); } + ); + + resolve("Hello!"); + reject("World!"); // should be ignored because already resolved + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["Hello!"]); +}); + +test("promise cannot be resolved after rejecting", () => { + util.testFunction` + const { promise, resolve, reject } = defer(); + + promise.then( + data => { log(data); }, + reason => { log(reason); } + ); + + reject("Hello!"); + resolve("World!"); // should be ignored because already rejected + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["Hello!"]); +}); + +test("promise can be (then-resolve) observed more than once", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise.then( + data => { log("then 1: " + data); } + ); + + promise.then( + data => { log("then 2: " + data); } + ); + + resolve("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["then 1: Hello!", "then 2: Hello!"]); +}); + +test("promise can be (then-reject) observed more than once", () => { + util.testFunction` + const { promise, reject } = defer(); + + promise.then( + undefined, + reason => { log("then 1: " + reason); } + ); + + promise.then( + undefined, + reason => { log("then 2: " + reason); }, + ); + + reject("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["then 1: Hello!", "then 2: Hello!"]); +}); + +test("promise can be (catch) observed more than once", () => { + util.testFunction` + const { promise, reject } = defer(); + + promise.catch( + reason => { log("catch 1: " + reason); } + ); + + promise.catch( + reason => { log("catch 2: " + reason); }, + ); + + reject("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["catch 1: Hello!", "catch 2: Hello!"]); +}); + +test("promise chained resolve resolves all", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + promise3.then(data => { + log("promise3: " + data); + resolve2(data); + }); + promise2.then(data => { + log("promise2: " + data); + resolve1(data); + }); + promise1.then(data => { + log("promise1: " + data); + }); + + resolve3("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise3: Hello!", "promise2: Hello!", "promise1: Hello!"]); +}); + +test("promise then returns a literal", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const promise2 = promise.then(data => { + log("promise resolved with: " + data); + return "promise 1 resolved: " + data; + }); + + promise2.then(data => { + log("promise2 resolved with: " + data); + }); + + resolve("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise resolved with: Hello!", "promise2 resolved with: promise 1 resolved: Hello!"]); +}); + +test("promise then returns a resolved promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const promise2 = promise.then(data => { + log("promise resolved with: " + data); + return Promise.resolve("promise 1 resolved: " + data); + }); + + promise2.then(data => { + log("promise2 resolved with: " + data); + }); + + resolve("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise resolved with: Hello!", "promise2 resolved with: promise 1 resolved: Hello!"]); +}); + +test("promise then returns a rejected promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const promise2 = promise.then(data => { + log("promise resolved with: " + data); + return Promise.reject("promise 1: reject!"); + }); + + promise2.catch(reason => { + log("promise2 rejected with: " + reason); + }); + + resolve("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise resolved with: Hello!", "promise2 rejected with: promise 1: reject!"]); +}); + +test("promise then returns a pending promise (resolves)", () => { + util.testFunction` + const { promise, resolve } = defer(); + + let resolve2: any; + + const promise2 = promise.then(data => { + log("promise resolved with: " + data); + + const promise3 = new Promise((res) => { + resolve2 = res; + }); + + promise3.then(data2 => { + log("promise3 resolved with: " + data2); + }); + + return promise3; + }); + + promise2.then(data => { + log("promise2 resolved with: " + data); + }); + + // Resolve promise 1 + resolve("Hello!"); + + // Resolve promise 2 and 3 + resolve2("World!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "promise resolved with: Hello!", + "promise3 resolved with: World!", + "promise2 resolved with: World!", + ]); +}); + +test("promise then returns a pending promise (rejects)", () => { + util.testFunction` + const { promise, resolve } = defer(); + + let reject: any; + + const promise2 = promise.then(data => { + log("promise resolved with: " + data); + + const promise3 = new Promise((_, rej) => { + reject = rej; + }); + + promise3.catch(reason => { + log("promise3 rejected with: " + reason); + }); + + return promise3; + }); + + promise2.catch(reason => { + log("promise2 rejected with: " + reason); + }); + + // Resolve promise 1 + resolve("Hello!"); + + // Reject promise 2 and 3 + reject("World!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "promise resolved with: Hello!", + "promise3 rejected with: World!", + "promise2 rejected with: World!", + ]); +}); + +test("promise then onFulfilled throws", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const promise2 = promise.then(data => { + throw "fulfill exception!" + }); + + promise2.catch(reason => { + log("promise2 rejected with: " + reason); + }); + + resolve("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise2 rejected with: fulfill exception!"]); +}); + +test("promise then onRejected throws", () => { + util.testFunction` + const { promise, reject } = defer(); + + const promise2 = promise.then( + _ => {}, + reason => { throw "fulfill exception from onReject!" } + ); + + promise2.catch(reason => { + log("promise2 rejected with: " + reason); + }); + + reject("Hello!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise2 rejected with: fulfill exception from onReject!"]); +}); + +test("then on resolved promise immediately calls callback", () => { + util.testFunction` + Promise.resolve(42).then(data => { log(data); }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([42]); +}); + +test("then on rejected promise immediately calls callback", () => { + util.testFunction` + Promise.reject("already rejected").then(data => { log("resolved", data); }, reason => { log("rejected", reason); }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["rejected", "already rejected"]); +}); + +test("second then throws", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise.then(data => { + // nothing + log("then1", data) + }); + + promise.then(data => { + log("then2", data) + throw "test throw"; + }).catch(err => { + // caught + log("rejected: ", err) + }); + + resolve("mydata"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["then1", "mydata", "then2", "mydata", "rejected: ", "test throw"]); +}); + +test("chained then throws", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise.then(data => { + // nothing + log("then1", data) + }).then(data => { + log("then2", data) + throw "test throw"; + }).catch(err => { + // caught + log("rejected: ", err) + }); + + resolve("mydata"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "then1", + "mydata", + "then2", // Does not have data because first then returned undefined + "rejected: ", + "test throw", + ]); +}); + +test("empty then resolves", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise.then().then(v => { log("then2", v) }); + + resolve("mydata"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["then2", "mydata"]); +}); + +test("empty then rejects", () => { + util.testFunction` + const { promise, reject } = defer(); + + promise.then().catch(err => { log("catch", err) }); + + reject("my error"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["catch", "my error"]); +}); + +test("catch on rejected promise immediately calls callback", () => { + util.testFunction` + Promise.reject("already rejected").catch(reason => { log(reason); }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["already rejected"]); +}); + +test("finally on resolved promise immediately calls callback", () => { + util.testFunction` + Promise.resolve(42).finally(() => { log("finally"); }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["finally"]); +}); + +test("finally on rejected promise immediately calls callback", () => { + util.testFunction` + Promise.reject("already rejected").finally(() => { log("finally"); }); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["finally"]); +}); + +test("direct chaining", () => { + util.testFunction` + const { promise, resolve } = defer(); + + promise + .then(data => { + log("resolving then1", data); + return "then 1 data"; + }).then(data => { + log("resolving then2", data); + throw "test throw"; + }).catch(reason => { + log("handling catch", reason); + }); + + resolve("test data"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + "resolving then1", + "test data", + "resolving then2", + "then 1 data", + "handling catch", + "test throw", + ]); +}); + +describe("finally behaves same as then/catch", () => { + const thenCatchPromise = ` + const { promise, resolve, reject } = defer(); + promise + .then(data => { + log("do something", data); + log("final code"); + }) + .catch(reason => { + log("handling error", reason); + log("final code"); + }); + `; + + const finallyPromise = ` + const { promise, resolve, reject } = defer(); + promise + .then(data => { + log("do something", data); + }) + .catch(reason => { + log("handling error", reason); + }) + .finally(() => { + log("final code"); + }); + `; + + test("when resolving", () => { + const thenResult = util.testFunction` + ${thenCatchPromise} + resolve("test data"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .getLuaExecutionResult(); + + const finallyResult = util.testFunction` + ${finallyPromise} + resolve("test data"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .getLuaExecutionResult(); + + expect(finallyResult).toEqual(thenResult); + }); + + test("when rejecting", () => { + const thenResult = util.testFunction` + ${thenCatchPromise} + reject("test rejection reason"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .getLuaExecutionResult(); + + const finallyResult = util.testFunction` + ${finallyPromise} + reject("test rejection reason"); + return allLogs; + ` + .setTsHeader(promiseTestLib) + .getLuaExecutionResult(); + + expect(finallyResult).toEqual(thenResult); + }); +}); + +test("example: asynchronous web request", () => { + const testHarness = ` + interface UserData { name: string, age: number} + const requests = new Map void>(); + function getUserData(id: number, callback: (userData: UserData) => void) { + requests.set(id, callback); + } + function emulateRequestReturn(id: number, data: UserData) { + requests.get(id)!(data); + } + `; + + util.testFunction` + // Wrap function getUserData(id: number, callback: (userData: UserData) => void) into a Promise + function getUserDataAsync(id: number): Promise { + return new Promise(resolve => { + getUserData(id, resolve); + }); + } + + const user1DataPromise = getUserDataAsync(1); + const user2DataPromise = getUserDataAsync(2); + + user1DataPromise.then(() => log("received data for user 1")); + user2DataPromise.then(() => log("received data for user 2")); + + const allDataPromise = Promise.all([user1DataPromise, user2DataPromise]); + + allDataPromise.then(([user1data, user2data]) => { + log("all requests completed", user1data, user2data); + }); + + emulateRequestReturn(2, { name: "bar", age: 42 }); + emulateRequestReturn(1, { name: "foo", age: 35 }); + + return allLogs; + ` + .setTsHeader(testHarness + promiseTestLib) + .expectToEqual([ + "received data for user 2", + "received data for user 1", + "all requests completed", + { + name: "foo", + age: 35, + }, + { + name: "bar", + age: 42, + }, + ]); +}); + +test("promise is instanceof promise", () => { + util.testExpression`Promise.resolve(4) instanceof Promise`.expectToMatchJsResult(); +}); + +test("chained then on resolved promise", () => { + util.testFunction` + Promise.resolve("result1").then(undefined, () => {}).then(value => log(value)); + Promise.resolve("result2").then(value => "then1", () => {}).then(value => log(value)); + Promise.resolve("result3").then(value => undefined, () => {}).then(value => log(value ?? "undefined")); + Promise.resolve("result4").then(value => "then2").then(value => [value, "then3"]).then(([v1, v2]) => log(v1, v2)); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["result1", "then1", "undefined", "then2", "then3"]); +}); + +test("chained catch on rejected promise", () => { + util.testFunction` + Promise.reject("reason1").then(() => {}).then(v => log("resolved", v), reason => log("rejected", reason)); + Promise.reject("reason2").then(() => {}, () => "reason3").then(v => log("resolved", v)); + Promise.reject("reason4").then(() => {}, () => undefined).then(v => log("resolved", v ?? "undefined")); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["rejected", "reason1", "resolved", "reason3", "resolved", "undefined"]); +}); + +// Issue 2 from https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1105 +test("catch after then catches rejected promise", () => { + util.testFunction` + Promise.reject('test error') + .then(result => { + log("then", result); + }) + .catch(e => { + log("catch", e); + }) + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["catch", "test error"]); +}); + +test("promise unwraps resolved promise result", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(v => log(v)); + + resolve(Promise.resolve("result")); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["result"]); +}); + +test("resolving promise with rejected promise rejects the promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.catch(err => log(err)); + + resolve(Promise.reject("reject")); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["reject"]); +}); + +test("resolving promise with pending promise will keep pending until promise2 resolved", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.then(v => log("promise 1", v)); + + const { promise: promise2, resolve: resolve2 } = defer(); + promise2.then(v => log("promise 2", v)); + + resolve(promise2); + resolve2("result"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2", "result", "promise 1", "result"]); +}); + +test("resolving promise with pending promise will keep pending until promise2 rejects", () => { + util.testFunction` + const { promise, resolve } = defer(); + promise.catch(v => log("promise 1", v)); + + const { promise: promise2, reject: reject2 } = defer(); + promise2.catch(v => log("promise 2", v)); + + resolve(promise2); + reject2("rejection"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2", "rejection", "promise 1", "rejection"]); +}); + +describe("Promise.resolve", () => { + test("returns the given resolved promise", () => { + util.testFunction` + let result = 0; + Promise.resolve(Promise.resolve(4)) + .then((value) => result = value); + return result; + `.expectToEqual(4); + }); + + test("returns the given rejected promise", () => { + util.testFunction` + let result = 0; + Promise.resolve(Promise.reject(4)) + .catch((value) => result = value); + return result; + `.expectToEqual(4); + }); +}); + +describe("Promise.all", () => { + test("resolves once all arguments are resolved", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.all([promise1, promise2, promise3]); + promise.then(([result1, result2, result3]) => { + log(result1, result2, result3); + }); + + resolve1("promise 1 result!"); + resolve2("promise 2 result!"); + resolve3("promise 3 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 1 result!", "promise 2 result!", "promise 3 result!"]); + }); + + test("rejects on first rejection", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, reject: reject2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.all([promise1, promise2, promise3]); + promise.then( + ([result1, result2, result3]) => { + log(result1, result2, result3); + }, + reason => { + log(reason); + } + ); + + resolve1("promise 1 result!"); + reject2("promise 2 rejects!"); + resolve3("promise 3 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2 rejects!"]); + }); + + test("handles already-resolved promises", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + + const promise = Promise.all([promise1, Promise.resolve("already resolved!")]); + promise.then(([result1, result2]) => { + log(result1, result2); + }); + + resolve1("promise 1 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 1 result!", "already resolved!"]); + }); + + test("handles non-promise data", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + + const promise = Promise.all([42, promise1, "foo"]); + promise.then(([result1, result2, result3]) => { + log(result1, result2, result3); + }); + + resolve1("promise 1 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([42, "promise 1 result!", "foo"]); + }); + + test("returns already-resolved promise if no pending promises in arguments", () => { + util.testFunction` + const { state, value } = Promise.all([42, Promise.resolve("already resolved!"), "foo"]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: [42, "already resolved!", "foo"], + }); + }); + + test("returns already-rejected promise if already rejected promise in arguments", () => { + util.testFunction` + const { state, rejectionReason } = Promise.all([42, Promise.reject("already rejected!")]) as any; + return { state, rejectionReason }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "already rejected!", + }); + }); +}); + +describe("Promise.allSettled", () => { + test("resolves once all arguments are resolved", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.allSettled([promise1, promise2, promise3]); + promise.then(([result1, result2, result3]) => { + log(result1, result2, result3); + }); + + resolve3("promise 3 result!"); + resolve1("promise 1 result!"); + resolve2("promise 2 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "fulfilled", value: "promise 1 result!" }, + { status: "fulfilled", value: "promise 2 result!" }, + { status: "fulfilled", value: "promise 3 result!" }, + ]); + }); + + test("resolves once all arguments are rejected", () => { + util.testFunction` + const { promise: promise1, reject: reject1 } = defer(); + const { promise: promise2, reject: reject2 } = defer(); + const { promise: promise3, reject: reject3 } = defer(); + + const promise = Promise.allSettled([promise1, promise2, promise3]); + promise.then(([result1, result2, result3]) => { + log(result1, result2, result3); + }); + + reject2("promise 2 rejected!"); + reject1("promise 1 rejected!"); + reject3("promise 3 rejected!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "rejected", reason: "promise 1 rejected!" }, + { status: "rejected", reason: "promise 2 rejected!" }, + { status: "rejected", reason: "promise 3 rejected!" }, + ]); + }); + + test("resolves once all arguments are rejected or resolved", () => { + util.testFunction` + const { promise: promise1, reject: reject1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, reject: reject3 } = defer(); + + const promise = Promise.allSettled([promise1, promise2, promise3]); + promise.then(([result1, result2, result3]) => { + log(result1, result2, result3); + }); + + resolve2("promise 2 resolved!"); + reject1("promise 1 rejected!"); + reject3("promise 3 rejected!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "rejected", reason: "promise 1 rejected!" }, + { status: "fulfilled", value: "promise 2 resolved!" }, + { status: "rejected", reason: "promise 3 rejected!" }, + ]); + }); + + test("handles already resolved promises", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const returnedPromise = Promise.allSettled([Promise.resolve("already resolved"), promise]); + returnedPromise.then(([result1, result2]) => { + log(result1, result2); + }); + + resolve("promise resolved!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "fulfilled", value: "already resolved" }, + { status: "fulfilled", value: "promise resolved!" }, + ]); + }); + + test("handles already rejected promises", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const returnedPromise = Promise.allSettled([Promise.reject("already rejected"), promise]); + returnedPromise.then(([result1, result2]) => { + log(result1, result2); + }); + + resolve("promise resolved!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "rejected", reason: "already rejected" }, + { status: "fulfilled", value: "promise resolved!" }, + ]); + }); + + test("handles literal arguments", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const returnedPromise = Promise.allSettled(["my literal", promise]); + returnedPromise.then(([result1, result2]) => { + log(result1, result2); + }); + + resolve("promise resolved!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { status: "fulfilled", value: "my literal" }, + { status: "fulfilled", value: "promise resolved!" }, + ]); + }); + + test("returns resolved promise for empty argument list", () => { + util.testFunction` + const { state, value } = Promise.allSettled([]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: [], + }); + }); +}); + +describe("Promise.any", () => { + test("resolves once first promise resolves", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.any([promise1, promise2, promise3]); + promise.then(data => { + log(data); + }); + + resolve2("promise 2 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2 result!"]); + }); + + test("rejects once all promises reject", () => { + util.testFunction` + const { promise: promise1, reject: reject1 } = defer(); + const { promise: promise2, reject: reject2 } = defer(); + const { promise: promise3, reject: reject3 } = defer(); + + const promise = Promise.any([promise1, promise2, promise3]); + promise.catch(reason => { + log(reason); + }); + + reject2("promise 2 rejected!"); + reject3("promise 3 rejected!"); + reject1("promise 1 rejected!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { + name: "AggregateError", + message: "All Promises rejected", + errors: ["promise 2 rejected!", "promise 3 rejected!", "promise 1 rejected!"], + }, + ]); + }); + + test("handles already rejected promises", () => { + util.testFunction` + const { promise: promise1, reject: reject1 } = defer(); + const { promise: promise2, reject: reject2 } = defer(); + + const promise = Promise.any([promise1, Promise.reject("already rejected!"), promise2]); + promise.catch(reason => { + log(reason); + }); + + reject2("promise 2 rejected!"); + reject1("promise 1 rejected!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual([ + { + name: "AggregateError", + message: "All Promises rejected", + errors: ["already rejected!", "promise 2 rejected!", "promise 1 rejected!"], + }, + ]); + }); + + test("rejects if iterable is empty", () => { + util.testFunction` + const { state, rejectionReason } = Promise.any([]) as any; + return { state, rejectionReason }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "No promises to resolve with .any()", + }); + }); + + test("immediately resolves with literal", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const { state, value } = Promise.any([promise, "my literal"]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "my literal", + }); + }); + + test("immediately resolves with resolved promise", () => { + util.testFunction` + const { promise, resolve } = defer(); + + const { state, value } = Promise.any([promise, Promise.resolve("my resolved promise")]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "my resolved promise", + }); + }); +}); + +describe("Promise.race", () => { + test("resolves once first promise resolves", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.race([promise1, promise2, promise3]); + promise.then(data => { + log(data); + }); + + resolve2("promise 2 result!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2 result!"]); + }); + + test("rejects once first promise rejects", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, reject: reject2 } = defer(); + const { promise: promise3, resolve: resolve3 } = defer(); + + const promise = Promise.race([promise1, promise2, promise3]); + promise.catch(reason => { + log(reason); + }); + + reject2("promise 2 rejected!"); + + return allLogs; + ` + .setTsHeader(promiseTestLib) + .expectToEqual(["promise 2 rejected!"]); + }); + + test("returns resolved promise if arguments contain resolved promise", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + + const { state, value } = Promise.race([promise1, Promise.resolve("already resolved!"), promise2]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "already resolved!", + }); + }); + + test("returns resolved promise if arguments contain literal", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + + const { state, value } = Promise.race([promise1, "my literal", promise2]) as any; + return { state, value }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 1, // __TS__PromiseState.Fulfilled + value: "my literal", + }); + }); + + test("returns rejected promise if arguments contain rejected promise", () => { + util.testFunction` + const { promise: promise1, resolve: resolve1 } = defer(); + const { promise: promise2, resolve: resolve2 } = defer(); + + const { state, rejectionReason } = Promise.race([promise1, Promise.reject("already rejected!"), promise2]) as any; + return { state, rejectionReason }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 2, // __TS__PromiseState.Rejected + rejectionReason: "already rejected!", + }); + }); + + test("returns forever pending promise if argument array is empty", () => { + util.testFunction` + const { state } = Promise.race([]) as any; + return { state }; + ` + .setTsHeader(promiseTestLib) + .expectToEqual({ + state: 0, // __TS__PromiseState.Pending + }); + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1660 +describe("Promise.finally", () => { + test("returns a different promise instance", () => { + util.testFunction` + const p1 = new Promise(() => {}); + const p2 = p1.finally(); + return p1 === p2; + `.expectToMatchJsResult(); + }); + + test("preserves fulfillment value", () => { + util.testFunction` + const result = Promise.resolve(42).finally(() => {}) as any; + return result.value; + `.expectToEqual(42); + }); + + test("preserves rejection reason", () => { + util.testFunction` + const result = Promise.reject("err").finally(() => {}) as any; + return result.rejectionReason; + `.expectToEqual("err"); + }); + + test("callback executes on fulfillment", () => { + util.testFunction` + let called = false; + Promise.resolve(1).finally(() => { called = true; }); + return called; + `.expectToEqual(true); + }); + + test("callback executes on rejection", () => { + util.testFunction` + let called = false; + Promise.reject("err").finally(() => { called = true; }); + return called; + `.expectToEqual(true); + }); + + test("finally with undefined callback", () => { + util.testFunction` + const result = Promise.resolve(99).finally(undefined) as any; + return result.value; + `.expectToEqual(99); + }); + + test("finally throw overrides fulfillment value", () => { + util.testModule` + let result: any; + Promise.resolve("ok") + .finally(() => { throw "finally-error"; }) + .then(v => { result = v; }, e => { result = e; }); + export const output = result; + `.expectToEqual({ output: "finally-error" }); + }); + + test("finally throw overrides rejection reason", () => { + util.testModule` + let result: any; + Promise.reject("original") + .finally(() => { throw "finally-error"; }) + .then(v => { result = v; }, e => { result = e; }); + export const output = result; + `.expectToEqual({ output: "finally-error" }); + }); + + test("finally returning rejected promise overrides fulfillment", () => { + util.testModule` + let result: any; + Promise.resolve("ok") + .finally(() => Promise.reject("finally-rejected") as any) + .then(v => { result = v; }, e => { result = e; }); + export const output = result; + `.expectToEqual({ output: "finally-rejected" }); + }); + + test("finally returning rejected promise overrides rejection", () => { + util.testModule` + let result: any; + Promise.reject("original") + .finally(() => Promise.reject("finally-rejected") as any) + .then(v => { result = v; }, e => { result = e; }); + export const output = result; + `.expectToEqual({ output: "finally-rejected" }); + }); +}); diff --git a/test/unit/builtins/set.spec.ts b/test/unit/builtins/set.spec.ts index 8f81edfe8..234be91a7 100644 --- a/test/unit/builtins/set.spec.ts +++ b/test/unit/builtins/set.spec.ts @@ -100,7 +100,7 @@ test("set has false", () => { test("set has null", () => { util.testFunction` - let myset = new Set(["a", "c"]); + let myset = new Set(["a", "c"]); return myset.has(null); `.expectToMatchJsResult(); }); @@ -194,3 +194,270 @@ describe.each(iterationMethods)("set.%s() preserves insertion order", iterationM `.expectToMatchJsResult(); }); }); + +describe.each(iterationMethods)("set.%s() handles mutation", iterationMethod => { + test("iterator persists after delete", () => { + util.testFunction` + const set1 = new Set(); + set1.add(42); + set1.add("forty two"); + + const iterator1 = set1.${iterationMethod}(); + set1.delete(42); + + return iterator1.next().value; + `.expectToMatchJsResult(); + }); + + test("iterator with delete and add between iterations", () => { + util.testFunction` + const set = new Set([1, 2, 3]); + const iter = set.${iterationMethod}(); + iter.next(); // 1 + set.delete(2); + set.add(4); + const results: IteratorResult[] = []; + let r = iter.next(); + while (!r.done) { results.push({ done: r.done, value: r.value }); r = iter.next(); } + return results; + `.expectToMatchJsResult(); + }); + + test("iterator does not restart after exhaustion", () => { + util.testFunction` + const set = new Set([1, 2]); + const iter = set.${iterationMethod}(); + const results: boolean[] = []; + results.push(iter.next().done!); + results.push(iter.next().done!); + results.push(iter.next().done!); // should be done + results.push(iter.next().done!); // should still be done, not restart + return results; + `.expectToMatchJsResult(); + }); +}); + +test("instanceof Set without creating set", () => { + util.testFunction` + const myset = 3 as any; + return myset instanceof Set; + `.expectToMatchJsResult(); +}); + +describe("new ECMAScript Set methods", () => { + test("union", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.union(set2); + return [...intersection]; + `.expectToEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); + }); + + test("union with empty sets", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([]); + + const intersection = set1.union(set2); + return [...intersection]; + `.expectToEqual([1, 2, 3, 4, 5, 6]); + + util.testFunction` + const set1 = new Set([]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.union(set2); + return [...intersection]; + `.expectToEqual([4, 5, 6, 7, 8, 9]); + }); + + test("intersection", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.intersection(set2); + return [...intersection]; + `.expectToEqual([4, 5, 6]); + }); + + test("intersection with empty sets", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([]); + + const intersection = set1.intersection(set2); + return [...intersection]; + `.expectToEqual([]); + + util.testFunction` + const set1 = new Set([]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.intersection(set2); + return [...intersection]; + `.expectToEqual([]); + }); + + test("difference", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.difference(set2); + return [...intersection]; + `.expectToEqual([1, 2, 3]); + }); + + test("symmetricDifference", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6]); + const set2 = new Set([4,5,6,7,8,9]); + + const intersection = set1.symmetricDifference(set2); + return [...intersection]; + `.expectToEqual([1, 2, 3, 7, 8, 9]); + }); + + test("isSubsetOf", () => { + util.testFunction` + const set1 = new Set([3,4,5,6]); + const set2 = new Set([1,2,3,4,5,6,7,8,9]); + + return { + set1SubsetOfSet2: set1.isSubsetOf(set2), + set2SubsetOfSet1: set2.isSubsetOf(set1), + }; + `.expectToEqual({ + set1SubsetOfSet2: true, + set2SubsetOfSet1: false, + }); + }); + + test("isSubsetOf equal", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6,7,8,9]); + const set2 = new Set([1,2,3,4,5,6,7,8,9]); + + return { + set1SubsetOfSet2: set1.isSubsetOf(set2), + set2SubsetOfSet1: set2.isSubsetOf(set1), + }; + `.expectToEqual({ + set1SubsetOfSet2: true, + set2SubsetOfSet1: true, + }); + }); + + test("isSubsetOf empty", () => { + util.testFunction` + const set1 = new Set([]); + const set2 = new Set([1,2,3]); + + return { + set1SubsetOfSet2: set1.isSubsetOf(set2), + set2SubsetOfSet1: set2.isSubsetOf(set1), + }; + `.expectToEqual({ + set1SubsetOfSet2: true, + set2SubsetOfSet1: false, + }); + }); + + test("isSupersetOf", () => { + util.testFunction` + const set1 = new Set([3,4,5,6]); + const set2 = new Set([1,2,3,4,5,6,7,8,9]); + + return { + set1SupersetOfSet2: set1.isSupersetOf(set2), + set2SupersetOfSet1: set2.isSupersetOf(set1), + }; + `.expectToEqual({ + set1SupersetOfSet2: false, + set2SupersetOfSet1: true, + }); + }); + + test("isSupersetOf equal", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6,7,8,9]); + const set2 = new Set([1,2,3,4,5,6,7,8,9]); + + return { + set1SupersetOfSet2: set1.isSupersetOf(set2), + set2SupersetOfSet1: set2.isSupersetOf(set1), + }; + `.expectToEqual({ + set1SupersetOfSet2: true, + set2SupersetOfSet1: true, + }); + }); + + test("isSupersetOf empty", () => { + util.testFunction` + const set1 = new Set([]); + const set2 = new Set([1,2,3]); + + return { + set1SupersetOfSet2: set1.isSupersetOf(set2), + set2SupersetOfSet1: set2.isSupersetOf(set1), + }; + `.expectToEqual({ + set1SupersetOfSet2: false, + set2SupersetOfSet1: true, + }); + }); + + test("isDisjointFrom", () => { + util.testFunction` + const set1 = new Set([3,4,5,6]); + const set2 = new Set([7,8,9]); + const set3 = new Set([1,2,3,4]); + + return { + set1DisjointFromSet2: set1.isDisjointFrom(set2), + set2DisjointFromSet1: set2.isDisjointFrom(set1), + set1DisjointFromSet3: set1.isDisjointFrom(set3), + set3DisjointFromSet1: set3.isDisjointFrom(set1), + }; + `.expectToEqual({ + set1DisjointFromSet2: true, + set2DisjointFromSet1: true, + set1DisjointFromSet3: false, + set3DisjointFromSet1: false, + }); + }); + + test("isDisjointFrom equal", () => { + util.testFunction` + const set1 = new Set([1,2,3,4,5,6,7,8,9]); + const set2 = new Set([1,2,3,4,5,6,7,8,9]); + + return { + set1DisjointFromSet2: set1.isDisjointFrom(set2), + set2DisjointFromSet1: set2.isDisjointFrom(set1), + }; + `.expectToEqual({ + set1DisjointFromSet2: false, + set2DisjointFromSet1: false, + }); + }); + + test("isDisjointFrom empty", () => { + util.testFunction` + const set1 = new Set([]); + const set2 = new Set([1,2,3]); + + return { + set1DisjointFromSet2: set1.isDisjointFrom(set2), + set2DisjointFromSet1: set2.isDisjointFrom(set1), + }; + `.expectToEqual({ + set1DisjointFromSet2: true, + set2DisjointFromSet1: true, + }); + }); +}); diff --git a/test/unit/builtins/string.spec.ts b/test/unit/builtins/string.spec.ts index c31ef012f..7f2ad312d 100644 --- a/test/unit/builtins/string.spec.ts +++ b/test/unit/builtins/string.spec.ts @@ -13,6 +13,10 @@ test("Supported lua string function", () => { util.testExpression`"test".upper()`.setTsHeader(tsHeader).expectToEqual("TEST"); }); +test("string.toString()", () => { + util.testExpression`"test".toString()`.expectToEqual("test"); +}); + test.each([[], [65], [65, 66], [65, 66, 67]])("String.fromCharCode (%p)", (...args) => { util.testExpression`String.fromCharCode(${util.formatCode(...args)})`.expectToMatchJsResult(); }); @@ -54,22 +58,43 @@ test("string index (side effect)", () => { `.expectToMatchJsResult(); }); -test.each([ - { inp: "hello test", searchValue: "", replaceValue: "" }, - { inp: "hello test", searchValue: " ", replaceValue: "" }, - { inp: "hello test", searchValue: "hello", replaceValue: "" }, - { inp: "hello test", searchValue: "test", replaceValue: "" }, - { inp: "hello test", searchValue: "test", replaceValue: "world" }, - { inp: "hello test", searchValue: "test", replaceValue: "%world" }, - { inp: "hello test", searchValue: "test", replaceValue: "." }, - { inp: "hello %test", searchValue: "test", replaceValue: "world" }, - { inp: "hello %test", searchValue: "%test", replaceValue: "world" }, - { inp: "hello test.", searchValue: ".", replaceValue: "$" }, - { inp: "hello test", searchValue: "test", replaceValue: () => "a" }, - { inp: "hello test", searchValue: "test", replaceValue: () => "%a" }, - { inp: "aaa", searchValue: "a", replaceValue: "b" }, -])("string.replace (%p)", ({ inp, searchValue, replaceValue }) => { - util.testExpression`"${inp}".replace(${util.formatCode(searchValue, replaceValue)})`.expectToMatchJsResult(); +describe.each(["replace", "replaceAll"])("string.%s", method => { + const testCases = [ + { inp: "hello test", searchValue: "", replaceValue: "" }, + { inp: "hello test", searchValue: "", replaceValue: "_" }, + { inp: "hello test", searchValue: " ", replaceValue: "" }, + { inp: "hello test", searchValue: "hello", replaceValue: "" }, + { inp: "hello test", searchValue: "test", replaceValue: "" }, + { inp: "hello test", searchValue: "test", replaceValue: "world" }, + { inp: "hello test", searchValue: "test", replaceValue: "%world" }, + { inp: "hello test", searchValue: "test", replaceValue: "." }, + { inp: "hello %test", searchValue: "test", replaceValue: "world" }, + { inp: "hello %test", searchValue: "%test", replaceValue: "world" }, + { inp: "hello test.", searchValue: ".", replaceValue: "$" }, + { inp: "aaa", searchValue: "a", replaceValue: "b" }, + ]; + + test.each(testCases)("string replacer %p", ({ inp, searchValue, replaceValue }) => { + util.testExpression`"${inp}${inp}".${method}(${util.formatCode( + searchValue, + replaceValue + )})`.expectToMatchJsResult(); + }); + + test.each(testCases)("function replacer %p", ({ inp, searchValue, replaceValue }) => { + util.testFunction` + const result = { + args: [] as string[], + string: "" + } + function replacer(...args: any[]): string { + result.args.push(...args) + return ${util.formatCode(replaceValue)} + } + result.string = "${inp}${inp}".${method}(${util.formatCode(searchValue)}, replacer) + return result + `.expectToMatchJsResult(); + }); }); test.each([ @@ -346,3 +371,55 @@ test("string intersected method", () => { return ({ abc: () => "a" } as Vector).abc(); `.expectToMatchJsResult(); }); + +test("tostring number with String constructor", () => { + util.testFunction` + const n = 123 + return "abc:" + String(n); + `.expectToEqual("abc:123"); +}); + +test("tostring table with String constructor", () => { + const result = util.testFunction` + const t = {} + return "abc:" + String(t); + `.getLuaExecutionResult(); + expect(result).toContain("abc:table: 0x"); +}); + +// Issue #1218: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1218 +test.each(['"foo"', "undefined"])("prototype call on nullable string (%p)", value => { + util.testFunction` + function toUpper(str?: string) { + return str?.toUpperCase(); + } + return toUpper(${value}); + ` + .setOptions({ strictNullChecks: true }) + .expectToMatchJsResult(); +}); + +// Issue #1218: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1218 +test.each(["string | undefined", "string | null", "null | string", "null | undefined | string"])( + "prototype call on nullable string type (%p)", + type => { + util.testFunction` + function toUpper(str: ${type}) { + return str?.toUpperCase(); + } + return toUpper("foo"); + ` + .setOptions({ strictNullChecks: true }) + .expectToMatchJsResult(); + } +); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1406 +test("string.indexOf without arguments (#1406)", () => { + util.testExpression`"".indexOf()`.expectNoTranspileException(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1406 +test("string.repeat without arguments (#1406)", () => { + util.testExpression`"".repeat()`.expectNoTranspileException(); +}); diff --git a/test/unit/builtins/weakMap.spec.ts b/test/unit/builtins/weakMap.spec.ts index 812e43622..8ff5d4c2e 100644 --- a/test/unit/builtins/weakMap.spec.ts +++ b/test/unit/builtins/weakMap.spec.ts @@ -74,7 +74,7 @@ test("weakMap has null", () => { util.testFunction` ${initRefsTs} let mymap = new WeakMap([[{}, true]]); - return mymap.has(null); + return mymap.has(null as any); `.expectToMatchJsResult(); }); diff --git a/test/unit/bundle.spec.ts b/test/unit/bundle.spec.ts index ddc678f34..b8179363a 100644 --- a/test/unit/bundle.spec.ts +++ b/test/unit/bundle.spec.ts @@ -109,6 +109,29 @@ test("cyclic imports", () => { .expectToEqual(new util.ExecutionError("stack overflow")); }); +test("does not evaluate files multiple times", () => { + util.testBundle` + import "./countingfile"; + import "./otherfile"; + + export const count = _count; + ` + .addExtraFile( + "otherfile.ts", + ` + import "./countingfile"; + ` + ) + .addExtraFile( + "countingfile.ts", + ` + declare var _count: number | undefined; + _count = (_count ?? 0) + 1; + ` + ) + .expectToEqual({ count: 1 }); +}); + test("no entry point", () => { util.testBundle`` .setOptions({ luaBundleEntry: undefined }) diff --git a/test/unit/classes/__snapshots__/classes.spec.ts.snap b/test/unit/classes/__snapshots__/classes.spec.ts.snap index a900582b5..9154d1911 100644 --- a/test/unit/classes/__snapshots__/classes.spec.ts.snap +++ b/test/unit/classes/__snapshots__/classes.spec.ts.snap @@ -1,10 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`missing declaration name: code 1`] = ` -"require(\\"lualib_bundle\\"); -____ = __TS__Class() -____.name = \\"\\" -function ____.prototype.____constructor(self) +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +____class_0 = __TS__Class() +____class_0.name = "" +function ____class_0.prototype.____constructor(self) end" `; diff --git a/test/unit/classes/__snapshots__/decorators.spec.ts.snap b/test/unit/classes/__snapshots__/decorators.spec.ts.snap index cbc983bd5..681e4fa3d 100644 --- a/test/unit/classes/__snapshots__/decorators.spec.ts.snap +++ b/test/unit/classes/__snapshots__/decorators.spec.ts.snap @@ -1,18 +1,62 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Throws error if decorator function has void context: code 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__Decorate = ____lualib.__TS__Decorate local ____exports = {} function ____exports.__main(self) - local function decorator(constructor) + local function decorator(constructor, context) end local TestClass = __TS__Class() - TestClass.name = \\"TestClass\\" + TestClass.name = "TestClass" function TestClass.prototype.____constructor(self) end - TestClass = __TS__Decorate({decorator}, TestClass) + TestClass = __TS__Decorate(TestClass, TestClass, {decorator}, {kind = "class", name = "TestClass"}) end return ____exports" `; exports[`Throws error if decorator function has void context: diagnostics 1`] = `"main.ts(4,9): error TSTL: Decorator function cannot have 'this: void'."`; + +exports[`class field decorator warns the return value is ignored: code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__Decorate = ____lualib.__TS__Decorate +local ____exports = {} +function ____exports.__main(self) + local fieldDecoratorContext + local function fieldDecorator(self, _, context) + fieldDecoratorContext = context + return function(____, initialValue) return initialValue * 12 end + end + local TestClass = __TS__Class() + TestClass.name = "TestClass" + function TestClass.prototype.____constructor(self) + self.value = 22 + end + __TS__Decorate(TestClass, nil, {fieldDecorator}, {kind = "field", name = "value", private = false, static = false}) +end +return ____exports" +`; + +exports[`class field decorator warns the return value is ignored: diagnostics 1`] = `"main.ts(11,13): warning TSTL: You are using a class field decorator, note that tstl ignores returned value initializers!"`; + +exports[`legacy experimentalDecorators Throws error if decorator function has void context: code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__DecorateLegacy = ____lualib.__TS__DecorateLegacy +local ____exports = {} +function ____exports.__main(self) + local function decorator(constructor) + end + local TestClass = __TS__Class() + TestClass.name = "TestClass" + function TestClass.prototype.____constructor(self) + end + TestClass = __TS__DecorateLegacy({decorator}, TestClass) +end +return ____exports" +`; + +exports[`legacy experimentalDecorators Throws error if decorator function has void context: diagnostics 1`] = `"main.ts(4,13): error TSTL: Decorator function cannot have 'this: void'."`; diff --git a/test/unit/classes/accessors.spec.ts b/test/unit/classes/accessors.spec.ts index 8a39fb21b..db17fe67d 100644 --- a/test/unit/classes/accessors.spec.ts +++ b/test/unit/classes/accessors.spec.ts @@ -11,6 +11,19 @@ test("get accessor", () => { `.expectToMatchJsResult(); }); +test("multiple get accessors", () => { + util.testFunction` + class Foo { + _foo = "foo"; + get foo() { return this._foo; } + _bar = "bar"; + get bar() { return this._bar; } + } + const f = new Foo(); + return f.foo + f.bar; + `.expectToMatchJsResult(); +}); + test("get accessor in base class", () => { util.testFunction` class Foo { @@ -142,6 +155,26 @@ test("get/set accessors", () => { `.expectToMatchJsResult(); }); +test("multiple get/set accessors", () => { + util.testFunction` + class Foo { + _foo = "foo"; + get foo() { return this._foo; } + set foo(val: string) { this._foo = val; } + + _bar = "bar"; + get bar() { return this._bar; } + set bar(val: string) { this._bar = val; } + } + const f = new Foo(); + const fooOriginal = f.foo; + f.foo = "fizz"; + const barOriginal = f.bar; + f.bar = "buzz"; + return [fooOriginal, f.foo, barOriginal, f.bar]; + `.expectToMatchJsResult(); +}); + test("get/set accessors in base class", () => { util.testFunction` class Foo { @@ -327,3 +360,44 @@ test("static get/set accessors in base class", () => { return fooOriginal + Bar.foo; `.expectToMatchJsResult(); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1437 +test("super class get accessor (#1437)", () => { + util.testFunction` + class A { + get foo() { + return "A"; + } + } + + class B extends A { + override get foo() { + return super.foo + "B"; + } + } + + return new B().foo; + `.expectToMatchJsResult(); +}); + +test("super class set accessor", () => { + util.testFunction` + let result = "unset"; + + class A { + set result(value: string) { + result = "foo" + value; + } + } + + class B extends A { + override set result(value: string) { + super.result = "bar" + value; + } + } + + new B().result = "baz"; + + return result; + `.expectToMatchJsResult(); +}); diff --git a/test/unit/classes/classes.spec.ts b/test/unit/classes/classes.spec.ts index f4c14df34..e7b8cc304 100644 --- a/test/unit/classes/classes.spec.ts +++ b/test/unit/classes/classes.spec.ts @@ -181,6 +181,27 @@ test("SubclassConstructor", () => { `.expectToMatchJsResult(); }); +test("SubclassConstructorPropertyInitiailizationSuperOrder", () => { + util.testFunction` + class a { + field: number; + constructor(field: number) { + this.field = field; + } + } + class b extends a { + fieldDouble = this.field * 2; + constructor(field: number) { + const newField = field + 1; + super(newField); + } + } + + const result = new b(10); + return [result.field, result.fieldDouble]; + `.expectToMatchJsResult(); +}); + test("Subclass constructor across merged namespace", () => { util.testModule` namespace NS { @@ -749,9 +770,9 @@ test("default exported anonymous class has 'default' name property", () => { }); // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/584 -test("constructor class name available with constructor", () => { +test("constructor class name available with decorator", () => { util.testModule` - const decorator = any>(constructor: T) => class extends constructor {}; + const decorator = any>(constructor: T, context: ClassDecoratorContext) => class extends constructor {}; @decorator class MyClass {} @@ -761,3 +782,142 @@ test("constructor class name available with constructor", () => { .setReturnExport("className") .expectToEqual("MyClass"); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/959 +test("methods accessed via this index pass correct context", () => { + util.testModule` + class Example { + baz = 3; + foo() { + this["bar"]() + } + + bar() { + return this.baz; + } + } + + const inst = new Example(); + export const result = inst.foo(); + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/959 +test.each(['(this["bar"])', '((((this["bar"]))))'])("methods in parentheses pass correct context %s", callPath => { + util.testModule` + class Example { + baz = 3; + foo() { + ${callPath}() + } + + bar() { + return this.baz; + } + } + + const inst = new Example(); + export const result = inst.foo(); + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1447 +test("static initialization block (#1447)", () => { + util.testModule` + class A { + private static staticProperty1 = 3; + public static staticProperty2; + static { + this.staticProperty2 = this.staticProperty1 + 5; + } + public static staticProperty3; + static { + this.staticProperty3 = this.staticProperty1 + this.staticProperty2; + } + } + export const result1 = A.staticProperty2; + export const result2 = A.staticProperty3; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1457 +test("static member definition order (#1457)", () => { + util.testFunction` + class A { + static a = A.foo() + + static foo(): number { + return 5 + } + } + + return A.a; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1504 +test("Calling static inherited functions works (#1504)", () => { + util.testFunction` + class A { + static Get() { + return "A"; + } + } + + class B extends A { + static Get() { + return super.Get() + "B"; + } + } + + return B.Get(); + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1537 +test("get inherted __index member from super (DotA 2 inheritance) (#1537)", () => { + util.testFunction` + // Inherit 'connected' class + class C extends Connected { + bar() { + return super.foo(); + } + } + + return new C().bar();` + .setTsHeader( + `interface I { + foo(): string; + } + + // Hacky interface/class merging + interface Connected extends I {} + class Connected {} + + declare function setmetatable(this: void, t: any, mt: any): void; + + const A = { + foo() { + return "foo"; + } + }; + + // Connect class 'Connected' to 'traditional' class A + setmetatable(Connected.prototype, { + __index: A + });` + ) + .expectToEqual("foo"); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1673 +test("vararg spread optimization in class constructor (#1673)", () => { + const lua = util.testModule` + class C { + constructor(...args: any[]) { + console.log(...args); + } + }`.getMainLuaCodeChunk(); + + expect(lua).not.toContain("table.unpack"); +}); diff --git a/test/unit/classes/decorators.spec.ts b/test/unit/classes/decorators.spec.ts index dadb73655..095bd8e3a 100644 --- a/test/unit/classes/decorators.spec.ts +++ b/test/unit/classes/decorators.spec.ts @@ -1,27 +1,37 @@ -import { decoratorInvalidContext } from "../../../src/transformation/utils/diagnostics"; +import { + decoratorInvalidContext, + incompleteFieldDecoratorWarning, +} from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("Class decorator with no parameters", () => { util.testFunction` - function setBool {}>(constructor: T) { + let classDecoratorContext; + + function classDecorator {}>(constructor: T, context: ClassDecoratorContext) { + classDecoratorContext = context; + return class extends constructor { decoratorBool = true; } } - @setBool + @classDecorator class TestClass { public decoratorBool = false; } - return new TestClass(); + return { decoratedClass: new TestClass(), context: { + kind: classDecoratorContext!.kind, + name: classDecoratorContext!.name, + } }; `.expectToMatchJsResult(); }); test("Class decorator with parameters", () => { util.testFunction` function setNum(numArg: number) { - return {}>(constructor: T) => { + return {}>(constructor: T, context: ClassDecoratorContext) => { return class extends constructor { decoratorNum = numArg; }; @@ -30,7 +40,7 @@ test("Class decorator with parameters", () => { @setNum(420) class TestClass { - public decoratorNum; + public decoratorNum?: number; } return new TestClass(); @@ -39,13 +49,13 @@ test("Class decorator with parameters", () => { test("Multiple class decorators", () => { util.testFunction` - function setTen {}>(constructor: T) { + function setTen {}>(constructor: T, context: ClassDecoratorContext) { return class extends constructor { decoratorTen = 10; } } - function setNum {}>(constructor: T) { + function setNum {}>(constructor: T, context: ClassDecoratorContext) { return class extends constructor { decoratorNum = 410; } @@ -54,8 +64,8 @@ test("Multiple class decorators", () => { @setTen @setNum class TestClass { - public decoratorTen; - public decoratorNum; + public decoratorTen?: number; + public decoratorNum?: number; } return new TestClass(); @@ -64,7 +74,7 @@ test("Multiple class decorators", () => { test("Class decorator with inheritance", () => { util.testFunction` - function setTen {}>(constructor: T) { + function setTen {}>(constructor: T, context: ClassDecoratorContext) { return class extends constructor { decoratorTen = 10; } @@ -85,11 +95,11 @@ test("Class decorator with inheritance", () => { test("Class decorators are applied in order and executed in reverse order", () => { util.testFunction` - const order = []; + const order: string[] = []; function pushOrder(index: number) { order.push("eval " + index); - return (constructor: new (...args: any[]) => {}) => { + return (constructor: new (...args: any[]) => {}, context: ClassDecoratorContext) => { order.push("execute " + index); }; } @@ -105,7 +115,7 @@ test("Class decorators are applied in order and executed in reverse order", () = test("Throws error if decorator function has void context", () => { util.testFunction` - function decorator(this: void, constructor: new (...args: any[]) => {}) {} + function decorator(this: void, constructor: new (...args: any[]) => {}, context: ClassDecoratorContext) {} @decorator class TestClass {} @@ -114,7 +124,7 @@ test("Throws error if decorator function has void context", () => { test("Exported class decorator", () => { util.testModule` - function decorator any>(Class: T): T { + function decorator any>(Class: T, context: ClassDecoratorContext): T { return class extends Class { public bar = "foobar"; }; @@ -127,60 +137,512 @@ test("Exported class decorator", () => { .expectToMatchJsResult(); }); -test.each([ - ["@decorator method() {}"], - ["@decorator property;"], - ["@decorator propertyWithInitializer = () => {};"], - ["@decorator ['evaluated property'];"], - ["@decorator get getter() { return 5 }"], - ["@decorator set setter(value) {}"], - ["@decorator static method() {}"], - ["@decorator static property;"], - ["@decorator static propertyWithInitializer = () => {}"], - ["@decorator static get getter() { return 5 }"], - ["@decorator static set setter(value) {}"], - ["@decorator static ['evaluated property'];"], - ["method(@decorator a) {}"], - ["static method(@decorator a) {}"], -])("Decorate class member (%p)", classMember => { +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1149 +test("exported class with decorator (#1149)", () => { + util.testModule` + import { MyClass } from "./other"; + const inst = new MyClass(); + export const result = inst.foo(); + ` + .addExtraFile( + "other.ts", + `function myDecorator(target: {new(): any}, context: ClassDecoratorContext) { + return class extends target { + foo() { + return "overridden"; + } + } + } + + @myDecorator + export class MyClass { + foo() { + return "foo"; + } + }` + ) + .expectToEqual({ result: "overridden" }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1634 +test("namespaced exported class with decorator (#1634)", () => { + util.testModule` + function myDecorator(target: {new(): any}, context: ClassDecoratorContext) { + return class extends target { + foo() { + return "overridden"; + } + } + } + + namespace ns { + @myDecorator + export class MyClass { + foo() { + return "foo"; + } + } + } + `.expectNoExecutionError(); +}); + +test("default exported class with decorator", () => { + util.testModule` + import MyClass from "./other"; + const inst = new MyClass(); + export const result = inst.foo(); + ` + .addExtraFile( + "other.ts", + `function myDecorator(target: {new(): any}, context: ClassDecoratorContext) { + return class extends target { + foo() { + return "overridden"; + } + } + } + + @myDecorator + export default class { + foo() { + return "foo"; + } + }` + ) + .expectToEqual({ result: "overridden" }); +}); + +test("class method decorator", () => { + util.testFunction` + let methodDecoratorContext; + + function methodDecorator(method: (v: number) => number, context: ClassMethodDecoratorContext) { + methodDecoratorContext = context; + + return (v: number) => { + return method(v) + 10; + }; + } + + class TestClass { + @methodDecorator + public myMethod(x: number) { + return x * 23; + } + } + + return { result: new TestClass().myMethod(4), context: { + kind: methodDecoratorContext!.kind, + name: methodDecoratorContext!.name, + private: methodDecoratorContext!.private, + static: methodDecoratorContext!.static + } }; + `.expectToMatchJsResult(); +}); + +test("this in decorator points to class being decorated", () => { + util.testFunction` + function methodDecorator(method: (v: number) => number, context: ClassMethodDecoratorContext) { + return function(this: TestClass) { + const thisCallTime = this.myInstanceVariable; + return thisCallTime; + }; + } + + class TestClass { + constructor(protected myInstanceVariable: number) { } + + @methodDecorator + public myMethod() { + return 0; + } + } + + return new TestClass(5).myMethod(); + `.expectToMatchJsResult(); +}); + +test("class getter decorator", () => { + util.testFunction` + let getterDecoratorContext; + + function getterDecorator(getter: () => number, context: ClassGetterDecoratorContext) { + getterDecoratorContext = context; + + return () => { + return getter() + 10; + }; + } + + class TestClass { + @getterDecorator + get getterValue() { return 10; } + } + + return { result: new TestClass().getterValue, context: { + kind: getterDecoratorContext!.kind, + name: getterDecoratorContext!.name, + private: getterDecoratorContext!.private, + static: getterDecoratorContext!.static + } }; + `.expectToMatchJsResult(); +}); + +test("class setter decorator", () => { util.testFunction` - let decoratorParameters: any; + let setterDecoratorContext; - const decorator = (target, key, index?) => { - const targetKind = target === Foo ? "Foo" : target === Foo.prototype ? "Foo.prototype" : "unknown"; - decoratorParameters = { targetKind, key, index: typeof index }; - }; + function setterDecorator(setter: (v: number) => void, context: ClassSetterDecoratorContext) { + setterDecoratorContext = context; - class Foo { - ${classMember} + return function(this: TestClass, v: number) { + setter.call(this, v + 15); + }; + } + + class TestClass { + public value?: number; + + @setterDecorator + set valueSetter(v: number) { this.value = v; } } - return decoratorParameters; + const instance = new TestClass(); + instance.valueSetter = 23; + return { result: instance.value, context: { + kind: setterDecoratorContext!.kind, + name: setterDecoratorContext!.name, + private: setterDecoratorContext!.private, + static: setterDecoratorContext!.static + } }; `.expectToMatchJsResult(); }); -describe("Decorators /w descriptors", () => { +test("class field decorator", () => { + util.testFunction` + let fieldDecoratorContext; + + function fieldDecorator(_: undefined, context: ClassFieldDecoratorContext) { + fieldDecoratorContext = context; + } + + class TestClass { + @fieldDecorator + public value: number = 22; + } + + return { result: new TestClass(), context: { + kind: fieldDecoratorContext!.kind, + name: fieldDecoratorContext!.name, + private: fieldDecoratorContext!.private, + static: fieldDecoratorContext!.static, + } }; + `.expectToEqual({ + result: { + value: 22, // Different from JS because we ignore the value initializer + }, + context: { + kind: "field", + name: "value", + private: false, + static: false, + }, + }); +}); + +test("class field decorator warns the return value is ignored", () => { + util.testFunction` + let fieldDecoratorContext; + + function fieldDecorator(_: undefined, context: ClassFieldDecoratorContext) { + fieldDecoratorContext = context; + + return (initialValue: number) => initialValue * 12; + } + + class TestClass { + @fieldDecorator + public value: number = 22; + } + `.expectDiagnosticsToMatchSnapshot([incompleteFieldDecoratorWarning.code]); +}); + +describe("legacy experimentalDecorators", () => { + test("Class decorator with no parameters", () => { + util.testFunction` + function setBool {}>(constructor: T) { + return class extends constructor { + decoratorBool = true; + } + } + + @setBool + class TestClass { + public decoratorBool = false; + } + + return new TestClass(); + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test("Class decorator with parameters", () => { + util.testFunction` + function setNum(numArg: number) { + return {}>(constructor: T) => { + return class extends constructor { + decoratorNum = numArg; + }; + }; + } + + @setNum(420) + class TestClass { + public decoratorNum?: number; + } + + return new TestClass(); + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test("Multiple class decorators", () => { + util.testFunction` + function setTen {}>(constructor: T) { + return class extends constructor { + decoratorTen = 10; + } + } + + function setNum {}>(constructor: T) { + return class extends constructor { + decoratorNum = 410; + } + } + + @setTen + @setNum + class TestClass { + public decoratorTen?: number; + public decoratorNum?: number; + } + + return new TestClass(); + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test("Class decorator with inheritance", () => { + util.testFunction` + function setTen {}>(constructor: T) { + return class extends constructor { + decoratorTen = 10; + } + } + + class TestClass { + public decoratorTen = 0; + } + + @setTen + class SubTestClass extends TestClass { + public decoratorTen = 5; + } + + return new SubTestClass(); + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test("Class decorators are applied in order and executed in reverse order", () => { + util.testFunction` + const order: string[] = []; + + function pushOrder(index: number) { + order.push("eval " + index); + return (constructor: new (...args: any[]) => {}) => { + order.push("execute " + index); + }; + } + + @pushOrder(1) + @pushOrder(2) + @pushOrder(3) + class TestClass {} + + return order; + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test("Throws error if decorator function has void context", () => { + util.testFunction` + function decorator(this: void, constructor: new (...args: any[]) => {}) {} + + @decorator + class TestClass {} + ` + .setOptions({ experimentalDecorators: true }) + .expectDiagnosticsToMatchSnapshot([decoratorInvalidContext.code]); + }); + + test("Exported class decorator", () => { + util.testModule` + function decorator any>(Class: T): T { + return class extends Class { + public bar = "foobar"; + }; + } + + @decorator + export class Foo {} + ` + .setReturnExport("Foo", "bar") + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + test.each([ - ["return { writable: true }", "return { configurable: true }"], - ["desc.writable = true", "return { configurable: true }"], - ])("Combine decorators (%p + %p)", (decorateA, decorateB) => { + ["@decorator method() {}"], + ["@decorator property: any;"], + ["@decorator propertyWithInitializer = () => {};"], + ["@decorator ['evaluated property']: any;"], + ["@decorator get getter() { return 5 }"], + ["@decorator set setter(value: any) {}"], + ["@decorator static method() {}"], + ["@decorator static property: any;"], + ["@decorator static propertyWithInitializer = () => {}"], + ["@decorator static get getter() { return 5 }"], + ["@decorator static set setter(value: any) {}"], + ["@decorator static ['evaluated property']: any;"], + ["method(@decorator a: any) {}"], + ["static method(@decorator a: any) {}"], + ["constructor(@decorator a: any) {}"], + ])("Decorate class member (%p)", classMember => { util.testFunction` - const A = (target, key, desc): any => { ${decorateA} }; - const B = (target, key, desc): any => { ${decorateB} }; - class Foo { @A @B static method() {} } - const { value, ...rest } = Object.getOwnPropertyDescriptor(Foo, "method"); - return rest; - `.expectToMatchJsResult(); + let decoratorParameters: any; + + const decorator = (target: any, key: any, index?: any) => { + const targetKind = target === Foo ? "Foo" : target === Foo.prototype ? "Foo.prototype" : "unknown"; + decoratorParameters = { targetKind, key, index: typeof index }; + }; + + class Foo { + ${classMember} + } + + return decoratorParameters; + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); }); - test.each(["return { value: true }", "desc.value = true"])( - "Use decorator to override method value", - overrideStatement => { + describe("Decorators /w descriptors", () => { + test.each([ + ["return { writable: true }", "return { configurable: true }"], + ["desc.writable = true", "return { configurable: true }"], + ])("Combine decorators (%p + %p)", (decorateA, decorateB) => { util.testFunction` - const decorator = (target, key, desc): any => { ${overrideStatement} }; - class Foo { @decorator static method() {} } - return Foo.method; - `.expectToMatchJsResult(); - } - ); + const A = (target: any, key: any, desc: any): any => { ${decorateA} }; + const B = (target: any, key: any, desc: any): any => { ${decorateB} }; + class Foo { @A @B static method() {} } + const { value, ...rest } = Object.getOwnPropertyDescriptor(Foo, "method")!; + return rest; + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); + + test.each(["return { value: true }", "desc.value = true"])( + "Use decorator to override method value %s", + overrideStatement => { + util.testFunction` + const decorator = (target: any, key: any, desc: any): any => { ${overrideStatement} }; + class Foo { @decorator static method() {} } + return Foo.method; + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + } + ); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1149 + test("exported class with decorator", () => { + util.testModule` + import { MyClass } from "./other"; + const inst = new MyClass(); + export const result = inst.foo(); + ` + .addExtraFile( + "other.ts", + `function myDecorator(target: {new(): any}) { + return class extends target { + foo() { + return "overridden"; + } + } + } + + @myDecorator + export class MyClass { + foo() { + return "foo"; + } + }` + ) + .setOptions({ experimentalDecorators: true }) + .expectToEqual({ result: "overridden" }); + }); + + test("default exported class with decorator", () => { + util.testModule` + import MyClass from "./other"; + const inst = new MyClass(); + export const result = inst.foo(); + ` + .addExtraFile( + "other.ts", + `function myDecorator(target: {new(): any}) { + return class extends target { + foo() { + return "overridden"; + } + } + } + + @myDecorator + export default class { + foo() { + return "foo"; + } + }` + ) + .setOptions({ experimentalDecorators: true }) + .expectToEqual({ result: "overridden" }); + }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1453 + test("Class methods with legacy decorators can still be called ($1453)", () => { + util.testFunction` + function decorator( + target: Class, + propertyKey: keyof Class, + ): void {} + + class Foo { + @decorator + public method2() { return 4; } + } + + return new Foo().method2(); + ` + .setOptions({ experimentalDecorators: true }) + .expectToMatchJsResult(); + }); }); diff --git a/test/unit/classes/instanceof.spec.ts b/test/unit/classes/instanceof.spec.ts index 4e4000153..3869bfa1c 100644 --- a/test/unit/classes/instanceof.spec.ts +++ b/test/unit/classes/instanceof.spec.ts @@ -84,7 +84,7 @@ test("instanceof export", () => { test("instanceof Symbol.hasInstance", () => { util.testFunction` class myClass { - static [Symbol.hasInstance]() { + static [Symbol.hasInstance](instance: unknown) { return false; } } diff --git a/test/unit/comments.spec.ts b/test/unit/comments.spec.ts new file mode 100644 index 000000000..2efb92b53 --- /dev/null +++ b/test/unit/comments.spec.ts @@ -0,0 +1,115 @@ +import * as util from "../util"; + +test("Single-line JSDoc is copied on a function", () => { + const builder = util.testModule` + /** This is a function comment. */ + function foo() {} + ` + .expectToHaveNoDiagnostics() + .expectDiagnosticsToMatchSnapshot(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("This is a function comment."); +}); + +test("Multi-line JSDoc with one block is copied on a function", () => { + const builder = util.testModule` + /** + * This is a function comment. + * It has more than one line. + */ + function foo() {} + ` + .expectToHaveNoDiagnostics() + .expectDiagnosticsToMatchSnapshot(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("It has more than one line."); +}); + +test("Multi-line JSDoc with two blocks is copied on a function", () => { + const builder = util.testModule` + /** + * This is a function comment. + * It has more than one line. + * + * It also has more than one block. + */ + function foo() {} + ` + .expectToHaveNoDiagnostics() + .expectDiagnosticsToMatchSnapshot(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("It also has more than one block."); +}); + +test("JSDoc is copied on a function with tags", () => { + const builder = util.testModule` + /** + * This is a function comment. + * It has multiple lines. + * + * @param arg1 This is the first argument. + * @param arg2 This is the second argument. + * @returns A very powerful string. + */ + function foo(arg1: boolean, arg2: number): string { + return "bar"; + } + ` + .expectToHaveNoDiagnostics() + .expectDiagnosticsToMatchSnapshot(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("This is the first argument."); + expect(lua).toContain("This is the second argument."); + expect(lua).toContain("A very powerful string."); +}); + +test("JSDoc is copied on a variable", () => { + const builder = util.testModule` + /** This is a variable comment. */ + const foo = 123; + ` + .expectToHaveNoDiagnostics() + .expectDiagnosticsToMatchSnapshot(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("This is a variable comment."); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1299 +test("tsdoc comment does not cause a diagnostic (#1299)", () => { + util.testModule` + interface LuaBootstrap { + /** + * @remarks + * + * Links can point to a URL: {@link https://github.com/microsoft/tsdoc} + */ + on_init(f: (() => void) ): void + } + + const script : LuaBootstrap = { + on_init: (x) => x() + } + + script.on_init(() => {}) + `.expectToHaveNoDiagnostics(); +}); diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index c9717d0c0..59ca587bc 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,5 +1,6 @@ import * as tstl from "../../src"; import * as util from "../util"; +import { truthyOnlyConditionalValue } from "../../src/transformation/utils/diagnostics"; test.each([0, 1])("if (%p)", inp => { util.testFunction` @@ -74,7 +75,7 @@ test.each([ ])("Ternary operator (%p)", ({ input, options }) => { util.testFunction` const literalValue = "literal"; - let variableValue: string; + let variableValue: string = "variable"; let maybeBooleanValue: string | boolean = false; let maybeUndefinedValue: string | undefined; return ${input}; @@ -88,7 +89,12 @@ test.each([ { condition: false, lhs: 4, rhs: 5 }, { condition: 3, lhs: 4, rhs: 5 }, ])("Ternary Conditional (%p)", ({ condition, lhs, rhs }) => { - util.testExpressionTemplate`${condition} ? ${lhs} : ${rhs}`.expectToMatchJsResult(); + util.testExpressionTemplate`${condition} ? ${lhs} : ${rhs}` + .ignoreDiagnostics([ + truthyOnlyConditionalValue.code, + 2872 /* TS2872: This kind of expression is always truthy. */, + ]) + .expectToMatchJsResult(); }); test.each(["true", "false", "a < 4", "a == 8"])("Ternary Conditional Delayed (%p)", condition => { @@ -99,3 +105,104 @@ test.each(["true", "false", "a < 4", "a == 8"])("Ternary Conditional Delayed (%p return delay(); `.expectToMatchJsResult(); }); + +test.each([false, true, null])("Ternary conditional with generic whenTrue branch (%p)", trueVal => { + util.testFunction` + function ternary(a: boolean, b: B, c: C) { + return a ? b : c + } + return ternary(true, ${trueVal}, "wasFalse") + ` + .setOptions({ + strictNullChecks: true, + }) + .expectToMatchJsResult(); +}); + +test.each([false, true])("Ternary conditional with preceding statements in true branch (%p)", trueVal => { + // language=TypeScript + util.testFunction` + let i = 0; + const result = ${trueVal} ? i += 1 : i; + return { result, i }; + ` + .setOptions({ + strictNullChecks: true, + }) + .expectToMatchJsResult(); +}); + +test.each([false, true])("Ternary conditional with preceding statements in false branch (%p)", trueVal => { + // language=TypeScript + util.testFunction` + let i = 0; + const result = ${trueVal} ? i : i += 2; + return { result, i }; + ` + .setOptions({ + strictNullChecks: true, + }) + .expectToMatchJsResult(); +}); + +test.each(["string", "number", "string | number"])( + "Warning when using if statement that cannot evaluate to false undefined or null (%p)", + type => { + util.testFunction` + if (condition) {} + ` + .setTsHeader(`declare var condition: ${type};`) + .setOptions({ strict: true }) + .expectToHaveDiagnostics([truthyOnlyConditionalValue.code]); + } +); + +test.each(["string", "number", "string | number"])("Warning can be disabled when strict is true (%p)", type => { + util.testFunction` + if (condition) {} + ` + .setTsHeader(`declare var condition: ${type};`) + .setOptions({ strict: true, strictNullChecks: false }) + .expectToHaveNoDiagnostics(); +}); + +test.each(["string", "number", "string | number"])( + "Warning when using while statement that cannot evaluate to false undefined or null (%p)", + type => { + util.testFunction` + while (condition) {} + ` + .setTsHeader(`declare var condition: ${type};`) + .setOptions({ strict: true }) + .expectToHaveDiagnostics([truthyOnlyConditionalValue.code]); + } +); + +test.each(["string", "number", "string | number"])( + "Warning when using do while statement that cannot evaluate to false undefined or null (%p)", + type => { + util.testFunction` + do {} while (condition) + ` + .setTsHeader(`declare var condition: ${type};`) + .setOptions({ strict: true }) + .expectToHaveDiagnostics([truthyOnlyConditionalValue.code]); + } +); + +test.each(["string", "number", "string | number"])( + "Warning when using ternary that cannot evaluate to false undefined or null (%p)", + type => { + util.testExpression`condition ? 1 : 0` + .setTsHeader(`declare var condition: ${type};`) + .setOptions({ strict: true }) + .expectToHaveDiagnostics([truthyOnlyConditionalValue.code]); + } +); + +test.each(["string", "number", "string | number"])("No warning when using element index in condition (%p)", type => { + util.testExpression`condition[0] ? 1 : 0` + .setTsHeader(`declare var condition: ${type}[];`) + .setOptions({ strict: true }) + .expectToHaveNoDiagnostics(); +}); diff --git a/test/unit/destructuring.spec.ts b/test/unit/destructuring.spec.ts index 2ec12c7d1..36b73daaf 100644 --- a/test/unit/destructuring.spec.ts +++ b/test/unit/destructuring.spec.ts @@ -1,41 +1,52 @@ +import { cannotAssignToNodeOfKind, invalidMultiReturnAccess } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; const allBindings = "x, y, z, rest"; const testCases = [ - { binding: "{ x }", value: { x: true } }, - { binding: "{ x, y }", value: { x: false, y: true } }, - { binding: "{ x: z, y }", value: { x: true, y: false } }, - { binding: "{ x: { x, y }, z }", value: { x: { x: true, y: false }, z: false } }, - { binding: "{ x, y = true }", value: { x: false, y: false } }, - { binding: "{ x = true }", value: {} }, - { binding: "{ x, y = true }", value: { x: false } }, - { binding: "{ ...rest }", value: {} }, - { binding: "{ x, ...rest }", value: { x: "x" } }, - { binding: "{ x, ...rest }", value: { x: "x", y: "y", z: "z" } }, - { binding: "{ x, ...y }", value: { x: "x", y: "y", z: "z" } }, - { binding: "{ x: y, ...z }", value: { x: "x", y: "y", z: "z" } }, - - { binding: "[]", value: [] }, - { binding: "[x, y]", value: ["x", "y"] }, - { binding: "[x, , y]", value: ["x", "", "y"] }, - { binding: "[x = true]", value: [false] }, - { binding: "[[x, y]]", value: [["x", "y"]] }, - { binding: "[x, ...rest]", value: ["x"] }, - { binding: "[x, ...rest]", value: ["x", "y", "z"] }, - - { binding: "{ y: [z = true] }", value: { y: [false] } }, - { binding: "{ x: [x, y] }", value: { x: ["x", "y"] } }, - { binding: "{ x: [{ y }] }", value: { x: [{ y: "y" }] } }, -].map(({ binding, value }) => ({ binding, value: util.formatCode(value) })); + { binding: "{ x }", type: "{ x: boolean }", value: { x: true } }, + { binding: "{ x, y }", type: "{ x: boolean, y: boolean }", value: { x: false, y: true } }, + { binding: "{ x: z, y }", type: "{ x: boolean, y?: boolean, z?: boolean }", value: { x: true, y: false } }, + { + binding: "{ x: { x, y }, z }", + type: "{ x: { x: boolean, y: boolean }, z: boolean }", + value: { x: { x: true, y: false }, z: false }, + }, + { binding: "{ x, y = true }", type: "{ x: boolean, y?: boolean }", value: { x: false, y: false } }, + { binding: "{ x = true }", type: "{ x?: boolean }", value: {} }, + { binding: "{ x, y = true }", type: "{ x: boolean, y?: boolean }", value: { x: false } }, + { binding: "{ ...rest }", type: "any", value: {} }, + { binding: "{ x, ...rest }", type: "any", value: { x: "x" } }, + { binding: "{ x, ...rest }", type: "any", value: { x: "x", y: "y", z: "z" } }, + { binding: "{ x, ...y }", type: "any", value: { x: "x", y: "y", z: "z" } }, + { binding: "{ x: y, ...z }", type: "any", value: { x: "x", y: "y", z: "z" } }, + + { binding: "[]", type: "boolean[]", value: [] }, + { binding: "[x, y]", type: "[string, string]", value: ["x", "y"] }, + { binding: "[x, , y]", type: "string[]", value: ["x", "", "y"] }, + { binding: "[x = true]", type: "boolean[]", value: [false] }, + { binding: "[x = true]", type: "boolean[]", value: [] }, + { binding: "[[x, y]]", type: "Array", value: [["x", "y"]] }, + { binding: "[x, ...rest]", type: "string[]", value: ["x"] }, + { binding: "[x, ...rest]", type: "string[]", value: ["x", "y", "z"] }, + + { binding: "{ y: [z = true] }", type: "{ y: boolean[] }", value: { y: [false] } }, + { binding: "{ y: [z = true] }", type: "{ y: boolean[] }", value: { y: [] } }, + { binding: "{ x: [x, y] }", type: "{ x: [string, string] }", value: { x: ["x", "y"] } }, + { binding: "{ x: [{ y }] }", type: "{ x: [{ y: string }] }", value: { x: [{ y: "y" }] } }, +].map(({ binding, type, value }) => ({ binding, type, value: util.formatCode(value) })); test.each([ ...testCases, - { binding: "{ x, y }, z", value: "{ x: false, y: false }, true" }, - { binding: "{ x, y }, { z }", value: "{ x: false, y: false }, { z: true }" }, -])("in function parameter (%p)", ({ binding, value }) => { + { binding: "{ x, y }", type: "{ x: boolean, y: boolean }, z: boolean", value: "{ x: false, y: false }, true" }, + { + binding: "{ x, y }", + type: "{ x: boolean, y: boolean }, { z }: { z: boolean }", + value: "{ x: false, y: false }, { z: true }", + }, +])("in function parameter (%p)", ({ binding, type, value }) => { util.testFunction` let ${allBindings}; - function test(${binding}) { + function test(${binding}: ${type}) { return { ${allBindings} }; } @@ -53,6 +64,17 @@ test("in function parameter creates local variables", () => { expect(code).toContain("local b ="); }); +test("in function parameter creates local variables in correct scope", () => { + util.testFunction` + let x = 7; + function foo([x]: [number]) { + x *= 2; + } + foo([1]); + return x; + `.expectToMatchJsResult(); +}); + test.each(testCases)("in variable declaration (%p)", ({ binding, value }) => { util.testFunction` let ${allBindings}; @@ -63,6 +85,28 @@ test.each(testCases)("in variable declaration (%p)", ({ binding, value }) => { `.expectToMatchJsResult(); }); +test.each(testCases)("in variable declaration from const variable (%p)", ({ binding, value }) => { + util.testFunction` + let ${allBindings}; + { + const v: any = ${value}; + const ${binding} = v; + return { ${allBindings} }; + } + `.expectToMatchJsResult(); +}); + +test.each(testCases)("in variable declaration from this (%p)", ({ binding, value }) => { + util.testFunction` + let ${allBindings}; + function test(this: any) { + const ${binding} = this; + return { ${allBindings} }; + } + return test.call(${value}); + `.expectToMatchJsResult(); +}); + test.each(testCases)("in exported variable declaration (%p)", ({ binding, value }) => { util.testModule` export const ${binding} = ${value}; @@ -90,6 +134,28 @@ test.each(assignmentTestCases)("in assignment expression (%p)", ({ binding, valu `.expectToMatchJsResult(); }); +test.each(assignmentTestCases)("in assignment expression from const variable (%p)", ({ binding, value }) => { + util.testFunction` + let ${allBindings}; + const obj = { prop: false }; + const v: any = ${value}; + const expressionResult = (${binding} = v); + return { ${allBindings}, expressionResult }; + `.expectToMatchJsResult(); +}); + +test.each(assignmentTestCases)("in assignment expression from this (%p)", ({ binding, value }) => { + util.testFunction` + let ${allBindings}; + const obj = { prop: false }; + function test(this: any) { + const expressionResult = (${binding} = this); + return { ${allBindings}, obj, expressionResult }; + } + return test.call(${value}); + `.expectToMatchJsResult(); +}); + test.each(["[]", "{}"])("empty binding pattern", bindingPattern => { util.testFunction` let i = 1; @@ -139,6 +205,17 @@ describe("array destructuring optimization", () => { .expectToMatchJsResult(); }); + util.testEachVersion( + "array versions", + () => + util.testFunction` + const array = [3, 5, 1]; + const [a, b, c] = array; + return { a, b, c }; + `, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); + test("array literal", () => { util.testFunction` const [a, b, c] = [3, 5, 1]; @@ -159,6 +236,33 @@ describe("array destructuring optimization", () => { .expectToMatchJsResult(); }); + test("array literal with side effects in elements", () => { + util.testFunction` + const arr = [1, 2]; + let i = 0; + let [v1, v2] = [arr[i], arr[++i]]; + return { v1, v2 }; + `.expectToMatchJsResult(); + }); + + test("array literal with many side effects in elements", () => { + util.testFunction` + const arr = [10, 20, 30, 40]; + let i = 0; + let [v1, v2, v3, v4] = [arr[i++], arr[i++], arr[i++], arr[i++]]; + return { v1, v2, v3, v4 }; + `.expectToMatchJsResult(); + }); + + test("array literal with mixed pure and impure elements", () => { + util.testFunction` + const arr = [10, 20, 30]; + let i = 0; + let [v1, v2, v3] = [1, arr[++i], 2]; + return { v1, v2, v3, i }; + `.expectToMatchJsResult(); + }); + test("array union", () => { util.testFunction` const array: [string] | [] = ["bar"]; @@ -170,3 +274,14 @@ describe("array destructuring optimization", () => { .expectToMatchJsResult(); }); }); + +test("no exception from semantically invalid TS", () => { + util.testModule` + declare function testFunc(value: number): LuaMultiReturn<[number, number]>; + let [a, b] = testFunc(5) // Missing ; + [a, b] = testFunc(b) // Interpreted as testFunc(5)[a, b] + ` + .withLanguageExtensions() + .disableSemanticCheck() + .expectToHaveDiagnostics([invalidMultiReturnAccess.code, cannotAssignToNodeOfKind.code]); +}); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index f421be2c5..ae552b9c1 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -4,7 +4,7 @@ import * as util from "../util"; const serializeEnum = (identifier: string) => `(() => { const mappedTestEnum: any = {}; for (const key in ${identifier}) { - mappedTestEnum[(key as any).toString()] = ${identifier}[key]; + mappedTestEnum[(key as any).toString()] = (${identifier} as any)[key]; } return mappedTestEnum; })()`; @@ -203,3 +203,14 @@ test("enum merging multiple files", () => { ) .expectToMatchJsResult(); }); + +test("enum nested in namespace", () => { + util.testModule` + namespace A { + export enum TestEnum { + B, + C + } + } + `.expectLuaToMatchSnapshot(); +}); diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 9174f941c..f7056655f 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,4 +1,5 @@ import * as util from "../util"; +import * as tstl from "../../src"; test("throwString", () => { util.testFunction` @@ -6,29 +7,40 @@ test("throwString", () => { `.expectToEqual(new util.ExecutionError("Some Error")); }); -test.skip.each([0, 1, 2])("re-throw (%p)", i => { +test.each([ + { innerTry: false, innerFinally: false, outerFinally: false }, + { innerTry: false, innerFinally: false, outerFinally: true }, + { innerTry: false, innerFinally: true, outerFinally: false }, + { innerTry: false, innerFinally: true, outerFinally: true }, + { innerTry: true, innerFinally: false, outerFinally: false }, + { innerTry: true, innerFinally: false, outerFinally: true }, + { innerTry: true, innerFinally: true, outerFinally: false }, + { innerTry: true, innerFinally: true, outerFinally: true }, +])("re-throw (%j)", o => { util.testFunction` - const i: number = ${i}; + const innerTry: boolean = ${o.innerTry}; + const innerFinally: boolean = ${o.innerFinally}; + const outerFinally: boolean = ${o.outerFinally}; function foo() { try { try { - if (i === 0) { throw "z"; } + if (innerTry) { throw "inner.try"; } } catch (e) { - throw "a"; + throw (e as string) + "->" + "inner.catch"; } finally { - if (i === 1) { throw "b"; } + if (innerFinally) { throw "inner.finally"; } } } catch (e) { - throw (e as string).toUpperCase(); + throw (e as string) + "->" + "outer.catch"; } finally { - throw "C"; + if (outerFinally) { throw "outer.finally"; } } } let result: string = "x"; try { foo(); } catch (e) { - result = (e as string)[(e as string).length - 1]; + result = e as string; } return result; `.expectToMatchJsResult(); @@ -77,18 +89,17 @@ test("return nil from try", () => { `.expectToMatchJsResult(); }); -test("tuple return from try", () => { +test("multi return from try", () => { const testBuilder = util.testFunction` - /** @tupleReturn */ function foobar() { try { - return ["foo", "bar"]; + return $multi("foo", "bar"); } catch { } } - const [foo, bar] = foobar(); + const [foo, bar] = foobar()!; return foo + bar; - `; + `.withLanguageExtensions(); expect(testBuilder.getMainLuaCodeChunk()).not.toMatch("unpack(foobar"); testBuilder.expectToMatchJsResult(); }); @@ -122,19 +133,18 @@ test("return nil from catch", () => { `.expectToMatchJsResult(); }); -test("tuple return from catch", () => { +test("multi return from catch", () => { const testBuilder = util.testFunction` - /** @tupleReturn */ - function foobar(): [string, string] { + function foobar(): LuaMultiReturn<[string, string]> { try { throw "foobar"; - } catch (e) { - return [e.toString(), " catch"]; + } catch (e: any) { + return $multi(e.toString(), " catch"); } } const [foo, bar] = foobar(); return foo + bar; - `; + `.withLanguageExtensions(); expect(testBuilder.getMainLuaCodeChunk()).not.toMatch("unpack(foobar"); testBuilder.expectToMatchJsResult(); }); @@ -210,46 +220,70 @@ test("return from catch->finally", () => { `.expectToMatchJsResult(); }); -test("tuple return from try->finally", () => { +test("multi return from try->finally", () => { util.testFunction` let x = "unevaluated"; function evaluate(arg: string) { x = "evaluated"; return arg; } - /** @tupleReturn */ function foobar() { try { - return [evaluate("foo"), "bar"]; + return $multi(evaluate("foo"), "bar"); } catch { } finally { - return ["final", "ly"]; + return $multi("final", "ly"); } } const [foo, bar] = foobar(); return foo + bar + " " + x; - `.expectToMatchJsResult(); + ` + .withLanguageExtensions() + .expectToMatchJsResult(); }); -test("tuple return from catch->finally", () => { +test("multi return from catch->finally", () => { util.testFunction` let x = "unevaluated"; function evaluate(arg: string) { x = "evaluated"; return arg; } - /** @tupleReturn */ function foobar() { try { throw "foo"; - } catch (e) { - return [evaluate(e), "bar"]; + } catch (e: any) { + return $multi(evaluate(e), "bar"); } finally { - return ["final", "ly"]; + return $multi("final", "ly"); } } const [foo, bar] = foobar(); return foo + bar + " " + x; + ` + .withLanguageExtensions() + .expectToMatchJsResult(); +}); + +test("throw propagates through finally to outer catch", () => { + util.testFunction` + function thrower() { + try { + throw "Error"; + } finally { + } + } + + function caller() { + try { + thrower(); + return "NoCatch"; + } catch (e) { + return e; + } + } + + return caller(); `.expectToMatchJsResult(); }); @@ -322,3 +356,172 @@ test.each([...builtinErrors, "CustomError"])("get stack from %s", errorType => { expect(stack).toMatch("innerFunction"); expect(stack).toMatch("outerFunction"); }); + +test("still works without debug module", () => { + util.testFunction` + try + { + throw new Error("hello, world"); + } + catch (e) + { + return e; + } + ` + .setLuaHeader("debug = nil") + .expectToEqual({ + message: "hello, world", + name: "Error", + stack: undefined, + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1665 +test("sourceMapTraceback maps anonymous function locations in .lua files (#1665)", () => { + // Nested IIFEs produce anonymous function notation in traceback. + // Old pattern (%S+)%.lua:(%d+) captures "", + // failing the sourcemap lookup. Fix: ([^%s<]+) excludes "<". + + // mapping is copied from the emitted Lua, not invented. + const mapping = `{["5"] = 1,["6"] = 2,["7"] = 3,["8"] = 4,["9"] = 3,["10"] = 2,["11"] = 1}`; + + // Test harness executes via luaL_dostring (chunk names are [string "..."]), so we mock a file-based traceback. + const fakeTraceback = [ + "stack traceback:", + "\tmain.lua:8: in function ", + "\tmain.lua:7: in function ", + "\t[C]: in ?", + ].join("\n"); + + // Inject sourcemap for "main.lua" and mock debug.traceback to return file-based frames. + const header = ` + __TS__sourcemap = { ["main.lua"] = ${mapping} }; + local __real_tb = debug.traceback + debug.traceback = function() return ${JSON.stringify(fakeTraceback)} end + `; + + const builder = util.testFunction` + return (() => { + return (() => { + return (debug.traceback as (this: void) => string)(); + })(); + })(); + ` + .setLuaHeader(header) + .setOptions({ sourceMapTraceback: true }); + + const lua = builder.getMainLuaCodeChunk(); + // Sanity check: emitted code registers the same mapping literal we inject above. + expect(lua).toContain(`__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapping});`); + + const result = builder.getLuaExecutionResult(); + expect(result).toEqual(expect.any(String)); + // Both `main.lua:N` and `` frames should be rewritten using the sourcemap. + expect(result).not.toContain("main.lua"); + // Regular line references + expect(result).toContain("\tmain.ts:4:"); + expect(result).toContain("\tmain.ts:3:"); + // Anonymous function references must keep <> format + expect(result).toContain(""); + expect(result).toContain(""); +}); + +test("try/finally rethrow preserves error value", () => { + util.testFunction` + function foo() { + try { + throw "oops"; + } finally { + } + } + try { foo(); return "no error"; } catch(e) { return e; } + `.expectToMatchJsResult(); +}); + +test("try/finally with return and throw paths", () => { + util.testFunction` + function foo(shouldReturn: boolean) { + try { + if (shouldReturn) return "returned"; + throw "thrown"; + } finally { + } + } + const results: any[] = []; + results.push(foo(true)); + try { foo(false); } catch(e) { results.push(e); } + return results; + `.expectToMatchJsResult(); +}); + +test("try/finally runs finally side effect before rethrow", () => { + util.testFunction` + let sideEffect = false; + function foo() { + try { + throw "err"; + } finally { + sideEffect = true; + } + } + try { foo(); } catch(e) {} + return sideEffect; + `.expectToMatchJsResult(); +}); + +test("try/finally with return and throw paths and non-empty finally body", () => { + util.testFunction` + let sideEffect = false; + function foo(shouldReturn: boolean) { + try { + if (shouldReturn) return "ok"; + throw "err"; + } finally { + sideEffect = true; + } + } + const results: any[] = []; + results.push(foo(true)); + results.push(sideEffect); + sideEffect = false; + try { foo(false); } catch(e) { results.push(e); } + results.push(sideEffect); + return results; + `.expectToMatchJsResult(); +}); + +test("try/finally rethrow with non-string error", () => { + util.testFunction` + function foo() { + try { + throw 42; + } finally { + } + } + try { foo(); return "no error"; } catch(e) { return e; } + `.expectToMatchJsResult(); +}); + +util.testEachVersion( + "error stacktrace omits constructor and __TS_New", + () => util.testFunction` + const e = new Error(); + return e.stack; + `, + { + ...util.expectEachVersionExceptJit(builder => { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + // eslint-disable-next-line jest/no-standalone-expect + expect(luaResult.split("\n")).toHaveLength(4); + }), + + // 5.0 debug.traceback doesn't support levels + [tstl.LuaTarget.Lua50](builder) { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + // eslint-disable-next-line jest/no-standalone-expect + expect(luaResult).toContain("Level 4"); + }, + } +); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 71c014fda..12fd85be1 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -18,9 +18,13 @@ test.each([ util.testFunction(input).disableSemanticCheck().expectLuaToMatchSnapshot(); }); -test.each(["3+4", "5-2", "6*3", "6**3", "20/5", "15/10", "15%3"])("Binary expressions basic numeric (%p)", input => { - util.testExpression(input).expectToMatchJsResult(); -}); +for (const expression of ["3+4", "5-2", "6*3", "6**3", "20/5", "15/10", "15%3"]) { + util.testEachVersion( + `Binary expressions basic numeric (${expression})`, + () => util.testExpression(expression), + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); +} test.each(["1==1", "1===1", "1!=1", "1!==1", "1>1", "1>=1", "1<1", "1<=1", "1&&1", "1||1"])( "Binary expressions basic boolean (%p)", @@ -48,6 +52,14 @@ test.each(["a+=b", "a-=b", "a*=b", "a/=b", "a%=b", "a**=b"])("Binary expressions const supportedInAll = ["~a", "a&b", "a&=b", "a|b", "a|=b", "a^b", "a^=b", "a<>>b", "a>>>=b"]; const unsupportedIn53And54 = ["a>>b", "a>>=b"]; const allBinaryOperators = [...supportedInAll, ...unsupportedIn53And54]; +test.each(allBinaryOperators)("Bitop [5.0] (%p)", input => { + // Bit operations not supported in 5.0, expect an exception + util.testExpression(input) + .setOptions({ luaTarget: tstl.LuaTarget.Lua50, luaLibImport: tstl.LuaLibImportKind.None }) + .disableSemanticCheck() + .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); +}); + test.each(allBinaryOperators)("Bitop [5.1] (%p)", input => { // Bit operations not supported in 5.1, expect an exception util.testExpression(input) @@ -84,6 +96,13 @@ test.each(supportedInAll)("Bitop [5.4] (%p)", input => { .expectLuaToMatchSnapshot(); }); +test.each(supportedInAll)("Bitop [5.5] (%p)", input => { + util.testExpression(input) + .setOptions({ luaTarget: tstl.LuaTarget.Lua55, luaLibImport: tstl.LuaLibImportKind.None }) + .disableSemanticCheck() + .expectLuaToMatchSnapshot(); +}); + test.each(unsupportedIn53And54)("Unsupported bitop 5.3 (%p)", input => { util.testExpression(input) .setOptions({ luaTarget: tstl.LuaTarget.Lua53, luaLibImport: tstl.LuaLibImportKind.None }) @@ -98,6 +117,35 @@ test.each(unsupportedIn53And54)("Unsupported bitop 5.4 (%p)", input => { .expectDiagnosticsToMatchSnapshot([unsupportedRightShiftOperator.code]); }); +// Execution tests: verify >>> produces correct results matching JS semantics +for (const expression of ["-5 >>> 0", "-1 >>> 0", "1 >>> 0", "-1 >>> 16", "255 >>> 4"]) { + util.testEachVersion(`Unsigned right shift execution (${expression})`, () => util.testExpression(expression), { + [tstl.LuaTarget.Universal]: false, + [tstl.LuaTarget.Lua50]: false, // No bit library in WASM runtime + [tstl.LuaTarget.Lua51]: false, // No bit library in WASM runtime + [tstl.LuaTarget.Lua52]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua53]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua54]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua55]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.LuaJIT]: false, // Can't execute LuaJIT in tests + [tstl.LuaTarget.Luau]: false, + }); +} + +for (const code of ["let a = -5; a >>>= 0; return a;", "let a = -1; a >>>= 16; return a;"]) { + util.testEachVersion(`Unsigned right shift assignment execution (${code})`, () => util.testFunction(code), { + [tstl.LuaTarget.Universal]: false, + [tstl.LuaTarget.Lua50]: false, // No bit library in WASM runtime + [tstl.LuaTarget.Lua51]: false, // No bit library in WASM runtime + [tstl.LuaTarget.Lua52]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua53]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua54]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.Lua55]: builder => builder.expectToMatchJsResult(), + [tstl.LuaTarget.LuaJIT]: false, // Can't execute LuaJIT in tests + [tstl.LuaTarget.Luau]: false, + }); +} + test.each(["1+1", "-1+1", "1*30+4", "1*(3+4)", "1*(3+4*2)", "10-(4+5)"])( "Binary expressions ordering parentheses (%p)", input => { @@ -153,6 +201,21 @@ test("Non-null expression", () => { `.expectToMatchJsResult(); }); +test("Typescript 4.7 instantiation expression", () => { + util.testFunction` + function foo(x: T): T { return x; } + const bar = foo; + return bar(3); + `.expectToMatchJsResult(); +}); + +test("Typescript 4.9 satisfies expression", () => { + util.testFunction` + const foo = { a: 1 } satisfies { a: number }; + return foo.a; + `.expectToMatchJsResult(); +}); + test.each([ '"foobar"', "17", diff --git a/test/unit/find-lua-requires.spec.ts b/test/unit/find-lua-requires.spec.ts new file mode 100644 index 000000000..bb879d642 --- /dev/null +++ b/test/unit/find-lua-requires.spec.ts @@ -0,0 +1,159 @@ +import { findLuaRequires, LuaRequire } from "../../src/transpilation/find-lua-requires"; + +test("empty string", () => { + expect(findLuaRequires("")).toEqual([]); +}); + +test("can find requires", () => { + const lua = ` + require("req1") + require('req2') + local r3 = require("req3") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2", "req3"]); +}); + +test("handles requires with spacing", () => { + const lua = 'require \t ( \t "req" )'; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req"]); +}); + +test("handles requires without parentheses", () => { + const lua = 'require "req"'; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req"]); +}); + +test("has correct offsets", () => { + const lua = ` + require("req1") + require('req2') + local r3 = require("req3") + `; + const requires = findLuaRequires(lua); + expect(requires).toHaveLength(3); + expect(lua.substring(requires[0].from, requires[0].to + 1)).toBe('require("req1")'); + expect(lua.substring(requires[1].from, requires[1].to + 1)).toBe("require('req2')"); + expect(lua.substring(requires[2].from, requires[2].to + 1)).toBe('require("req3")'); +}); + +test("has correct offsets for offsets without parentheses", () => { + const lua = ` + require"req1" + require 'req2' + local r3 = require"req3" + `; + const requires = findLuaRequires(lua); + expect(requires).toHaveLength(3); + expect(lua.substring(requires[0].from, requires[0].to + 1)).toBe('require"req1"'); + expect(lua.substring(requires[1].from, requires[1].to + 1)).toBe("require 'req2'"); + expect(lua.substring(requires[2].from, requires[2].to + 1)).toBe('require"req3"'); +}); + +test("ignores requires that should not be included", () => { + const lua = ` + require("req1") + local a = "require('This should not be included')" + require('req2') + local b = 'require("This should not be included")' + require("req3") + -- require("this should not be included") + require("req4") + --[[ require("this should not be included") ]] + require("req5") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2", "req3", "req4", "req5"]); +}); + +test("non-terminated require", () => { + expect(findLuaRequires("require('abc")).toEqual([]); +}); + +describe.each(['"', "'"])("strings with delimiter %p", delimiter => { + test("escaped delimiter", () => { + const lua = ` + require(${delimiter}req1${delimiter}); + local a = ${delimiter}require(excludeThis\\${delimiter})${delimiter} + require(${delimiter}req\\${delimiter}2${delimiter}); + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", `req${delimiter}2`]); + }); + + test("multiple escaped delimiters", () => { + const lua = ` + require(${delimiter}r\\${delimiter}e.- q%\\${delimiter}1${delimiter}) + `; + expect(requirePaths(findLuaRequires(lua))).toEqual([`r${delimiter}e.- q%${delimiter}1`]); + }); + + test("handles other escaped characters", () => { + expect(requirePaths(findLuaRequires(`require(${delimiter}req\\n\\\\${delimiter})`))).toEqual(["req\\n\\\\"]); + }); + + test("handles non-delimiter quote", () => { + const oppositeDelimiter = delimiter === "'" ? '"' : "'"; + const lua = ` + require(${delimiter}req1${delimiter}); + local a = ${delimiter}require(excludeThis${oppositeDelimiter})${delimiter}; + require(${delimiter}req2${oppositeDelimiter}${delimiter}); + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", `req2${oppositeDelimiter}`]); + }); + + test("non-terminated string", () => { + const lua = ` + require(${delimiter}myRequire${delimiter}); + local a = ${delimiter}require("excludeThis") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["myRequire"]); + }); +}); + +describe("single-line comments", () => { + test("comment at end of file", () => { + expect(findLuaRequires("--")).toEqual([]); + }); + + test("require before and after comment", () => { + const lua = ` + require("req1")-- comment\nrequire("req2") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2"]); + }); + + test("require before and after empty comment", () => { + const lua = ` + require("req1")--\nrequire("req2") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2"]); + }); +}); + +describe("multi-line comments", () => { + test("comment at end of file", () => { + expect(findLuaRequires("--[[]]")).toEqual([]); + }); + + test("unterminated comment", () => { + expect(findLuaRequires("--[[")).toEqual([]); + }); + + test("require before and after comment", () => { + const lua = ` + require("req1")--[[ + ml comment require("this should be excluded") + ]]require("req2") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2"]); + }); + + test("require before and after empty comment", () => { + const lua = ` + require("req1")--[[]]require("req2") + `; + expect(requirePaths(findLuaRequires(lua))).toEqual(["req1", "req2"]); + }); +}); + +function requirePaths(matches: LuaRequire[]): string[] { + return matches.map(m => m.requirePath); +} diff --git a/test/unit/functions/__snapshots__/functions.spec.ts.snap b/test/unit/functions/__snapshots__/functions.spec.ts.snap index 345e31731..83345e13b 100644 --- a/test/unit/functions/__snapshots__/functions.spec.ts.snap +++ b/test/unit/functions/__snapshots__/functions.spec.ts.snap @@ -1,5 +1,39 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Function default parameter with value "null" 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function foo(self, x) + return x + end + return foo(nil) +end +return ____exports" +`; + +exports[`Function default parameter with value "undefined" 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function foo(self, x) + return x + end + return foo(nil) +end +return ____exports" +`; + +exports[`function.length unsupported ("5.0"): code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local function fn(self) + end + return debug.getinfo(fn).nparams - 1 +end +return ____exports" +`; + +exports[`function.length unsupported ("5.0"): diagnostics 1`] = `"main.ts(3,20): error TSTL: function.length is/are not supported for target Lua 5.0."`; + exports[`function.length unsupported ("5.1"): code 1`] = ` "local ____exports = {} function ____exports.__main(self) @@ -10,7 +44,7 @@ end return ____exports" `; -exports[`function.length unsupported ("5.1"): diagnostics 1`] = `"main.ts(3,16): error TSTL: function.length is/are not supported for target Lua 5.1."`; +exports[`function.length unsupported ("5.1"): diagnostics 1`] = `"main.ts(3,20): error TSTL: function.length is/are not supported for target Lua 5.1."`; exports[`function.length unsupported ("universal"): code 1`] = ` "local ____exports = {} @@ -22,7 +56,7 @@ end return ____exports" `; -exports[`function.length unsupported ("universal"): diagnostics 1`] = `"main.ts(3,16): error TSTL: function.length is/are not supported for target Lua 5.1."`; +exports[`function.length unsupported ("universal"): diagnostics 1`] = `"main.ts(3,20): error TSTL: function.length is/are not supported for target Lua universal."`; exports[`missing declaration name: code 1`] = ` "function ____(self) diff --git a/test/unit/functions/__snapshots__/noSelfAnnotation.spec.ts.snap b/test/unit/functions/__snapshots__/noSelfAnnotation.spec.ts.snap index f4e5fdd6d..64eb65457 100644 --- a/test/unit/functions/__snapshots__/noSelfAnnotation.spec.ts.snap +++ b/test/unit/functions/__snapshots__/noSelfAnnotation.spec.ts.snap @@ -13,3 +13,8 @@ exports[`@noSelf on parent class declaration removes context argument 1`] = `"ho exports[`@noSelf on parent interface declaration removes context argument 1`] = `"holder.myMethod()"`; exports[`@noSelf on parent namespace declaration removes context argument 1`] = `"MyNamespace.myMethod()"`; + +exports[`@noSelf on static class methods with string key access 1`] = ` +"TestClass.myMethod() +TestClass.myKey()" +`; diff --git a/test/unit/functions/functionProperties.spec.ts b/test/unit/functions/functionProperties.spec.ts new file mode 100644 index 000000000..85b3ec155 --- /dev/null +++ b/test/unit/functions/functionProperties.spec.ts @@ -0,0 +1,202 @@ +import * as util from "../../util"; + +test("property on function", () => { + util.testFunction` + function foo(s: string) { return s; } + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("property on void function", () => { + util.testFunction` + function foo(this: void, s: string) { return s; } + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("property on recursively referenced function", () => { + util.testFunction` + function foo(s: string) { return s + foo.bar; } + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("property on hoisted function", () => { + util.testFunction` + foo.bar = "bar"; + function foo(s: string) { return s; } + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("function merged with namespace", () => { + util.testModule` + function foo(s: string) { return s; } + namespace foo { + export let bar = "bar"; + } + export const result = foo("foo") + foo.bar; + ` + .setReturnExport("result") + .expectToEqual("foobar"); +}); + +test("function with property assigned to variable", () => { + util.testFunction` + const foo = function(s: string) { return s; }; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("void function with property assigned to variable", () => { + util.testFunction` + const foo = function(this: void, s: string) { return s; }; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("named function with property assigned to variable", () => { + util.testFunction` + const foo = function baz(s: string) { return s; } + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("recursively referenced function with property assigned to variable", () => { + util.testFunction` + const foo = function(s: string) { return s + foo.bar; }; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("named recursively referenced function with property assigned to variable", () => { + util.testFunction` + const foo = function baz(s: string) { return s + foo.bar + baz.bar; }; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("arrow function with property assigned to variable", () => { + util.testFunction` + const foo: { (s: string): string; bar: string; } = s => s; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("void arrow function with property assigned to variable", () => { + util.testFunction` + const foo: { (this: void, s: string): string; bar: string; } = s => s; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("recursively referenced arrow function with property assigned to variable", () => { + util.testFunction` + const foo: { (s: string): string; bar: string; } = s => s + foo.bar; + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); + +test("property on generator function", () => { + util.testFunction` + function *foo(s: string) { yield s; } + foo.bar = "bar"; + for (const s of foo("foo")) { + return s + foo.bar; + } + `.expectToMatchJsResult(); +}); + +test("generator function assigned to variable", () => { + util.testFunction` + const foo = function *(s: string) { yield s; } + foo.bar = "bar"; + for (const s of foo("foo")) { + return s + foo.bar; + } + `.expectToMatchJsResult(); +}); + +test("property on async function", () => { + util.testFunction` + let result = ""; + async function foo(s: string) { result = s + foo.bar; } + foo.bar = "bar"; + void foo("foo"); + return result; + `.expectToMatchJsResult(); +}); + +test("async function with property assigned to variable", () => { + util.testFunction` + let result = ""; + const foo = async function(s: string) { result = s + foo.bar; } + foo.bar = "bar"; + void foo("foo"); + return result; + `.expectToMatchJsResult(); +}); + +test("async arrow function with property assigned to variable", () => { + util.testFunction` + let result = ""; + const foo: { (s: string): Promise; bar: string; } = async s => { result = s + foo.bar; }; + foo.bar = "bar"; + void foo("foo"); + return result; + `.expectToMatchJsResult(); +}); + +test("call function with property using call method", () => { + util.testFunction` + function foo(this: string, s: string) { return this + s; } + foo.baz = "baz"; + return foo.call("foo", "bar") + foo.baz; + `.expectToMatchJsResult(); +}); + +test("call function with property using apply method", () => { + util.testFunction` + function foo(this: string, s: string) { return this + s; } + foo.baz = "baz"; + return foo.apply("foo", ["bar"]) + foo.baz; + `.expectToMatchJsResult(); +}); + +test("call function with property using bind method", () => { + util.testFunction` + function foo(this: string, s: string) { return this + s; } + foo.baz = "baz"; + return foo.bind("foo", "bar")() + foo.baz; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1196 +test("Does not wrap simple variable declaration", () => { + util.testFunction` + function foo(s: string) { return s; } + foo.bar = "bar"; + const foo2 = foo; + return foo2("foo") + foo2.bar; + `.expectToMatchJsResult(); +}); + +test("Wraps function in inner expression", () => { + util.testFunction` + type Foo = { (s: string): string; bar: string; } + const foo = (s => s)! as Foo + foo.bar = "bar"; + return foo("foo") + foo.bar; + `.expectToMatchJsResult(); +}); diff --git a/test/unit/functions/functions.spec.ts b/test/unit/functions/functions.spec.ts index 2d9d8f1e3..27b48a1ee 100644 --- a/test/unit/functions/functions.spec.ts +++ b/test/unit/functions/functions.spec.ts @@ -1,10 +1,11 @@ +import * as ts from "typescript"; import * as tstl from "../../../src"; import * as util from "../../util"; import { unsupportedForTarget } from "../../../src/transformation/utils/diagnostics"; test("Arrow Function Expression", () => { util.testFunction` - const add = (a, b) => a + b; + const add = (a: number, b: number) => a + b; return add(1, 2); `.expectToMatchJsResult(); }); @@ -24,17 +25,22 @@ test.each(["i++", "i--", "++i", "--i"])("Arrow function unary expression (%p)", `.expectToMatchJsResult(); }); -test.each(["b => a = b", "b => a += b", "b => a -= b", "b => a *= b", "b => a /= b", "b => a **= b", "b => a %= b"])( - "Arrow function assignment (%p)", - lambda => { - util.testFunction` +test.each([ + "(b: number) => a = b", + "(b: number) => a += b", + "(b: number) => a -= b", + "(b: number) => a *= b", + "(b: number) => a /= b", + "(b: number) => a **= b", + "(b: number) => a %= b", +])("Arrow function assignment (%p)", lambda => { + util.testFunction` let a = 10; let lambda = ${lambda}; lambda(5); return a; `.expectToMatchJsResult(); - } -); +}); test.each([{ args: [] }, { args: [1] }, { args: [1, 2] }])("Arrow default values (%p)", ({ args }) => { util.testFunction` @@ -45,7 +51,7 @@ test.each([{ args: [] }, { args: [1] }, { args: [1, 2] }])("Arrow default values test("Function Expression", () => { util.testFunction` - let add = function(a, b) {return a+b}; + let add = function(a: number, b: number) {return a+b}; return add(1,2); `.expectToMatchJsResult(); }); @@ -106,6 +112,48 @@ test("Function default binding parameter maintains order", () => { `.expectToMatchJsResult(); }); +test.each(["undefined", "null"])("Function default parameter with value %p", defaultValue => { + util.testFunction` + function foo(x = ${defaultValue}) { + return x; + } + return foo(); + ` + .expectToMatchJsResult() + .tap(builder => { + const lua = builder.getMainLuaCodeChunk(); + expect(lua).not.toMatch("if x == nil then"); + }) + .expectLuaToMatchSnapshot(); +}); + +test("Function default parameter with preceding statements", () => { + util.testFunction` + let i = 1 + function foo(x = i++) { + return x; + } + return [i, foo(), i]; + `.expectToMatchJsResult(); +}); + +test("Function default parameter with nil value and preceding statements", () => { + util.testFunction` + const a = new LuaTable() + a.set("foo", "bar") + function foo(x: any = a.set("foo", "baz")) { + return x ?? "nil"; + } + return [a.get("foo"), foo(), a.get("foo")]; + ` + .withLanguageExtensions() + .tap(builder => { + const lua = builder.getMainLuaCodeChunk(); + expect(lua).not.toMatch(" x = nil"); + }) + .expectToEqual(["bar", "nil", "baz"]); +}); + test("Class method call", () => { util.testFunction` class TestClass { @@ -159,35 +207,62 @@ test("Class static dot method with parameter", () => { `.expectToMatchJsResult(); }); -test("Function bind", () => { +const functionTypeDeclarations = [ + ["arrow", ": (...args: any) => any"], + ["call signature", ": { (...args: any): any; }"], + ["generic", ": Function"], + ["inferred", ""], +]; + +test.each(functionTypeDeclarations)("Function bind (%s)", (_, type) => { util.testFunction` - const abc = function (this: { a: number }, a: string, b: string) { return this.a + a + b; } + const abc${type} = function (this: { a: number }, a: string, b: string) { return this.a + a + b; } return abc.bind({ a: 4 }, "b")("c"); `.expectToMatchJsResult(); }); -test("Function apply", () => { +test.each(functionTypeDeclarations)("Function apply (%s)", (_, type) => { util.testFunction` - const abc = function (this: { a: number }, a: string) { return this.a + a; } + const abc${type} = function (this: { a: number }, a: string) { return this.a + a; } return abc.apply({ a: 4 }, ["b"]); `.expectToMatchJsResult(); }); -test("Function call", () => { +// Fix #1226: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1226 +test.each(functionTypeDeclarations)("function apply without arguments should not lead to exception (%s)", (_, type) => { + util.testFunction` + const f${type} = function (this: number) { return this + 3; } + return f.apply(4); + `.expectToMatchJsResult(); +}); + +// Issue #1218: https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1218 +test.each(["() => 4", "undefined"])("prototype call on nullable function (%p)", value => { util.testFunction` - const abc = function (this: { a: number }, a: string) { return this.a + a; } + function call(f?: () => number) { + return f?.apply(3); + } + return call(${value}); + ` + .setOptions({ strictNullChecks: true }) + .expectToMatchJsResult(); +}); + +test.each(functionTypeDeclarations)("Function call (%s)", (_, type) => { + util.testFunction` + const abc${type} = function (this: { a: number }, a: string) { return this.a + a; } return abc.call({ a: 4 }, "b"); `.expectToMatchJsResult(); }); test.each([ - "function fn() {}", - "function fn(x, y, z) {}", - "function fn(x, y, z, ...args) {}", - "function fn(...args) {}", - "function fn(this: void) {}", - "function fn(this: void, x, y, z) {}", - "function fnReference(x, y, z) {} const fn = fnReference;", + "function fn(): void {}", + "function fn(x: any, y: any, z: any): void {}", + "function fn(x: any, y: any, z: any, ...args: any[]): void {}", + "function fn(...args: any[]): void {}", + "function fn(this: void): void {}", + "function fn(this: void, x: any, y: any, z: any): void {}", + "function fnReference(x: any, y: any, z: any): void {} const fn = fnReference;", "const wrap = (fn: (...args: any[]) => any) => (...args: any[]) => fn(...args); const fn = wrap((x, y, z) => {});", ])("function.length (%p)", declaration => { util.testFunction` @@ -196,14 +271,17 @@ test.each([ `.expectToMatchJsResult(); }); -test.each([tstl.LuaTarget.Lua51, tstl.LuaTarget.Universal])("function.length unsupported (%p)", luaTarget => { - util.testFunction` - function fn() {} - return fn.length; - ` - .setOptions({ luaTarget }) - .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); -}); +test.each([tstl.LuaTarget.Lua50, tstl.LuaTarget.Lua51, tstl.LuaTarget.Universal])( + "function.length unsupported (%p)", + luaTarget => { + util.testFunction` + function fn() {} + return fn.length; + ` + .setOptions({ luaTarget }) + .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); + } +); test("Recursive function definition", () => { util.testFunction` @@ -248,6 +326,14 @@ test("Object method declaration", () => { `.expectToMatchJsResult(); }); +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1266 +test("Object method declaration used with non-null operator (#1266)", () => { + util.testFunction` + let o = { v: 4, m(i: number): number { return this.v * i; } }; + return o.m!(3); + `.expectToMatchJsResult(); +}); + test.each([ { args: ["bar"], expected: "foobar" }, { args: ["baz", "bar"], expected: "bazbar" }, @@ -351,7 +437,7 @@ test("Complex element access call no args", () => { test("Complex element access call statement", () => { util.testFunction` - let foo: string; + let foo: string | undefined; class C { prop = "bar"; method(s: string) { foo = s + this.prop; } @@ -477,3 +563,15 @@ test("top-level function declaration is global", () => { .addExtraFile("a.ts", 'function foo() { return "foo" }') .expectToEqual({ result: "foo" }); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1325 +test("call expression should not throw (#1325)", () => { + util.testModule` + function test(iterator:Iterator) { + iterator.return?.(); + } + ` + // Note: does not reproduce without strict=true + .setOptions({ target: ts.ScriptTarget.ESNext, strict: true }) + .expectToHaveNoDiagnostics(); +}); diff --git a/test/unit/functions/generators.spec.ts b/test/unit/functions/generators.spec.ts index 7065aecf6..6cf935528 100644 --- a/test/unit/functions/generators.spec.ts +++ b/test/unit/functions/generators.spec.ts @@ -1,3 +1,5 @@ +import { LuaTarget } from "../../../src/CompilerOptions"; +import { unsupportedForTarget } from "../../../src/transformation/utils/diagnostics"; import * as util from "../../util"; test("generator parameters", () => { @@ -25,7 +27,7 @@ test(".next()", () => { test(".next() with parameters", () => { util.testFunction` - function* generator() { + function* generator(): Generator { return yield 0; } @@ -147,3 +149,23 @@ test("hoisting", () => { } `.expectToMatchJsResult(); }); + +util.testEachVersion( + "generator yield inside try/catch", + () => util.testFunction` + function* generator() { + try { + yield 4; + } catch { + throw "something went wrong"; + } + } + return generator().next(); + `, + // Cannot execute LuaJIT with test runner + { + ...util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()), + [LuaTarget.Lua50]: builder => builder.expectToHaveDiagnostics([unsupportedForTarget.code]), + [LuaTarget.Lua51]: builder => builder.expectToHaveDiagnostics([unsupportedForTarget.code]), + } +); diff --git a/test/unit/functions/noImplicitGlobalVariables.spec.ts b/test/unit/functions/noImplicitGlobalVariables.spec.ts new file mode 100644 index 000000000..00bd6195a --- /dev/null +++ b/test/unit/functions/noImplicitGlobalVariables.spec.ts @@ -0,0 +1,30 @@ +import * as util from "../../util"; + +test("normal TSTL creates global variables", () => { + const builder = util.testModule` + function foo() {} + const bar = 123; + `.expectToHaveNoDiagnostics(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).not.toContain("local"); +}); + +test("noImplicitGlobalVariables does not create any global variables", () => { + const builder = util.testModule` + function foo() {} + const bar = 123; + ` + .setOptions({ noImplicitGlobalVariables: true }) + .expectToHaveNoDiagnostics(); + + const transpiledFile = builder.getLuaResult().transpiledFiles[0]; + expect(transpiledFile).toBeDefined(); + const { lua } = transpiledFile; + expect(lua).toBeDefined(); + expect(lua).toContain("local function foo("); + expect(lua).toContain("local bar ="); +}); diff --git a/test/unit/functions/noImplicitSelfOption.spec.ts b/test/unit/functions/noImplicitSelfOption.spec.ts index 2da1d9722..ef788c922 100644 --- a/test/unit/functions/noImplicitSelfOption.spec.ts +++ b/test/unit/functions/noImplicitSelfOption.spec.ts @@ -1,3 +1,5 @@ +import * as path from "path"; +import { transpileFiles } from "../../../src"; import { couldNotResolveRequire } from "../../../src/transpilation/diagnostics"; import * as util from "../../util"; @@ -5,11 +7,46 @@ test("enables noSelfInFile behavior for functions", () => { util.testFunction` function fooBar() {} const test: (this: void) => void = fooBar; + fooBar(); ` .setOptions({ noImplicitSelf: true }) .expectToHaveNoDiagnostics(); }); +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1084 +test.each(["\\", "/"])("transpileFiles handles paths with noImplicitSelf and %s separator (#1084)", separator => { + const projectDir = `${path.dirname(path.dirname(__dirname))}${separator}transpile${separator}project`; + const emittedFiles: Record = {}; + const { diagnostics } = transpileFiles( + [ + `${projectDir}${separator}index.ts`, + `${projectDir}${separator}api.d.ts`, + `${projectDir}${separator}otherFile.ts`, + ], + { noImplicitSelf: true }, + (fileName, text) => (emittedFiles[fileName] = text) + ); + expect(diagnostics).toHaveLength(0); + expect(Object.keys(emittedFiles)).not.toHaveLength(0); + for (const fileContent of Object.values(emittedFiles)) { + expect(fileContent).toContain("getNumber()"); + expect(fileContent).not.toContain("getNumber(self)"); + expect(fileContent).not.toContain("getNumber(_G)"); + } +}); + +test("noImplicitSelf does not affect functions in default libraries", () => { + util.testFunction` + const array = [1, 2, 3]; + const items = array.filter(x => x > 1); // array.filter is in external library + return items; + ` + .setOptions({ + noImplicitSelf: true, + }) + .expectToMatchJsResult(); +}); + test("enables noSelfInFile behavior for methods", () => { util.testFunction` class FooBar { @@ -42,3 +79,17 @@ test("generates declaration files with @noSelfInFile", () => { .ignoreDiagnostics([couldNotResolveRequire.code]) // no foo implementation in the project to create foo.lua .expectToHaveNoDiagnostics(); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1292 +test("explicit this parameter respected over noImplicitSelf", () => { + util.testModule` + function foo(this: unknown, arg: any) { + return {self: this, arg}; + } + export const result = foo(1); + ` + .setOptions({ + noImplicitSelf: true, + }) + .expectToMatchJsResult(); +}); diff --git a/test/unit/functions/noSelfAnnotation.spec.ts b/test/unit/functions/noSelfAnnotation.spec.ts index ab77ec03e..e9fbb853d 100644 --- a/test/unit/functions/noSelfAnnotation.spec.ts +++ b/test/unit/functions/noSelfAnnotation.spec.ts @@ -51,3 +51,126 @@ test("@noSelf on parent namespace declaration removes context argument", () => { MyNamespace.myMethod(); `.expectLuaToMatchSnapshot(); }); + +test("@noSelf on static class methods with string key access", () => { + util.testModule` + /** @noSelf */ + declare class TestClass { + static [key: string]: () => void; + static myMethod(): void; + } + + TestClass.myMethod(); + TestClass.myKey(); + `.expectLuaToMatchSnapshot(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1661 +// A Lua-side function observes the actual argc, so a missing @noSelf would +// surface as a phantom leading nil (argc 2 instead of 1). +const argcProbeHeader = ` + function probe(...) + return select("#", ...) + end +`; + +test("@noSelf on interface call signature: Lua probe sees correct argc", () => { + util.testModule` + /** @noSelf */ + interface Probe { (a: string): number; } + declare const probe: Probe; + export const result = probe("hi"); + ` + .setLuaHeader(argcProbeHeader) + .expectToEqual({ result: 1 }); +}); + +test("@noSelf parent interface, property typed by call-signature interface: Lua probe sees correct argc", () => { + util.testModule` + /** @noSelf */ + interface CallSignature { (a: string): number; } + /** @noSelf */ + interface Holder { fn: CallSignature; } + declare const holder: Holder; + export const result = holder.fn("hi"); + ` + .setLuaHeader(`${argcProbeHeader}\nholder = { fn = probe }`) + .expectToEqual({ result: 1 }); +}); + +test("@noSelf parent interface, property typed by type-literal call signature: Lua probe sees correct argc", () => { + util.testModule` + /** @noSelf */ + interface Holder { fn: { (a: string): number }; } + declare const holder: Holder; + export const result = holder.fn("hi"); + ` + .setLuaHeader(`${argcProbeHeader}\nholder = { fn = probe }`) + .expectToEqual({ result: 1 }); +}); + +// additional coverage for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1292 +test("explicit this parameter respected over @noSelf", () => { + util.testModule` + /** @noSelfInFile */ + function foo(this: unknown, arg: any) { + return {self: this, arg}; + } + export const result = foo(1); + `.expectToMatchJsResult(); +}); + +test("respect noSelfInFile over noImplicitSelf", () => { + const result = util.testModule` + /** @noSelfInFile **/ + const func: Function = () => 1; + export const result = func(1); + ` + .expectToMatchJsResult() + .getLuaResult(); + + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("func(1)"); +}); + +test("respect noSelfInFile over noImplicitSelf (func declared in other file)", () => { + const result = util.testModule` + import { func, result } from "./functions"; + + export const result1 = result; + export const result2 = func(1); + ` + .addExtraFile( + "functions.ts", + ` + /** @noSelfInFile **/ + export const func: Function = () => 1; + export const result = func(2); + ` + ) + .expectToMatchJsResult() + .getLuaResult(); + + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath.includes("main.lua")); + expect(mainFile).toBeDefined(); + const functionFile = result.transpiledFiles.find(f => f.outPath.includes("functions.lua")); + expect(functionFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile || !functionFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("func(1)"); + expect(mainFile.lua).toBeDefined(); + expect(functionFile.lua).toContain("func(2)"); +}); diff --git a/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap b/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap index 7ed8e7560..87cb07b9d 100644 --- a/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap +++ b/test/unit/functions/validation/__snapshots__/invalidFunctionAssignments.spec.ts.snap @@ -179,15 +179,15 @@ exports[`Invalid function argument ({"definition": "class NoSelfAnonFuncNSMerged exports[`Invalid function argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"definition": "class NoSelfMethodClass { +exports[`Invalid function argument ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(8,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"definition": "class NoSelfMethodClass { +exports[`Invalid function argument ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(8,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; @@ -249,16 +249,16 @@ exports[`Invalid function argument ({"definition": "interface FuncPropInterface exports[`Invalid function argument ({"definition": "interface MethodInterface { method(this: any, s: string): string; } const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function argument ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { noSelfMethod: function(s: string): string { return s; } };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -340,17 +340,17 @@ exports[`Invalid function argument ({"definition": "namespace NoSelfFuncNs { exports[`Invalid function argument ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function argument ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function argument ({"value": "(function(this: any, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function argument ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function argument ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function argument ({"value": "function(this: any, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function argument ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function argument ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid function argument with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` "main.ts(4,23): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. @@ -571,15 +571,15 @@ exports[`Invalid function assignment ({"definition": "class NoSelfAnonFuncNSMerg exports[`Invalid function assignment ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"definition": "class NoSelfMethodClass { +exports[`Invalid function assignment ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(8,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"definition": "class NoSelfMethodClass { +exports[`Invalid function assignment ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(8,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; @@ -641,16 +641,16 @@ exports[`Invalid function assignment ({"definition": "interface FuncPropInterfac exports[`Invalid function assignment ({"definition": "interface MethodInterface { method(this: any, s: string): string; } const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function assignment ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function assignment ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { noSelfMethod: function(s: string): string { return s; } };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(10,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function assignment ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -732,17 +732,17 @@ exports[`Invalid function assignment ({"definition": "namespace NoSelfFuncNs { exports[`Invalid function assignment ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function assignment ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function assignment ({"value": "(function(this: any, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function assignment ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function assignment ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function assignment ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function assignment ({"value": "function(this: any, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function assignment ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function assignment ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function assignment ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function assignment ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 2`] = `"main.ts(4,18): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid function assignment with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` "main.ts(4,14): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. @@ -963,15 +963,15 @@ exports[`Invalid function generic argument ({"definition": "class NoSelfAnonFunc exports[`Invalid function generic argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"definition": "class NoSelfMethodClass { +exports[`Invalid function generic argument ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(8,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"definition": "class NoSelfMethodClass { +exports[`Invalid function generic argument ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(8,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; @@ -1033,16 +1033,16 @@ exports[`Invalid function generic argument ({"definition": "interface FuncPropIn exports[`Invalid function generic argument ({"definition": "interface MethodInterface { method(this: any, s: string): string; } const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function generic argument ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function generic argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { noSelfMethod: function(s: string): string { return s; } };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(10,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function generic argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -1124,17 +1124,17 @@ exports[`Invalid function generic argument ({"definition": "namespace NoSelfFunc exports[`Invalid function generic argument ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function generic argument ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function generic argument ({"value": "(function(this: any, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function generic argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function generic argument ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function generic argument ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function generic argument ({"value": "function(this: any, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function generic argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function generic argument ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function generic argument ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function generic argument ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 2`] = `"main.ts(4,27): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid function overload assignment ("(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(7,52): error TSTL: Unsupported assignment of function with different overloaded types for 'this'. Overloads should all have the same type for 'this'."`; @@ -1323,15 +1323,15 @@ exports[`Invalid function return ({"definition": "class NoSelfAnonFuncNSMergedCl exports[`Invalid function return ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(5,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"definition": "class NoSelfMethodClass { +exports[`Invalid function return ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(8,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"definition": "class NoSelfMethodClass { +exports[`Invalid function return ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(8,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; @@ -1393,16 +1393,16 @@ exports[`Invalid function return ({"definition": "interface FuncPropInterface { exports[`Invalid function return ({"definition": "interface MethodInterface { method(this: any, s: string): string; } const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function return ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function return ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { noSelfMethod: function(s: string): string { return s; } };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(10,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function return ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -1484,17 +1484,17 @@ exports[`Invalid function return ({"definition": "namespace NoSelfFuncNs { exports[`Invalid function return ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(5,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function return ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function return ({"value": "(function(this: any, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function return ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function return ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function return ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function return ({"value": "function(this: any, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function return ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function return ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function return ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function return ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 2`] = `"main.ts(4,17): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid function return with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}): diagnostics 1`] = ` "main.ts(4,17): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. @@ -1538,9 +1538,10 @@ main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter t exports[`Invalid function tuple assignment: diagnostics 1`] = ` "main.ts(5,13): error TS2322: Type '[number, Meth]' is not assignable to type '[number, Func]'. - Type 'Meth' is not assignable to type 'Func'. - The 'this' types of each signature are incompatible. - Type 'void' is not assignable to type '{}'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'Meth' is not assignable to type 'Func'. + The 'this' types of each signature are incompatible. + Type 'void' is not assignable to type '{}'. main.ts(5,38): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." `; @@ -1723,15 +1724,15 @@ exports[`Invalid function variable declaration ({"definition": "class NoSelfAnon exports[`Invalid function variable declaration ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}): diagnostics 2`] = `"main.ts(4,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"definition": "class NoSelfMethodClass { +exports[`Invalid function variable declaration ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 1`] = `"main.ts(7,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"definition": "class NoSelfMethodClass { +exports[`Invalid function variable declaration ({"definition": "class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}): diagnostics 2`] = `"main.ts(7,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; @@ -1793,16 +1794,16 @@ exports[`Invalid function variable declaration ({"definition": "interface FuncPr exports[`Invalid function variable declaration ({"definition": "interface MethodInterface { method(this: any, s: string): string; } const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function variable declaration ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function variable declaration ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { noSelfMethod: function(s: string): string { return s; } };", "value": "noSelfMethodInterface.noSelfMethod"}): diagnostics 1`] = `"main.ts(9,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"definition": "interface NoSelfMethodInterface { - /** @noSelf */ +exports[`Invalid function variable declaration ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -1884,20 +1885,1167 @@ exports[`Invalid function variable declaration ({"definition": "namespace NoSelf exports[`Invalid function variable declaration ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}): diagnostics 1`] = `"main.ts(4,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function variable declaration ({"value": "(function(this: any, s) { return s; })"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function variable declaration ({"value": "(function(this: any, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function variable declaration ({"value": "(function(this: void, s) { return s; })"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function variable declaration ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"value": "(function(this: void, s) { return s; })"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function variable declaration ({"value": "(function(this: void, s: string) { return s; })"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"value": "function(this: any, s) { return s; }"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; +exports[`Invalid function variable declaration ({"value": "function(this: any, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(3,59): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; -exports[`Invalid function variable declaration ({"value": "function(this: void, s) { return s; }"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function variable declaration ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 1`] = `"main.ts(3,47): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; -exports[`Invalid function variable declaration ({"value": "function(this: void, s) { return s; }"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; +exports[`Invalid function variable declaration ({"value": "function(this: void, s: string) { return s; }"}): diagnostics 2`] = `"main.ts(3,58): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid interface method assignment: diagnostics 1`] = `"main.ts(5,22): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; exports[`Invalid lua lib function argument: diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'callbackfn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; exports[`Invalid method tuple assignment: diagnostics 1`] = `"main.ts(5,38): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(10,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(10,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(9,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(11,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(8,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(8,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(7,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(10,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(10,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(9,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(9,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(9,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(9,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"value": "(function(this: any, s: string) { return s; })"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"value": "(function(this: void, s: string) { return s; })"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"value": "(function(this: void, s: string) { return s; })"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"value": "function(this: any, s: string) { return s; }"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with a 'this' parameter to function 'obj.fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method argument ({"value": "function(this: void, s: string) { return s; }"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method argument ({"value": "function(this: void, s: string) { return s; }"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,35): error TSTL: Unable to convert function with no 'this' parameter to function 'obj.fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(10,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(10,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(9,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(11,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(8,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(8,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(7,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(10,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(10,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(9,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(9,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(9,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(9,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(6,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(5,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"value": "(function(this: any, s: string) { return s; })"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"value": "(function(this: void, s: string) { return s; })"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"value": "(function(this: void, s: string) { return s; })"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"value": "function(this: any, s: string) { return s; }"}, "(this: void, s: string) => string", false): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method assignment ({"value": "function(this: void, s: string) { return s; }"}, "(s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment ({"value": "function(this: void, s: string) { return s; }"}, "(this: any, s: string) => string", true): diagnostics 1`] = `"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method assignment with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(noSelfInFileFunc) as ((this: any, s: string) => string)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "<(this: any, s: string) => string>(noSelfInFileFunc)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}, "(selfFunc) as ((this: void, s: string) => string)", true): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'. +main.ts(4,24): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}, "<(this: void, s: string) => string>(selfFunc)", true): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'. +main.ts(4,24): error TSTL: Unable to convert function with a 'this' parameter to function with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(voidFunc) as ((s: string) => string)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(voidFunc) as ((this: any, s: string) => string)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "<(s: string) => string>(voidFunc)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method assignment with cast ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "<(this: any, s: string) => string>(voidFunc)", false): diagnostics 1`] = ` +"main.ts(4,19): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'. +main.ts(4,24): error TSTL: Unable to convert function with no 'this' parameter to function with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'." +`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class AnonFuncNSMergedNoSelfClass { method(s: string): string { return s; } } + namespace AnonFuncNSMergedNoSelfClass { export function nsFunc(s: string) { return s; } }", "value": "AnonFuncNSMergedNoSelfClass.nsFunc"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();", "value": "anonFunctionNestedInNoSelfClass"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(6,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfAnonMethodClassMergedNS { method(s: string): string { return s; } } + namespace NoSelfAnonMethodClassMergedNS { export function nsFunc(s: string) { return s; } } + const noSelfAnonMethodClassMergedNS = new NoSelfAnonMethodClassMergedNS();", "value": "noSelfAnonMethodClassMergedNS.method"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(4,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();", "value": "noSelfFuncPropClass.noSelfFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(4,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(4,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(4,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }", "value": "NoSelfStaticFuncPropClass.noSelfStaticFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }", "value": "NoSelfStaticMethodClass.noSelfStaticMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();", "value": "noSelfMethodClassExpression.noSelfMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };", "value": "noSelfFuncPropInterface.noSelfFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(9,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();", "value": "anonFunctionNestedInClassInNoSelfNs"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(9,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();", "value": "anonMethodClassInNoSelfNs.method"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(8,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };", "value": "anonMethodInterfaceInNoSelfNs.method"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(10,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }", "value": "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }", "value": "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfLambdaNs.noSelfNsLambda"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();", "value": "noSelfInFileFuncNestedInClass"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };", "value": "noSelfInFileFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;", "value": "noSelfInFileLambda"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }", "value": "NoSelfInFileFuncNs.noSelfInFileNsFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }", "value": "NoSelfInFileLambdaNs.noSelfInFileNsLambda"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();", "value": "anonFuncPropClass.anonFuncProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();", "value": "anonMethodClass.anonMethod"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class AnonMethodClassMergedNoSelfNS { method(s: string): string { return s; } } + /** @noSelf */ namespace AnonMethodClassMergedNoSelfNS { export function nsFunc(s: string) { return s; } } + const anonMethodClassMergedNoSelfNS = new AnonMethodClassMergedNoSelfNS();", "value": "anonMethodClassMergedNoSelfNS.method"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }", "value": "AnonStaticFuncPropClass.anonStaticFuncProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }", "value": "AnonStaticMethodClass.anonStaticMethod"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();", "value": "funcPropClass.funcProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();", "value": "methodClass.method"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(4,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class NoSelfAnonFuncNSMergedClass { method(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedClass { export function nsFunc(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedClass.nsFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(4,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(7,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class NoSelfMethodClass { + /** @noSelf */ + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClass = new NoSelfMethodClass();", "value": "noSelfMethodClass.noSelfMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(7,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }", "value": "StaticFuncPropClass.staticFuncProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }", "value": "StaticMethodClass.staticMethod"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }", "value": "StaticVoidFuncPropClass.staticVoidFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }", "value": "StaticVoidMethodClass.staticVoidMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();", "value": "voidFuncPropClass.voidFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(6,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();", "value": "voidMethodClass.voidMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(6,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };", "value": "anonFuncPropInterface.anonFuncProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };", "value": "anonMethodInterface.anonMethod"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(6,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };", "value": "funcPropInterface.funcProp"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } };", "value": "methodInterface.method"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(9,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface NoSelfMethodInterface { + /** @noSelf */ + noSelfMethod(s: string): string; + } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };", "value": "noSelfMethodInterface.noSelfMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(9,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(8,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };", "value": "voidFuncPropInterface.voidFuncProp"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(8,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(8,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };", "value": "voidMethodInterface.voidMethod"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(8,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let anonFunc: {(s: string): string} = function(s) { return s; };", "value": "anonFunc"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let anonLambda: (s: string) => string = s => s;", "value": "anonLambda"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let selfFunc: {(this: any, s: string): string} = function(s) { return s; };", "value": "selfFunc"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let selfLambda: (this: any, s: string) => string = s => s;", "value": "selfLambda"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let voidFunc: {(this: void, s: string): string} = function(s) { return s; };", "value": "voidFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "let voidLambda: (this: void, s: string) => string = s => s;", "value": "voidLambda"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }", "value": "FuncNestedNs.NestedNs.nestedNsFunc"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace FuncNs { export function nsFunc(s: string) { return s; } }", "value": "FuncNs.nsFunc"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }", "value": "LambdaNestedNs.NestedNs.nestedNsLambda"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }", "value": "LambdaNs.nsLambda"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(5,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(4,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace NoSelfAnonFuncNSMergedSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "NoSelfAnonFuncNSMergedSelfNS.nsFuncNoSelf"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(4,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(5,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace NoSelfFuncNs { + /** @noSelf */ + export function noSelfNsFunc(s: string) { return s; } }", "value": "NoSelfFuncNs.noSelfNsFunc"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(5,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"definition": "namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncSelf(s: string): string { return s; } } + /** @noSelf */ namespace SelfAnonFuncNSMergedNoSelfNS { export function nsFuncNoSelf(s: string) { return s; } }", "value": "SelfAnonFuncNSMergedNoSelfNS.nsFuncSelf"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(4,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"value": "(function(this: any, s: string) { return s; })"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"value": "(function(this: void, s: string) { return s; })"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"value": "(function(this: void, s: string) { return s; })"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"value": "function(this: any, s: string) { return s; }"}, "(this: void, s: string) => string"): diagnostics 1`] = `"main.ts(3,68): error TSTL: Unable to convert function with a 'this' parameter to function 'fn' with no 'this'. To fix, wrap in an arrow function, or declare with 'this: void'."`; + +exports[`Invalid object with method variable declaration ({"value": "function(this: void, s: string) { return s; }"}, "(s: string) => string"): diagnostics 1`] = `"main.ts(3,56): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; + +exports[`Invalid object with method variable declaration ({"value": "function(this: void, s: string) { return s; }"}, "(this: any, s: string) => string"): diagnostics 1`] = `"main.ts(3,67): error TSTL: Unable to convert function with no 'this' parameter to function 'fn' with 'this'. To fix, wrap in an arrow function, or declare with 'this: any'."`; diff --git a/test/unit/functions/validation/functionExpressionTypeInference.spec.ts b/test/unit/functions/validation/functionExpressionTypeInference.spec.ts index abac4e483..9220902b2 100644 --- a/test/unit/functions/validation/functionExpressionTypeInference.spec.ts +++ b/test/unit/functions/validation/functionExpressionTypeInference.spec.ts @@ -79,7 +79,7 @@ test.each([ test("Function expression type inference in object literal assigned to narrower type", () => { util.testFunction` - let foo: {} = {bar: s => s}; + let foo: {} = {bar: (s: string) => s}; return (foo as {bar: (a: any) => any}).bar("foobar"); `.expectToMatchJsResult(); }); diff --git a/test/unit/functions/validation/functionPermutations.ts b/test/unit/functions/validation/functionPermutations.ts index f95af8ab3..4947bc9a4 100644 --- a/test/unit/functions/validation/functionPermutations.ts +++ b/test/unit/functions/validation/functionPermutations.ts @@ -221,9 +221,9 @@ export const noSelfTestFunctions: TestFunction[] = [ }, { value: "noSelfMethodClass.noSelfMethod", - definition: `class NoSelfMethodClass { + definition: `class NoSelfMethodClass { /** @noSelf */ - noSelfMethod(s: string): string { return s; } + noSelfMethod(s: string): string { return s; } } const noSelfMethodClass = new NoSelfMethodClass();`, }, @@ -271,8 +271,8 @@ export const noSelfTestFunctions: TestFunction[] = [ }, { value: "noSelfMethodInterface.noSelfMethod", - definition: `interface NoSelfMethodInterface { - /** @noSelf */ + definition: `interface NoSelfMethodInterface { + /** @noSelf */ noSelfMethod(s: string): string; } const noSelfMethodInterface: NoSelfMethodInterface = { @@ -352,20 +352,20 @@ const noSelfInFileTestFunctions: TestFunction[] = [ ]; export const anonTestFunctionExpressions: TestFunction[] = [ - { value: "s => s" }, - { value: "(s => s)" }, - { value: "function(s) { return s; }" }, - { value: "(function(s) { return s; })" }, + { value: "(s: string) => s" }, + { value: "((s: string) => s)" }, + { value: "function(s: string) { return s; }" }, + { value: "(function(s: string) { return s; })" }, ]; export const selfTestFunctionExpressions: TestFunction[] = [ - { value: "function(this: any, s) { return s; }" }, - { value: "(function(this: any, s) { return s; })" }, + { value: "function(this: any, s: string) { return s; }" }, + { value: "(function(this: any, s: string) { return s; })" }, ]; export const noSelfTestFunctionExpressions: TestFunction[] = [ - { value: "function(this: void, s) { return s; }" }, - { value: "(function(this: void, s) { return s; })" }, + { value: "function(this: void, s: string) { return s; }" }, + { value: "(function(this: void, s: string) { return s; })" }, ]; export const anonTestFunctionType = "(s: string) => string"; @@ -377,18 +377,21 @@ type TestFunctionCast = [ /* castedFunction: */ string, /* isSelfConversion?: */ boolean? ]; -export const validTestFunctionCasts: TestFunctionCast[] = [ +export const validTestMethodCasts: TestFunctionCast[] = [ [selfTestFunctions[0], `<${anonTestFunctionType}>(${selfTestFunctions[0].value})`], [selfTestFunctions[0], `(${selfTestFunctions[0].value}) as (${anonTestFunctionType})`], [selfTestFunctions[0], `<${selfTestFunctionType}>(${selfTestFunctions[0].value})`], [selfTestFunctions[0], `(${selfTestFunctions[0].value}) as (${selfTestFunctionType})`], [noSelfTestFunctions[0], `<${noSelfTestFunctionType}>(${noSelfTestFunctions[0].value})`], [noSelfTestFunctions[0], `(${noSelfTestFunctions[0].value}) as (${noSelfTestFunctionType})`], - [noSelfInFileTestFunctions[0], `<${anonTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`], - [noSelfInFileTestFunctions[0], `(${noSelfInFileTestFunctions[0].value}) as (${anonTestFunctionType})`], [noSelfInFileTestFunctions[0], `<${noSelfTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`], [noSelfInFileTestFunctions[0], `(${noSelfInFileTestFunctions[0].value}) as (${noSelfTestFunctionType})`], ]; +export const validTestFunctionCasts: TestFunctionCast[] = [ + ...validTestMethodCasts, + [noSelfInFileTestFunctions[0], `<${anonTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`], + [noSelfInFileTestFunctions[0], `(${noSelfInFileTestFunctions[0].value}) as (${anonTestFunctionType})`], +]; export const invalidTestFunctionCasts: TestFunctionCast[] = [ [noSelfTestFunctions[0], `<${anonTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], [noSelfTestFunctions[0], `(${noSelfTestFunctions[0].value}) as (${anonTestFunctionType})`, false], @@ -405,11 +408,10 @@ export type TestFunctionAssignment = [ /* functionType: */ string, /* isSelfConversion?: */ boolean? ]; -export const validTestFunctionAssignments: TestFunctionAssignment[] = [ +export const validTestMethodAssignments: TestFunctionAssignment[] = [ ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), ...selfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), - ...noSelfInFileTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), ...noSelfInFileTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), ...anonTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), ...anonTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), @@ -418,6 +420,10 @@ export const validTestFunctionAssignments: TestFunctionAssignment[] = [ ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), ]; +export const validTestFunctionAssignments: TestFunctionAssignment[] = [ + ...validTestMethodAssignments, + ...noSelfInFileTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), +]; export const invalidTestFunctionAssignments: TestFunctionAssignment[] = [ ...selfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType, false]), ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), @@ -427,3 +433,7 @@ export const invalidTestFunctionAssignments: TestFunctionAssignment[] = [ ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), ]; +export const invalidTestMethodAssignments: TestFunctionAssignment[] = [ + ...invalidTestFunctionAssignments, + ...noSelfInFileTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), +]; diff --git a/test/unit/functions/validation/invalidFunctionAssignments.spec.ts b/test/unit/functions/validation/invalidFunctionAssignments.spec.ts index cd12b4ba8..2b9fd61db 100644 --- a/test/unit/functions/validation/invalidFunctionAssignments.spec.ts +++ b/test/unit/functions/validation/invalidFunctionAssignments.spec.ts @@ -4,7 +4,11 @@ import { unsupportedSelfFunctionConversion, } from "../../../../src/transformation/utils/diagnostics"; import * as util from "../../../util"; -import { invalidTestFunctionAssignments, invalidTestFunctionCasts } from "./functionPermutations"; +import { + invalidTestFunctionAssignments, + invalidTestFunctionCasts, + invalidTestMethodAssignments, +} from "./functionPermutations"; test.each(invalidTestFunctionAssignments)( "Invalid function variable declaration (%p)", @@ -19,6 +23,19 @@ test.each(invalidTestFunctionAssignments)( } ); +test.each(invalidTestMethodAssignments)( + "Invalid object with method variable declaration (%p, %p)", + (testFunction, functionType, isSelfConversion) => { + util.testModule` + ${testFunction.definition ?? ""} + const obj: { fn: ${functionType} } = {fn: ${testFunction.value}}; + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); + } +); + test.each(invalidTestFunctionAssignments)( "Invalid function assignment (%p)", (testFunction, functionType, isSelfConversion) => { @@ -33,6 +50,20 @@ test.each(invalidTestFunctionAssignments)( } ); +test.each(invalidTestMethodAssignments)( + "Invalid object with method assignment (%p, %p, %p)", + (testFunction, functionType, isSelfConversion) => { + util.testModule` + ${testFunction.definition ?? ""} + let obj: { fn: ${functionType} }; + obj = {fn: ${testFunction.value}}; + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); + } +); + test.each(invalidTestFunctionCasts)("Invalid function assignment with cast (%p)", (testFunction, castedFunction) => { util.testModule` ${testFunction.definition ?? ""} @@ -44,12 +75,28 @@ test.each(invalidTestFunctionCasts)("Invalid function assignment with cast (%p)" ); }); +test.each(invalidTestFunctionCasts)( + "Invalid object with method assignment with cast (%p, %p, %p)", + (testFunction, castedFunction, isSelfConversion) => { + util.testModule` + ${testFunction.definition ?? ""} + let obj: { fn: typeof ${testFunction.value} }; + obj = {fn: ${castedFunction}}; + `.expectDiagnosticsToMatchSnapshot( + isSelfConversion + ? [unsupportedSelfFunctionConversion.code, unsupportedNoSelfFunctionConversion.code] + : [unsupportedNoSelfFunctionConversion.code, unsupportedSelfFunctionConversion.code], + true + ); + } +); + test.each(invalidTestFunctionAssignments)( "Invalid function argument (%p)", (testFunction, functionType, isSelfConversion) => { util.testModule` ${testFunction.definition ?? ""} - declare function takesFunction(fn: ${functionType}); + declare function takesFunction(fn: ${functionType}): void; takesFunction(${testFunction.value}); `.expectDiagnosticsToMatchSnapshot( [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], @@ -58,6 +105,20 @@ test.each(invalidTestFunctionAssignments)( } ); +test.each(invalidTestMethodAssignments)( + "Invalid object with method argument (%p, %p, %p)", + (testFunction, functionType, isSelfConversion) => { + util.testModule` + ${testFunction.definition ?? ""} + declare function takesObjectWithMethod(obj: { fn: ${functionType} }): void; + takesObjectWithMethod({fn: ${testFunction.value}}); + `.expectDiagnosticsToMatchSnapshot( + [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], + true + ); + } +); + test("Invalid lua lib function argument", () => { util.testModule` declare function foo(this: void, value: string): void; @@ -69,7 +130,7 @@ test("Invalid lua lib function argument", () => { test.each(invalidTestFunctionCasts)("Invalid function argument with cast (%p)", (testFunction, castedFunction) => { util.testModule` ${testFunction.definition ?? ""} - declare function takesFunction(fn: typeof ${testFunction.value}); + declare function takesFunction(fn: typeof ${testFunction.value}): void; takesFunction(${castedFunction}); `.expectDiagnosticsToMatchSnapshot( [unsupportedNoSelfFunctionConversion.code, unsupportedSelfFunctionConversion.code], @@ -82,7 +143,7 @@ test.each(invalidTestFunctionAssignments)( (testFunction, functionType, isSelfConversion) => { util.testModule` ${testFunction.definition ?? ""} - declare function takesFunction(fn: T); + declare function takesFunction(fn: T): void; takesFunction(${testFunction.value}); `.expectDiagnosticsToMatchSnapshot( [isSelfConversion ? unsupportedSelfFunctionConversion.code : unsupportedNoSelfFunctionConversion.code], @@ -165,3 +226,18 @@ test.each([ let f: ${assignType} = o; `.expectDiagnosticsToMatchSnapshot([unsupportedOverloadAssignment.code], true); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/896 +test("Does not fail on union type signatures (#896)", () => { + util.testExpression`foo<'a'>(() => {});` + .setTsHeader( + ` + declare interface Events { + a(): void; + [key: string]: (this: void) => void; + } + declare function foo(callback: Events[T]): void; + ` + ) + .expectToHaveDiagnostics([unsupportedOverloadAssignment.code]); +}); diff --git a/test/unit/functions/validation/validFunctionAssignments.spec.ts b/test/unit/functions/validation/validFunctionAssignments.spec.ts index d9613692d..525b95929 100644 --- a/test/unit/functions/validation/validFunctionAssignments.spec.ts +++ b/test/unit/functions/validation/validFunctionAssignments.spec.ts @@ -12,6 +12,8 @@ import { TestFunctionAssignment, validTestFunctionAssignments, validTestFunctionCasts, + validTestMethodAssignments, + validTestMethodCasts, } from "./functionPermutations"; test.each(validTestFunctionAssignments)("Valid function variable declaration (%p)", (testFunction, functionType) => { @@ -23,6 +25,15 @@ test.each(validTestFunctionAssignments)("Valid function variable declaration (%p .expectToMatchJsResult(); }); +test.each(validTestMethodAssignments)("Valid object wit method declaration (%p, %p)", (testFunction, functionType) => { + util.testFunction` + const obj: { fn: ${functionType} } = {fn: ${testFunction.value}}; + return obj.fn("foobar"); + ` + .setTsHeader(testFunction.definition ?? "") + .expectToMatchJsResult(); +}); + test.each(validTestFunctionAssignments)("Valid function assignment (%p)", (testFunction, functionType) => { util.testFunction` let fn: ${functionType}; @@ -43,6 +54,19 @@ test.each(validTestFunctionCasts)("Valid function assignment with cast (%p)", (t .expectToMatchJsResult(); }); +test.each(validTestMethodCasts)( + "Valid object with method assignment with cast (%p, %p)", + (testFunction, castedFunction) => { + util.testFunction` + let obj: { fn: typeof ${testFunction.value} }; + obj = {fn: ${castedFunction}}; + return obj.fn("foobar"); + ` + .setTsHeader(testFunction.definition ?? "") + .expectToMatchJsResult(); + } +); + test.each(validTestFunctionAssignments)("Valid function argument (%p)", (testFunction, functionType) => { util.testFunction` function takesFunction(fn: ${functionType}) { @@ -54,6 +78,17 @@ test.each(validTestFunctionAssignments)("Valid function argument (%p)", (testFun .expectToMatchJsResult(); }); +test.each(validTestMethodAssignments)("Valid object with method argument (%p, %p)", (testFunction, functionType) => { + util.testFunction` + function takesObjectWithMethod(obj: { fn: ${functionType} }) { + return obj.fn("foobar"); + } + return takesObjectWithMethod({fn: ${testFunction.value}}); + ` + .setTsHeader(testFunction.definition ?? "") + .expectToMatchJsResult(); +}); + test("Valid lua lib function argument", () => { util.testFunction` let result = ""; @@ -198,3 +233,35 @@ test.each([ return f(${args.map(a => '"' + a + '"').join(", ")}); `.expectToMatchJsResult(); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/896 +test("Does not fail on union type signatures (#896)", () => { + util.testExpression`foo<'a'>(() => {});` + .setTsHeader( + ` + declare interface Events { + a(): void; + [key: string]: Function; + } + declare function foo(callback: Events[T]): void; + ` + ) + .expectToHaveNoDiagnostics(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1568 +test("No false positives when using generic functions (#1568)", () => { + util.testModule` + /** @noSelf */ + declare namespace Test { + export function testCallback void>( + callback: T, + ): void; + } + + Test.testCallback(() => {}); + + const f = () => {}; + Test.testCallback(f); + `.expectToHaveNoDiagnostics(); +}); diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index 144460067..e08a7c083 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -254,7 +254,7 @@ test("Hoisting variable without initializer", () => { function foo() { return x; } - let x: number; + let x: number | undefined; return foo(); `.expectToMatchJsResult(); }); diff --git a/test/unit/identifiers.spec.ts b/test/unit/identifiers.spec.ts index 9f72ad671..ddac778fc 100644 --- a/test/unit/identifiers.spec.ts +++ b/test/unit/identifiers.spec.ts @@ -1,3 +1,4 @@ +import { LuaTarget } from "../../src"; import { invalidAmbientIdentifierName } from "../../src/transformation/utils/diagnostics"; import { luaKeywords } from "../../src/transformation/utils/safe-names"; import * as util from "../util"; @@ -92,9 +93,8 @@ test.each([ "const foo: any, bar: any, $$$: any;", "class $$$ {}", "namespace $$$ { export const bar: any; }", - "module $$$ { export const bar: any; }", "enum $$$ {}", - "function $$$();", + "function $$$(): void;", ])("ambient identifier must be a valid lua identifier (%p)", statement => { util.testModule` declare ${statement} @@ -195,7 +195,7 @@ test.each(validTsInvalidLuaNames)("class with invalid lua name has correct name test.each(validTsInvalidLuaNames)("decorated class with invalid lua name", name => { util.testFunction` - function decorator any>(Class: T): T { + function decorator any>(Class: T, context: ClassDecoratorContext): T { return class extends Class { public bar = "foobar"; }; @@ -209,7 +209,7 @@ test.each(validTsInvalidLuaNames)("decorated class with invalid lua name", name test.each(validTsInvalidLuaNames)("exported decorated class with invalid lua name", name => { util.testModule` - function decorator any>(Class: T): T { + function decorator any>(Class: T, context: ClassDecoratorContext): T { return class extends Class { public bar = "foobar"; }; @@ -222,6 +222,111 @@ test.each(validTsInvalidLuaNames)("exported decorated class with invalid lua nam .expectToMatchJsResult(); }); +describe("unicode identifiers in supporting environments (luajit)", () => { + const unicodeNames = ["𝛼𝛽𝚫", "ɥɣɎɌͼƛಠ", "_̀ः٠‿"]; + + test.each(unicodeNames)("identifier name (%p)", name => { + util.testFunction` + const ${name} = "foobar"; + return ${name}; + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); + + test.each(unicodeNames)("property name (%p)", name => { + util.testFunction` + const x = { ${name}: "foobar" }; + return x.${name}; + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); + + test.each(unicodeNames)("destructuring property name (%p)", name => { + util.testFunction` + const { foo: ${name} } = { foo: "foobar" }; + return ${name}; + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); + + test.each(unicodeNames)("destructuring shorthand (%p)", name => { + util.testFunction` + const { ${name} } = { ${name}: "foobar" }; + return ${name}; + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); + + test.each(unicodeNames)("function (%p)", name => { + util.testFunction` + function ${name}(arg: string) { + return "foo" + arg; + } + return ${name}("bar"); + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); + + test.each(unicodeNames)("method (%p)", name => { + util.testFunction` + const foo = { + ${name}(arg: string) { return "foo" + arg; } + }; + return foo.${name}("bar"); + ` + .setOptions({ luaTarget: LuaTarget.LuaJIT }) + .expectLuaToMatchSnapshot(); + }); +}); + +test("unicode export class", () => { + util.testModule` + import { 你好 } from "./utfclass"; + export const result = new 你好().hello(); + ` + .addExtraFile( + "utfclass.ts", + `export class 你好 { + hello() { + return "你好"; + } + }` + ) + .expectToEqual({ result: "你好" }); +}); + +test("unicode export default class", () => { + util.testModule` + import c from "./utfclass"; + export const result = new c().hello(); + ` + .addExtraFile( + "utfclass.ts", + `export default class 你好 { + hello() { + return "你好"; + } + }` + ) + .expectToEqual({ result: "你好" }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1645 +test("unicode static initialization block (#1645)", () => { + util.testModule` + export default class 自定义异能 { + static { + let a = 1; + } + } + `.expectLuaToMatchSnapshot(); +}); + describe("lua keyword as identifier doesn't interfere with lua's value", () => { test("variable (nil)", () => { util.testFunction` @@ -239,7 +344,7 @@ describe("lua keyword as identifier doesn't interfere with lua's value", () => { test("variable (elseif)", () => { util.testFunction` - const elseif = "foobar"; + const elseif: string | undefined = "foobar"; if (false) { } else if (elseif) { return elseif; @@ -287,7 +392,7 @@ describe("lua keyword as identifier doesn't interfere with lua's value", () => { test("variable (then)", () => { util.testFunction` - const then = "foobar"; + const then: string | undefined = "foobar"; if (then) { return then; } @@ -482,6 +587,15 @@ describe("lua keyword as identifier doesn't interfere with lua's value", () => { expect(luaResult).toBe("foobar"); }); + test("variable (bit32)", () => { + util.testFunction` + const bit32 = 1; + return bit32 << 1; + ` + .setOptions({ luaTarget: LuaTarget.Lua52 }) + .expectToMatchJsResult(); + }); + test("variable (_G)", () => { util.testFunction` const _G = "bar"; @@ -750,3 +864,193 @@ test("lua built-in as in constructor assignment", () => { export const result = new A("42").error; `.expectToMatchJsResult(); }); + +test("customName rename function", () => { + const result = util.testModule` + /** @customName test2 **/ + function test(this: void): number { return 3; } + export const result: number = test(); + ` + .expectToEqual({ result: 3 }) + .getLuaResult(); + + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("function test2()"); + expect(mainFile.lua).not.toContain("test()"); +}); + +test("customName rename variable", () => { + const result = util.testModule` + /** @customName result2 **/ + export const result: number = 3; + ` + .expectToEqual({ result2: 3 }) + .getLuaResult(); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("result2 ="); + expect(mainFile.lua).not.toContain("result ="); +}); + +test("customName rename classes", () => { + const testModule = util.testModule` + /** @customName Class2 **/ + class Class { + test: string; + + constructor(test: string) { + this.test = test; + } + } + + export const result = new Class("hello world"); + `; + + const executionResult = testModule.getLuaExecutionResult(); + expect(executionResult.result).toBeDefined(); + expect(executionResult.result).toMatchObject({ test: "hello world" }); + + const result = testModule.getLuaResult(); + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("local Class2 ="); + expect(mainFile.lua).not.toContain("local Class ="); +}); + +test("customName rename namespace", () => { + const testModule = util.testModule` + /** @customName Test2 **/ + namespace Test { + /** @customName Func2 **/ + export function Func(): string { + return "hi"; + } + } + + export const result = Test.Func(); + `; + + testModule.expectToEqual({ result: "hi" }); + + const result = testModule.getLuaResult(); + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("Test2 ="); + expect(mainFile.lua).toContain("Test2.Func2"); + expect(mainFile.lua).not.toContain("Test ="); + expect(mainFile.lua).not.toContain("Func("); +}); + +test("customName rename declared function", () => { + const testModule = util.testModule` + /** @customName Test2 **/ + declare function Test(this: void): void; + + Test(); + `; + + const result = testModule.getLuaResult(); + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("Test2("); + expect(mainFile.lua).not.toContain("Test("); +}); + +test("customName rename import specifier", () => { + const testModule = util.testModule` + import { Test } from "./myimport"; + import { Test as Aliased } from "./myimport"; + Test(); + Aliased(); + `.addExtraFile( + "myimport.ts", + ` + /** @customName Test2 **/ + export function Test(this: void): void {} + ` + ); + + testModule.expectToHaveNoDiagnostics(); + const result = testModule.getLuaResult(); + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("Test2("); + expect(mainFile.lua).toContain("myimport.Test2"); + expect(mainFile.lua).not.toContain("Test("); + + testModule.expectNoExecutionError(); +}); + +test("customName import specifier from declarations", () => { + const testModule = util.testModule` + import { Test } from "./myimport"; + import { Test as Aliased } from "./myimport"; + Test(); + Aliased(); + ` + .addExtraFile( + "myimport.d.ts", + ` + /** @customName Test2 **/ + export declare function Test(this: void): void; + ` + ) + .setOptions({ noResolvePaths: ["./myimport"] }); + + testModule.expectToHaveNoDiagnostics(); + const result = testModule.getLuaResult(); + expect(result.transpiledFiles).not.toHaveLength(0); + + const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua"); + expect(mainFile).toBeDefined(); + + // avoid ts error "not defined", even though toBeDefined is being checked above + if (!mainFile) return; + + expect(mainFile.lua).toBeDefined(); + expect(mainFile.lua).toContain("Test2("); + expect(mainFile.lua).toContain("myimport.Test2"); + expect(mainFile.lua).not.toContain("Test("); +}); diff --git a/test/unit/jsx.spec.ts b/test/unit/jsx.spec.ts new file mode 100644 index 000000000..a72d0d7f9 --- /dev/null +++ b/test/unit/jsx.spec.ts @@ -0,0 +1,375 @@ +import * as util from "../util"; +import { TestBuilder } from "../util"; +import { JsxEmit } from "typescript"; +import { unsupportedJsxEmit } from "../../src/transpilation/diagnostics"; +import { unsupportedNodeKind } from "../../src/transformation/utils/diagnostics"; + +// language=TypeScript +const reactLib = ` + export class Component { + static isClass = true + } + + namespace React { + const isLua = typeof Component === "object" + + export function createElement( + type: any, + props?: any, + ...children: any[] + ) { + let typeStr: string + if (isLua) { + typeStr = + typeof type === "function" ? "<< function >>" : + typeof type === "object" ? \`<< class \${type.name} >>\` : + type + } else { + typeStr = typeof type === "function" ? (type.isClass + ? \`<< class \${type.name} >>\` + : "<< function >>") + : type + } + + return { + type: typeStr, + props, + children + }; + } + + export class Fragment extends Component { + } + } + export default React; +`; +// language=TypeScript +const jsxTypings = `declare namespace JSX { + interface IntrinsicElements { + a: any + b: any + foo: any + bar: any + div: any + "with-dash": any + } +} +`; + +function testJsx(...args: [string] | [TemplateStringsArray, ...any[]]): TestBuilder { + return util + .testFunction(...args) + .setOptions({ + jsx: JsxEmit.React, + }) + .setMainFileName("main.tsx") + .addExtraFile("react.ts", reactLib) + .addExtraFile("jsx.d.ts", jsxTypings) + .setTsHeader('import React, { Component } from "./react";'); +} + +describe("jsx", () => { + test("element", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("self closing element", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("element with dash name", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("custom element", () => { + testJsx` + function Foo() {} + return + `.expectToMatchJsResult(); + }); + test("fragment", () => { + testJsx` + return <> + `.expectToMatchJsResult(); + }); + test("fragment with children", () => { + testJsx` + return <> + `.expectToMatchJsResult(); + }); + test("esoteric component names", () => { + testJsx` + class _Foo extends Component {} + return <_Foo /> + `.expectToMatchJsResult(); + + testJsx` + class $ extends Component {} + return <$ /> + `.expectToMatchJsResult(); + + testJsx` + class é extends Component {} + return <é /> + `.expectToMatchJsResult(); + }); + test("nested elements", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("many nested elements", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("interpolated children", () => { + testJsx` + const x = 3 + return {x} + `.expectToMatchJsResult(); + }); + test("string prop", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("value prop", () => { + testJsx` + const x = 5 + return + `.expectToMatchJsResult(); + }); + test("quoted prop", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("shorthand prop", () => { + testJsx` + return + `.expectToMatchJsResult(); + }); + test("spaces in jsxText", () => { + testJsx` + return this + is somemultiline + text thing. + + + `.expectToMatchJsResult(); + }); + test("multiline string jsxText", () => { + testJsx` + return + foo bar + baz + + `.expectToMatchJsResult(); + }); + + test("access tag value", () => { + testJsx` + const a = { b(){} }; + return + `.expectToMatchJsResult(); + testJsx` + const a = { b: { c: { d(){} } } }; + return + `.expectToMatchJsResult(); + }); + + test("spread props", () => { + testJsx` + const x = {c: "d", e: "f"} + return + `.expectToMatchJsResult(); + testJsx` + const x = {c: "d", e: "no"} + return + `.expectToMatchJsResult(); + }); + + test("comment children", () => { + testJsx` + return + {/* comment */} + {/* another comment */} + + `.expectToMatchJsResult(); + testJsx` + return + + {/* comment */} + + + `.expectToMatchJsResult(); + }); + + test("multiline string prop value", () => { + testJsx` + return
+ `.expectToMatchJsResult(); + testJsx` + return
+ `.expectToMatchJsResult(); + }); + + test("prop strings with entities", () => { + testJsx` + return
+ `.expectToMatchJsResult(); + }); + test("jsxText with entities", () => { + testJsx` + return 9+10<21 + `.expectToMatchJsResult(); + }); + + test("Spread children", () => { + // doesn't actually "spread" (typescript's current behavior) + testJsx` + const children = [, ] + return {...children} + `.expectToMatchJsResult(); + }); + + test("complex", () => { + testJsx` + const x = 3 + const props = {one: "two", three: 4} + return + `.expectToMatchJsResult(); + }); + + // language=TypeScript + const customJsxLib = `export namespace MyLib { + export function myCreate( + type: any, + props: any, + ...children: any[] + ) { + return { type: typeof type, props, children, myThing: true }; + } + + export function MyFragment() { + } + } + `; + + test("custom JSX factory", () => { + testJsx` + return c + ` + .setTsHeader('import { MyLib } from "./myJsx";') + .setOptions({ jsxFactory: "MyLib.myCreate" }) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + testJsx` + return c + ` + .setTsHeader('import { MyLib } from "./myJsx";const myCreate2 = MyLib.myCreate;') + .setOptions({ jsxFactory: "myCreate2" }) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + }); + test("custom JSX factory with noImplicitSelf", () => { + testJsx` + return c + ` + .setTsHeader( + `function createElement(tag: string | Function, props: { [key: string]: string | boolean }, ...children: any[]) { + return { tag, children }; + }` + ) + .setOptions({ jsxFactory: "createElement", noImplicitSelf: true }) + .expectToMatchJsResult(); + }); + test("custom fragment factory", () => { + testJsx` + return <>c + ` + .setTsHeader('import { MyLib } from "./myJsx";') + .setOptions({ jsxFactory: "MyLib.myCreate", jsxFragmentFactory: "MyLib.MyFragment" }) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + testJsx` + return <>c + ` + .setTsHeader('import { MyLib } from "./myJsx";function MyFragment2(){};') + .setOptions({ jsxFactory: "MyLib.myCreate", jsxFragmentFactory: "MyFragment2" }) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + }); + test("custom JSX pragma", () => { + testJsx` + return c + ` + .setTsHeader('/** @jsx MyLib.myCreate */\nimport { MyLib } from "./myJsx";') + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + testJsx` + return c + ` + .setTsHeader('/** @jsx myCreate2 */import { MyLib } from "./myJsx";const myCreate2 = MyLib.myCreate;') + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + }); + test("custom fragment pragma", () => { + testJsx` + return <>c + ` + .setTsHeader( + '/** @jsx MyLib.myCreate */\n/** @jsxFrag MyLib.MyFragment */\nimport { MyLib } from "./myJsx";' + ) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + testJsx` + return <>c + ` + .setTsHeader( + "/** @jsx MyLib.myCreate */\n/** @jsxFrag MyFragment2 */\n" + + 'import { MyLib } from "./myJsx";function MyFragment2(){};' + ) + .setOptions({ jsxFactory: "MyLib.myCreate", jsxFragmentFactory: "MyFragment" }) + .addExtraFile("myJsx.ts", customJsxLib) + .expectToMatchJsResult(); + }); + + test("forward declare components", () => { + testJsx` + const foo = + + function Foo(){} + + return foo + `.expectToMatchJsResult(); + }); + + test("invalid jsx config", () => { + testJsx(` + return + `) + .setOptions({ + jsx: JsxEmit.Preserve, + }) + .expectToHaveDiagnostics([unsupportedJsxEmit.code, unsupportedNodeKind.code]); + }); +}); diff --git a/test/unit/language-extensions/__snapshots__/iterable.spec.ts.snap b/test/unit/language-extensions/__snapshots__/iterable.spec.ts.snap index 1f76110a4..e3c25d948 100644 --- a/test/unit/language-extensions/__snapshots__/iterable.spec.ts.snap +++ b/test/unit/language-extensions/__snapshots__/iterable.spec.ts.snap @@ -4,14 +4,12 @@ exports[`LuaIterable with LuaMultiReturn value type invalid LuaIterable {}): code 1`] = ` "local function ____(____, ____bindingPattern0) if ____bindingPattern0 == nil then - ____bindingPattern0 = { - ____(_G, 1) - } + ____bindingPattern0 = {____(_G, 1)} end local a = ____bindingPattern0[1] end" @@ -52,7 +48,7 @@ end" exports[`invalid $multi call (([a] = $multi(1)) => {}): diagnostics 1`] = `"main.ts(2,16): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid $multi call (({ $multi });): code 1`] = `"local ____ = nil"`; +exports[`invalid $multi call (({ $multi });): code 1`] = `"local ____ = {["$multi"] = ____}"`; exports[`invalid $multi call (({ $multi });): diagnostics 1`] = `"main.ts(2,12): error TSTL: The $multi function must be called in a return statement."`; @@ -65,27 +61,17 @@ end" exports[`invalid $multi call (const [a = 0] = $multi()): diagnostics 1`] = `"main.ts(2,25): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid $multi call (const {} = $multi();): code 1`] = ` -"local ____ = { - { - ____(_G) - } -}" -`; +exports[`invalid $multi call (const {} = $multi();): code 1`] = `"local ____temp_0 = {{____(_G)}}"`; exports[`invalid $multi call (const {} = $multi();): diagnostics 1`] = `"main.ts(2,20): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid $multi call (const a = $multi();): code 1`] = ` -"a = { - ____(_G) -}" -`; +exports[`invalid $multi call (const a = $multi();): code 1`] = `"a = {____(_G)}"`; exports[`invalid $multi call (const a = $multi();): diagnostics 1`] = `"main.ts(2,19): error TSTL: The $multi function must be called in a return statement."`; exports[`invalid $multi implicit cast: code 1`] = ` "function badMulti(self) - return \\"foo\\", 42 + return "foo", 42 end" `; @@ -174,35 +160,34 @@ return ____exports" exports[`invalid direct $multi function use (const ar = [1]; const [a] = $multi(...ar)): diagnostics 1`] = `"main.ts(7,37): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid direct $multi function use (let a; [a] = $multi()): code 1`] = ` +exports[`invalid direct $multi function use (let a: any; for ([a] = $multi(1, 2); false; 1) {}): code 1`] = ` "local ____exports = {} local function multi(self, ...) return ... end local a -local ____ = { - ____(nil) -} -a = ____[1] -____exports.a = a +do + local ____temp_0 = {____(nil, 1, 2)} + a = ____temp_0[1] + ____exports.a = a + while false do + local ____ = 1 + end +end ____exports.a = a return ____exports" `; -exports[`invalid direct $multi function use (let a; [a] = $multi()): diagnostics 1`] = `"main.ts(7,22): error TSTL: The $multi function must be called in a return statement."`; +exports[`invalid direct $multi function use (let a: any; for ([a] = $multi(1, 2); false; 1) {}): diagnostics 1`] = `"main.ts(7,32): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid direct $multi function use (let a; for ([a] = $multi(1, 2); false; 1) {}): code 1`] = ` +exports[`invalid direct $multi function use (let a: any; for (const [a] = $multi(1, 2); false; 1) {}): code 1`] = ` "local ____exports = {} local function multi(self, ...) return ... end local a do - local ____ = { - ____(nil, 1, 2) - } - a = ____[1] - ____exports.a = a + local a = ____(nil, 1, 2) while false do local ____ = 1 end @@ -211,45 +196,38 @@ ____exports.a = a return ____exports" `; -exports[`invalid direct $multi function use (let a; for ([a] = $multi(1, 2); false; 1) {}): diagnostics 1`] = `"main.ts(7,27): error TSTL: The $multi function must be called in a return statement."`; +exports[`invalid direct $multi function use (let a: any; for (const [a] = $multi(1, 2); false; 1) {}): diagnostics 1`] = `"main.ts(7,38): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid direct $multi function use (let a; for (const [a] = $multi(1, 2); false; 1) {}): code 1`] = ` +exports[`invalid direct $multi function use (let a: any; if ([a] = $multi(1)) { ++a; }): code 1`] = ` "local ____exports = {} local function multi(self, ...) return ... end local a -do - local a = ____(nil, 1, 2) - while false do - local ____ = 1 - end +local ____temp_0 = {____(nil, 1)} +a = ____temp_0[1] +____exports.a = a +if ____temp_0 then + a = a + 1 + ____exports.a = a end ____exports.a = a return ____exports" `; -exports[`invalid direct $multi function use (let a; for (const [a] = $multi(1, 2); false; 1) {}): diagnostics 1`] = `"main.ts(7,33): error TSTL: The $multi function must be called in a return statement."`; +exports[`invalid direct $multi function use (let a: any; if ([a] = $multi(1)) { ++a; }): diagnostics 1`] = `"main.ts(7,31): error TSTL: The $multi function must be called in a return statement."`; -exports[`invalid direct $multi function use (let a; if ([a] = $multi(1)) { ++a; }): code 1`] = ` +exports[`invalid direct $multi function use (let a; [a] = $multi()): code 1`] = ` "local ____exports = {} local function multi(self, ...) return ... end local a -if (function() - local ____ = { - ____(nil, 1) - } - a = ____[1] - ____exports.a = a - return ____ -end)() then - a = a + 1 - ____exports.a = a -end +local ____temp_0 = {____(nil)} +a = ____temp_0[1] +____exports.a = a ____exports.a = a return ____exports" `; -exports[`invalid direct $multi function use (let a; if ([a] = $multi(1)) { ++a; }): diagnostics 1`] = `"main.ts(7,26): error TSTL: The $multi function must be called in a return statement."`; +exports[`invalid direct $multi function use (let a; [a] = $multi()): diagnostics 1`] = `"main.ts(7,22): error TSTL: The $multi function must be called in a return statement."`; diff --git a/test/unit/language-extensions/__snapshots__/operators.spec.ts.snap b/test/unit/language-extensions/__snapshots__/operators.spec.ts.snap index cfeef91c8..a4554a8a1 100644 --- a/test/unit/language-extensions/__snapshots__/operators.spec.ts.snap +++ b/test/unit/language-extensions/__snapshots__/operators.spec.ts.snap @@ -1,24 +1,60 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`does not crash on invalid operator use global function: code 1`] = `""`; + +exports[`does not crash on invalid operator use global function: diagnostics 1`] = `"main.ts(3,13): error TS2554: Expected 2 arguments, but got 1."`; + +exports[`does not crash on invalid operator use method: code 1`] = `"left = {}"`; + +exports[`does not crash on invalid operator use method: diagnostics 1`] = `"main.ts(5,18): error TS2554: Expected 1 arguments, but got 0."`; + +exports[`does not crash on invalid operator use unary operator: code 1`] = `"op(_G)"`; + +exports[`does not crash on invalid operator use unary operator: diagnostics 1`] = `"main.ts(2,31): error TS2304: Cannot find name 'LuaUnaryMinus'."`; + exports[`operator mapping - invalid use (const foo = (op as any)(1, 2);): code 1`] = `"foo = op(_G, 1, 2)"`; -exports[`operator mapping - invalid use (const foo = (op as any)(1, 2);): diagnostics 1`] = `"main.ts(3,22): error TSTL: This function must always be directly called and cannot be referred to."`; +exports[`operator mapping - invalid use (const foo = (op as any)(1, 2);): diagnostics 1`] = `"main.ts(3,22): error TSTL: This function must be called directly and cannot be referred to."`; exports[`operator mapping - invalid use (const foo = [op];): code 1`] = `"foo = {op}"`; -exports[`operator mapping - invalid use (const foo = [op];): diagnostics 1`] = `"main.ts(3,22): error TSTL: This function must always be directly called and cannot be referred to."`; +exports[`operator mapping - invalid use (const foo = [op];): diagnostics 1`] = `"main.ts(3,22): error TSTL: This function must be called directly and cannot be referred to."`; exports[`operator mapping - invalid use (const foo = \`\${op}\`): code 1`] = `"foo = tostring(op)"`; -exports[`operator mapping - invalid use (const foo = \`\${op}\`): diagnostics 1`] = `"main.ts(3,24): error TSTL: This function must always be directly called and cannot be referred to."`; +exports[`operator mapping - invalid use (const foo = \`\${op}\`): diagnostics 1`] = `"main.ts(3,24): error TSTL: This function must be called directly and cannot be referred to."`; exports[`operator mapping - invalid use (const foo: unknown = op;): code 1`] = `"foo = op"`; -exports[`operator mapping - invalid use (const foo: unknown = op;): diagnostics 1`] = `"main.ts(3,30): error TSTL: This function must always be directly called and cannot be referred to."`; +exports[`operator mapping - invalid use (const foo: unknown = op;): diagnostics 1`] = `"main.ts(3,30): error TSTL: This function must be called directly and cannot be referred to."`; exports[`operator mapping - invalid use (declare function foo(op: LuaAddition): void; foo(op);): code 1`] = `"foo(_G, op)"`; -exports[`operator mapping - invalid use (declare function foo(op: LuaAddition): void; foo(op);): diagnostics 1`] = `"main.ts(3,82): error TSTL: This function must always be directly called and cannot be referred to."`; +exports[`operator mapping - invalid use (declare function foo(op: LuaAddition): void; foo(op);): diagnostics 1`] = `"main.ts(3,82): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseAnd): code 1`] = `"local ____ = left & right"`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseAnd): diagnostics 1`] = `"main.ts(6,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseExclusiveOr): code 1`] = `"local ____ = left ~ right"`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseExclusiveOr): diagnostics 1`] = `"main.ts(6,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseLeftShift): code 1`] = `"local ____ = left << right"`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseLeftShift): diagnostics 1`] = `"main.ts(6,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseOr): code 1`] = `"local ____ = left | right"`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseOr): diagnostics 1`] = `"main.ts(6,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseRightShift): code 1`] = `"local ____ = left >> right"`; + +exports[`unsupported binary operator mapping (5.0 LuaBitwiseRightShift): diagnostics 1`] = `"main.ts(6,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + +exports[`unsupported binary operator mapping (5.0 LuaFloorDivision): code 1`] = `"local ____ = left // right"`; + +exports[`unsupported binary operator mapping (5.0 LuaFloorDivision): diagnostics 1`] = `"main.ts(6,9): error TSTL: Floor division operator is/are not supported for target Lua 5.0."`; exports[`unsupported binary operator mapping (5.1 LuaBitwiseAnd): code 1`] = `"local ____ = left & right"`; @@ -116,6 +152,10 @@ exports[`unsupported binary operator mapping (universal LuaFloorDivision): code exports[`unsupported binary operator mapping (universal LuaFloorDivision): diagnostics 1`] = `"main.ts(6,9): error TSTL: Floor division operator is/are not supported for target Lua 5.1."`; +exports[`unsupported unary operator mapping (5.0 LuaBitwiseNot): code 1`] = `"local ____ = ~operand"`; + +exports[`unsupported unary operator mapping (5.0 LuaBitwiseNot): diagnostics 1`] = `"main.ts(5,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.0."`; + exports[`unsupported unary operator mapping (5.1 LuaBitwiseNot): code 1`] = `"local ____ = ~operand"`; exports[`unsupported unary operator mapping (5.1 LuaBitwiseNot): diagnostics 1`] = `"main.ts(5,9): error TSTL: Native bitwise operations is/are not supported for target Lua 5.1."`; diff --git a/test/unit/language-extensions/__snapshots__/pairsIterable.spec.ts.snap b/test/unit/language-extensions/__snapshots__/pairsIterable.spec.ts.snap new file mode 100644 index 000000000..f38856514 --- /dev/null +++ b/test/unit/language-extensions/__snapshots__/pairsIterable.spec.ts.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`invalid LuaPairsIterable without destructuring ("for (const s of testIterable) {}"): code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local testIterable = {a1 = "a2", b1 = "b2", c1 = "c2"} + for ____ in pairs(testIterable) do + end +end +return ____exports" +`; + +exports[`invalid LuaPairsIterable without destructuring ("for (const s of testIterable) {}"): diagnostics 1`] = `"main.ts(5,20): error TSTL: LuaPairsIterable type must be destructured in a for...of statement."`; + +exports[`invalid LuaPairsIterable without destructuring ("let s; for (s of testIterable) {}"): code 1`] = ` +"local ____exports = {} +function ____exports.__main(self) + local testIterable = {a1 = "a2", b1 = "b2", c1 = "c2"} + local s + for ____ in pairs(testIterable) do + end +end +return ____exports" +`; + +exports[`invalid LuaPairsIterable without destructuring ("let s; for (s of testIterable) {}"): diagnostics 1`] = `"main.ts(5,21): error TSTL: LuaPairsIterable type must be destructured in a for...of statement."`; diff --git a/test/unit/language-extensions/__snapshots__/range.spec.ts.snap b/test/unit/language-extensions/__snapshots__/range.spec.ts.snap index f066c1260..73a56890b 100644 --- a/test/unit/language-extensions/__snapshots__/range.spec.ts.snap +++ b/test/unit/language-extensions/__snapshots__/range.spec.ts.snap @@ -33,14 +33,11 @@ return ____exports" exports[`$range invalid use ("const x = $range(1, 10);"): diagnostics 1`] = `"main.ts(2,19): error TSTL: $range can only be used in a for...of loop."`; exports[`$range invalid use ("const y = [...$range(1, 10)];"): code 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Spread = ____lualib.__TS__Spread local ____exports = {} function ____exports.__main(self) - local y = { - __TS__Spread( - ____(nil, 1, 10) - ) - } + local y = {__TS__Spread(____(nil, 1, 10))} end return ____exports" `; @@ -50,9 +47,7 @@ exports[`$range invalid use ("const y = [...$range(1, 10)];"): diagnostics 1`] = exports[`$range invalid use ("for (const i in $range(1, 10, 2)) {}"): code 1`] = ` "local ____exports = {} function ____exports.__main(self) - for i in pairs( - ____(nil, 1, 10, 2) - ) do + for i in pairs(____(nil, 1, 10, 2)) do end end return ____exports" @@ -63,9 +58,7 @@ exports[`$range invalid use ("for (const i in $range(1, 10, 2)) {}"): diagnostic exports[`$range invalid use ("for (const i of $range(1, 10, 2) as number[]) {}"): code 1`] = ` "local ____exports = {} function ____exports.__main(self) - for ____, i in ipairs( - ____(nil, 1, 10, 2) - ) do + for ____, i in ipairs(____(nil, 1, 10, 2)) do end end return ____exports" @@ -74,12 +67,11 @@ return ____exports" exports[`$range invalid use ("for (const i of $range(1, 10, 2) as number[]) {}"): diagnostics 1`] = `"main.ts(2,25): error TSTL: $range can only be used in a for...of loop."`; exports[`$range invalid use ("for (const i of ($range(1, 10, 2))) {}"): code 1`] = ` -"require(\\"lualib_bundle\\"); +"local ____lualib = require("lualib_bundle") +local __TS__Iterator = ____lualib.__TS__Iterator local ____exports = {} function ____exports.__main(self) - for ____, i in __TS__Iterator( - ____(nil, 1, 10, 2) - ) do + for ____, i in __TS__Iterator(____(nil, 1, 10, 2)) do end end return ____exports" diff --git a/test/unit/language-extensions/__snapshots__/table.spec.ts.snap b/test/unit/language-extensions/__snapshots__/table.spec.ts.snap index 5deed95c3..24abd6e71 100644 --- a/test/unit/language-extensions/__snapshots__/table.spec.ts.snap +++ b/test/unit/language-extensions/__snapshots__/table.spec.ts.snap @@ -46,92 +46,6 @@ return ____exports" exports[`LuaTable extension interface LuaTable in strict mode does not accept key type that could be nil ("unknown"): diagnostics 1`] = `"main.ts(1,38): error TS2344: Type 'unknown' does not satisfy the constraint 'AnyNotNil'."`; -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = [tableDelete({}, \\"foo\\")];"): code 1`] = ` -"foo = { - (function() - ({}).foo = nil - return nil - end)() -}" -`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = [tableDelete({}, \\"foo\\")];"): diagnostics 1`] = `"main.ts(3,26): error TSTL: Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = \`\${tableDelete({}, \\"foo\\")}\`;"): code 1`] = ` -"foo = tostring( - (function() - ({}).foo = nil - return nil - end)() -)" -`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = \`\${tableDelete({}, \\"foo\\")}\`;"): diagnostics 1`] = `"main.ts(3,28): error TSTL: Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = tableDelete({}, \\"foo\\");"): code 1`] = ` -"foo = (function() - ({}).foo = nil - return nil -end)()" -`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("const foo = tableDelete({}, \\"foo\\");"): diagnostics 1`] = `"main.ts(3,25): error TSTL: Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("declare function foo(arg: any): void; foo(tableDelete({}, \\"foo\\"));"): code 1`] = ` -"foo( - _G, - (function() - ({}).foo = nil - return nil - end)() -)" -`; - -exports[`LuaTableDelete extension LuaTableDelete invalid use as expression ("declare function foo(arg: any): void; foo(tableDelete({}, \\"foo\\"));"): diagnostics 1`] = `"main.ts(3,55): error TSTL: Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = [setTable({}, \\"foo\\", 3)];"): code 1`] = ` -"foo = { - (function() - ({}).foo = 3 - return nil - end)() -}" -`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = [setTable({}, \\"foo\\", 3)];"): diagnostics 1`] = `"main.ts(3,26): error TSTL: Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = \`\${setTable({}, \\"foo\\", 3)}\`;"): code 1`] = ` -"foo = tostring( - (function() - ({}).foo = 3 - return nil - end)() -)" -`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = \`\${setTable({}, \\"foo\\", 3)}\`;"): diagnostics 1`] = `"main.ts(3,28): error TSTL: Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = setTable({}, \\"foo\\", 3);"): code 1`] = ` -"foo = (function() - ({}).foo = 3 - return nil -end)()" -`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("const foo = setTable({}, \\"foo\\", 3);"): diagnostics 1`] = `"main.ts(3,25): error TSTL: Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("declare function foo(arg: any): void; foo(setTable({}, \\"foo\\", 3));"): code 1`] = ` -"foo( - _G, - (function() - ({}).foo = 3 - return nil - end)() -)" -`; - -exports[`LuaTableGet & LuaTableSet extensions LuaTableSet invalid use as expression ("declare function foo(arg: any): void; foo(setTable({}, \\"foo\\", 3));"): diagnostics 1`] = `"main.ts(3,55): error TSTL: Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement."`; - exports[`LuaTableGet & LuaTableSet extensions invalid use ("const foo = (getTable as any)(1, 2);"): code 1`] = `"foo = getTable(_G, 1, 2)"`; exports[`LuaTableGet & LuaTableSet extensions invalid use ("const foo = (getTable as any)(1, 2);"): diagnostics 1`] = `"main.ts(3,26): error TSTL: This function must be called directly and cannot be referred to."`; @@ -171,3 +85,59 @@ exports[`LuaTableHas extension invalid use ("const foo: unknown = tableHas;"): d exports[`LuaTableHas extension invalid use ("declare function foo(tableHas: LuaTableHas<{}, string>): void; foo(tableHas);"): code 1`] = `"foo(_G, tableHas)"`; exports[`LuaTableHas extension invalid use ("declare function foo(tableHas: LuaTableHas<{}, string>): void; foo(tableHas);"): diagnostics 1`] = `"main.ts(3,80): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaMap"): code 1`] = ` +"____table = {} +has = ____table.has" +`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaMap"): diagnostics 1`] = `"main.ts(3,29): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaSet"): code 1`] = ` +"____table = {} +has = ____table.has" +`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaSet"): diagnostics 1`] = `"main.ts(3,29): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaTable"): code 1`] = ` +"____table = {} +has = ____table.has" +`; + +exports[`LuaTableHas extension invalid use method assignment ("LuaTable"): diagnostics 1`] = `"main.ts(3,29): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method expression ("LuaMap"): code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__ArrayMap = ____lualib.__TS__ArrayMap +____table = {} +__TS__ArrayMap({"a", "b", "c"}, ____table.has)" +`; + +exports[`LuaTableHas extension invalid use method expression ("LuaMap"): diagnostics 1`] = `"main.ts(3,37): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method expression ("LuaSet"): code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__ArrayMap = ____lualib.__TS__ArrayMap +____table = {} +__TS__ArrayMap({"a", "b", "c"}, ____table.has)" +`; + +exports[`LuaTableHas extension invalid use method expression ("LuaSet"): diagnostics 1`] = `"main.ts(3,37): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`LuaTableHas extension invalid use method expression ("LuaTable"): code 1`] = ` +"local ____lualib = require("lualib_bundle") +local __TS__ArrayMap = ____lualib.__TS__ArrayMap +____table = {} +__TS__ArrayMap({"a", "b", "c"}, ____table.has)" +`; + +exports[`LuaTableHas extension invalid use method expression ("LuaTable"): diagnostics 1`] = `"main.ts(3,37): error TSTL: This function must be called directly and cannot be referred to."`; + +exports[`does not crash on invalid extension use global function: code 1`] = `""`; + +exports[`does not crash on invalid extension use global function: diagnostics 1`] = `"main.ts(3,9): error TS2554: Expected 2 arguments, but got 1."`; + +exports[`does not crash on invalid extension use method: code 1`] = `"left = {}"`; + +exports[`does not crash on invalid extension use method: diagnostics 1`] = `"main.ts(5,14): error TS2554: Expected 2 arguments, but got 0."`; diff --git a/test/unit/language-extensions/__snapshots__/vararg.spec.ts.snap b/test/unit/language-extensions/__snapshots__/vararg.spec.ts.snap index 819cc27a0..e2cf42298 100644 --- a/test/unit/language-extensions/__snapshots__/vararg.spec.ts.snap +++ b/test/unit/language-extensions/__snapshots__/vararg.spec.ts.snap @@ -24,12 +24,14 @@ f(_G, ____)" exports[`$vararg invalid use ("function f(s: string[]) {} f($vararg);"): diagnostics 1`] = `"main.ts(2,38): error TSTL: $vararg can only be used in a spread element ('...$vararg') in global scope."`; exports[`$vararg invalid use ("function foo(...args: string[]) {} function bar() { foo(...$vararg); }"): code 1`] = ` -"function foo(self, ...) +"local ____lualib = require("lualib_bundle") +local __TS__Spread = ____lualib.__TS__Spread +function foo(self, ...) end function bar(self) foo( _G, - table.unpack(____) + __TS__Spread(____) ) end" `; diff --git a/test/unit/language-extensions/iterable.spec.ts b/test/unit/language-extensions/iterable.spec.ts index b6f7ab141..30e602f62 100644 --- a/test/unit/language-extensions/iterable.spec.ts +++ b/test/unit/language-extensions/iterable.spec.ts @@ -1,12 +1,6 @@ -import * as path from "path"; import * as util from "../../util"; -import * as tstl from "../../../src"; import { invalidMultiIterableWithoutDestructuring } from "../../../src/transformation/utils/diagnostics"; -const iterableProjectOptions: tstl.CompilerOptions = { - types: [path.resolve(__dirname, "../../../language-extensions")], -}; - describe("simple LuaIterable", () => { const testIterable = ` function testIterable(this: void): LuaIterable { @@ -26,7 +20,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -39,7 +33,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -53,7 +47,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -67,7 +61,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -81,7 +75,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -95,7 +89,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -113,7 +107,7 @@ describe("simple LuaIterable", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); }); @@ -136,7 +130,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -149,7 +143,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -163,7 +157,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -177,7 +171,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -191,7 +185,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -205,7 +199,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -223,7 +217,7 @@ describe("LuaIterable using state", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); }); @@ -245,27 +239,27 @@ describe("LuaIterable with array value type", () => { test("basic destructuring", () => { util.testFunction` ${testIterable} - const results: Array = []; + const results = []; for (const [x, y] of testIterable()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); test("destructure with external control variable", () => { util.testFunction` ${testIterable} - const results: Array = []; + const results = [] let x: string, y: string; for ([x, y] of testIterable()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -279,7 +273,7 @@ describe("LuaIterable with array value type", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -293,7 +287,7 @@ describe("LuaIterable with array value type", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -307,7 +301,7 @@ describe("LuaIterable with array value type", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -325,15 +319,15 @@ describe("LuaIterable with array value type", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); }); describe("LuaIterable with LuaMultiReturn value type", () => { const testIterable = ` - function testIterable(this: void): LuaIterable> { - const strsArray = [["a1", "a2"], ["b1", "b2"], ["c1", "c2"]]; + function testIterable(this: void): LuaIterable> { + const strsArray = [["a1", {a: "a"}], ["b1", {a: "b"}], ["c1", {a: "c"}]]; let i = 0; return (() => { const strs = strsArray[i++]; @@ -344,35 +338,35 @@ describe("LuaIterable with LuaMultiReturn value type", () => { } `; const testResults = [ - ["a1", "a2"], - ["b1", "b2"], - ["c1", "c2"], + ["a1", { a: "a" }], + ["b1", { a: "b" }], + ["c1", { a: "c" }], ]; test("basic destructuring", () => { util.testFunction` ${testIterable} - const results: Array = []; + const results = []; for (const [x, y] of testIterable()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); test("destructure with external control variable", () => { util.testFunction` ${testIterable} - const results: Array = []; - let x: string, y: string; + const results = []; + let x: string, y: any; for ([x, y] of testIterable()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -380,13 +374,13 @@ describe("LuaIterable with LuaMultiReturn value type", () => { util.testFunction` ${testIterable} function forward() { return testIterable(); } - const results: Array = []; + const results = []; for (const [x, y] of forward()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -394,13 +388,13 @@ describe("LuaIterable with LuaMultiReturn value type", () => { util.testFunction` ${testIterable} function forward() { const iter = testIterable(); return iter; } - const results: Array = []; + const results = []; for (const [x, y] of forward()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -408,20 +402,20 @@ describe("LuaIterable with LuaMultiReturn value type", () => { util.testFunction` ${testIterable} const forward = () => testIterable(); - const results: Array = []; + const results = []; for (const [x, y] of forward()) { results.push([x, y]); } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); test("destructure manual use", () => { util.testFunction` ${testIterable} - const results: Array = []; + const results = []; const iter = testIterable(); while (true) { const [x, y] = iter(); @@ -432,10 +426,27 @@ describe("LuaIterable with LuaMultiReturn value type", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); + test("nested destructuring", () => { + util.testFunction` + ${testIterable} + const results = []; + for (const [x, {a}] of testIterable()) { + results.push([x, a]); + } + return results; + ` + .withLanguageExtensions() + .expectToEqual([ + ["a1", "a"], + ["b1", "b"], + ["c1", "c"], + ]); + }); + test.each(["for (const s of testIterable()) {}", "let s; for (s of testIterable()) {}"])( "invalid LuaIterable without destructuring (%p)", statement => { @@ -443,7 +454,7 @@ describe("LuaIterable with LuaMultiReturn value type", () => { ${testIterable} ${statement} ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidMultiIterableWithoutDestructuring.code]); } ); @@ -472,7 +483,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -486,7 +497,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -500,7 +511,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -514,7 +525,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -528,7 +539,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); @@ -546,7 +557,7 @@ describe("LuaIterable property", () => { } return results; ` - .setOptions(iterableProjectOptions) + .withLanguageExtensions() .expectToEqual(testResults); }); }); diff --git a/test/unit/language-extensions/multi.spec.ts b/test/unit/language-extensions/multi.spec.ts index 5d59aa4d0..90fc54200 100644 --- a/test/unit/language-extensions/multi.spec.ts +++ b/test/unit/language-extensions/multi.spec.ts @@ -1,16 +1,10 @@ -import * as path from "path"; import * as util from "../../util"; -import * as tstl from "../../../src"; import { invalidMultiFunctionUse, invalidMultiReturnAccess, invalidMultiFunctionReturnType, } from "../../../src/transformation/utils/diagnostics"; -const multiProjectOptions: tstl.CompilerOptions = { - types: [path.resolve(__dirname, "../../../language-extensions")], -}; - test("multi example use case", () => { util.testModule` function multiReturn(): LuaMultiReturn<[string, number]> { @@ -20,7 +14,7 @@ test("multi example use case", () => { const [a, b] = multiReturn(); export { a, b }; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual({ a: "foo", b: 5 }); }); @@ -34,7 +28,7 @@ test("Destructuring assignment of LuaMultiReturn", () => { const [a, ...b] = multiReturn(); export {a, b}; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual({ a: 1, b: [2, 3] }); }); @@ -47,7 +41,8 @@ test("Destructuring assignment of LuaMultiReturn returning nil", () => { const [a, ...b] = multiReturn(); export {a, b}; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() + .setOptions({ strict: false }) .expectToEqual({ a: undefined, b: [] }); }); @@ -59,12 +54,12 @@ test.each<[string, any]>([ util.testFunction` return ${expression}; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(result); }); const multiFunction = ` -function multi(...args) { +function multi(...args: unknown[]) { return $multi(...args); } `; @@ -77,9 +72,9 @@ const createCasesThatCall = (name: string): Array<[string, any]> => [ [`const [a = 1] = ${name}(2)`, 2], [`const ar = [1]; const [a] = ${name}(...ar)`, 1], [`const _ = null, [a] = ${name}(1)`, 1], - [`let a; for (const [a] = ${name}(1, 2); false; 1) {}`, undefined], - [`let a; for ([a] = ${name}(1, 2); false; 1) {}`, 1], - [`let a; if ([a] = ${name}(1)) { ++a; }`, 2], + [`let a: any; for (const [a] = ${name}(1, 2); false; 1) {}`, undefined], + [`let a: any; for ([a] = ${name}(1, 2); false; 1) {}`, 1], + [`let a: any; if ([a] = ${name}(1)) { ++a; }`, 2], ]; test.each<[string, any]>(createCasesThatCall("$multi"))("invalid direct $multi function use (%s)", statement => { @@ -88,7 +83,7 @@ test.each<[string, any]>(createCasesThatCall("$multi"))("invalid direct $multi f ${statement} export { a }; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .setReturnExport("a") .expectDiagnosticsToMatchSnapshot([invalidMultiFunctionUse.code]); }); @@ -101,7 +96,7 @@ test.each<[string, any]>(createCasesThatCall("multi"))( ${statement} export { a }; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .setReturnExport("a") .expectToEqual(result); } @@ -119,7 +114,7 @@ test.each<[string, number[]]>([ util.testModule` ${statement} ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot(diagnostics); }); @@ -131,7 +126,7 @@ test("function to spread multi type result from multi type function", () => { } return m(); ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(true); }); @@ -142,7 +137,7 @@ test("$multi call with destructuring assignment side effects", () => { export { a }; [a] = multi(1); ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .setReturnExport("a") .expectToEqual(1); }); @@ -153,7 +148,7 @@ test("allow $multi call in ArrowFunction body", () => { const [result] = call(); return result; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(1); }); @@ -164,7 +159,7 @@ test("forward $multi call", () => { const [resultA, resultB] = call(); return [resultA, resultB]; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual([1, 2]); }); @@ -175,7 +170,7 @@ test("forward $multi call indirect", () => { const [resultA, resultB] = call(); return [resultA, resultB]; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual([1, 2]); }); @@ -186,17 +181,47 @@ test("forward $multi call in ArrowFunction body", () => { const [resultA, resultB] = call(); return [resultA, resultB]; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual([1, 2]); }); +test("$multi call in function typed as any", () => { + util.testFunction` + function foo(): any { return $multi(1, 2); } + return foo() + ` + .withLanguageExtensions() + .expectToHaveNoDiagnostics() + .expectToEqual(1); +}); + +test("$multi call cast to any", () => { + util.testFunction` + function foo() { return $multi(1, 2) as any; } + return foo() + ` + .withLanguageExtensions() + .expectToHaveNoDiagnostics() + .expectToEqual(1); +}); + +test("$multi call cast to MultiReturn type", () => { + util.testFunction` + function foo() { return $multi(1, 2) as unknown as LuaMultiReturn; } + return foo() + ` + .withLanguageExtensions() + .expectToHaveNoDiagnostics() + .expectToEqual(1); +}); + test.each(["0", "i"])("allow LuaMultiReturn numeric access (%s)", expression => { util.testFunction` ${multiFunction} const i = 0; return multi(1)[${expression}]; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(1); }); @@ -205,7 +230,7 @@ test.each(["multi()['forEach']", "multi().forEach"])("disallow LuaMultiReturn no ${multiFunction} return ${expression}; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidMultiReturnAccess.code]); }); @@ -215,7 +240,7 @@ test("invalid $multi implicit cast", () => { return $multi("foo", 42); } ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidMultiFunctionReturnType.code]); }); @@ -236,7 +261,7 @@ test.each([ const [x, y] = multiOverload(${flag}); return y; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(result); }); @@ -248,10 +273,10 @@ test("return $multi from try", () => { } catch { } } - const [_, a] = multiTest(); + const [_, a] = multiTest()!; return a; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(2); }); @@ -267,7 +292,7 @@ test("return $multi from catch", () => { const [_, a] = multiTest(); return a; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(2); }); @@ -280,10 +305,10 @@ test("return LuaMultiReturn from try", () => { } catch { } } - const [_, a] = multiTest(); + const [_, a] = multiTest()!; return a; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(2); }); @@ -300,6 +325,80 @@ test("return LuaMultiReturn from catch", () => { const [_, a] = multiTest(); return a; ` - .setOptions(multiProjectOptions) + .withLanguageExtensions() .expectToEqual(2); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1404 +test("LuaMultiReturn applies after casting a function (#1404)", () => { + util.testFunction` + let swap: any = (a: number, b: number) => $multi(b, a); + let [a, b] = (swap as (...args: any) => LuaMultiReturn<[number, number]>)(4, 3); + return [a, b]; + ` + .withLanguageExtensions() + .expectToEqual([3, 4]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1411 +describe("LuaMultiReturn returns all values even when indexed with [0] #1411", () => { + const sharedCode = ` + declare function select(this:void, index: '#', ...args: T[]): number; + + function foo(this: void): LuaMultiReturn<[number, number]> { + return $multi(123, 456); + } + + function bar(this: void): number { + return foo()[0]; + } + `; + test("Returns the correct value", () => { + util.testFunction` + return bar(); + ` + .setTsHeader(sharedCode) + .withLanguageExtensions() + .expectToEqual(123); + }); + + // We require an extra test since the test above would succeed even if bar() returned more than one value. + // This is because our test helper always returns just the first lua value returned from the testFunction. + // Here we need to test explicitly that only one value is returned. + test("Does not return multiple values", () => { + util.testFunction` + return select("#", bar()); + ` + .setTsHeader(sharedCode) + .withLanguageExtensions() + .expectToEqual(1); + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1591 +test("LuaMultiReturn in LuaIterable (#1591)", () => { + const lua = util.testModule` + type IterableAlias = LuaIterable>; + + declare const iterable: IterableAlias; + + for (const [a, b] of iterable) {} + ` + .withLanguageExtensions() + .getMainLuaCodeChunk(); + + expect(lua).toContain("a, b"); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1591 +test("LuaMultiReturn in LuaIterable intersection (#1591)", () => { + const lua = util.testModule` + declare function iterator(): { a: string } & LuaIterable>; + + for (const [a, b] of iterator()) {} + ` + .withLanguageExtensions() + .getMainLuaCodeChunk(); + + expect(lua).toContain("a, b"); +}); diff --git a/test/unit/language-extensions/operators.spec.ts b/test/unit/language-extensions/operators.spec.ts index c84f8aac9..303a5d0be 100644 --- a/test/unit/language-extensions/operators.spec.ts +++ b/test/unit/language-extensions/operators.spec.ts @@ -1,9 +1,12 @@ import * as path from "path"; import * as util from "../../util"; import * as tstl from "../../../src"; -import { invalidOperatorMappingUse } from "../../../src/transformation/utils/diagnostics"; import { LuaTarget } from "../../../src"; -import { unsupportedForTarget } from "../../../src/transformation/utils/diagnostics"; +import { + unsupportedForTarget, + invalidCallExtensionUse, + invalidSpreadInCallExtension, +} from "../../../src/transformation/utils/diagnostics"; const operatorsProjectOptions: tstl.CompilerOptions = { luaTarget: LuaTarget.Lua54, @@ -114,7 +117,7 @@ test.each(binaryMathOperatorTests)( } ); -const luaTargetsPre53 = [LuaTarget.Lua51, LuaTarget.Lua52, LuaTarget.LuaJIT, LuaTarget.Universal]; +const luaTargetsPre53 = [LuaTarget.Lua50, LuaTarget.Lua51, LuaTarget.Lua52, LuaTarget.LuaJIT, LuaTarget.Universal]; const operatorTypesPost53 = [ "LuaFloorDivision", @@ -388,5 +391,43 @@ test.each([ ${invalidCode} ` .setOptions(operatorsProjectOptions) - .expectDiagnosticsToMatchSnapshot([invalidOperatorMappingUse.code]); + .expectDiagnosticsToMatchSnapshot([invalidCallExtensionUse.code]); +}); + +describe("does not crash on invalid operator use", () => { + test("global function", () => { + util.testModule` + declare const op: LuaAddition; + op(1) + ` + .setOptions(operatorsProjectOptions) + .expectDiagnosticsToMatchSnapshot(); + }); + test("unary operator", () => { + util.testModule` + declare const op: LuaUnaryMinus; + op() + ` + .setOptions(operatorsProjectOptions) + .expectDiagnosticsToMatchSnapshot(); + }); + test("method", () => { + util.testModule` + const left = {} as { + op: LuaAdditionMethod; + } + left.op() + ` + .setOptions(operatorsProjectOptions) + .expectDiagnosticsToMatchSnapshot(); + }); +}); + +test("does not allow spread", () => { + util.testModule` + declare const op: LuaAddition; + op(...[1, 2] as const); + ` + .setOptions(operatorsProjectOptions) + .expectToHaveDiagnostics([invalidSpreadInCallExtension.code]); }); diff --git a/test/unit/language-extensions/pairsIterable.spec.ts b/test/unit/language-extensions/pairsIterable.spec.ts new file mode 100644 index 000000000..51c7e0b4e --- /dev/null +++ b/test/unit/language-extensions/pairsIterable.spec.ts @@ -0,0 +1,219 @@ +import * as util from "../../util"; +import { invalidPairsIterableWithoutDestructuring } from "../../../src/transformation/utils/diagnostics"; +import { LuaTarget } from "../../../src"; + +const testIterable = ` +const testIterable = {a1: "a2", b1: "b2", c1: "c2"} as unknown as LuaPairsIterable; +`; + +const testResults = { + a1: "a2", + b1: "b2", + c1: "c2", +}; + +test("pairs iterable", () => { + util.testFunction` + ${testIterable} + const results: Record = {}; + for (const [k, v] of testIterable) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual(testResults); +}); + +test("pairs iterable with external control variable", () => { + util.testFunction` + ${testIterable} + const results: Record = {}; + let k: string, v: string; + for ([k, v] of testIterable) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual(testResults); +}); + +test("pairs iterable function forward", () => { + util.testFunction` + ${testIterable} + function forward() { return testIterable; } + const results: Record = {}; + for (const [k, v] of forward()) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual(testResults); +}); + +test("pairs iterable function indirect forward", () => { + util.testFunction` + ${testIterable} + function forward() { const iter = testIterable; return iter; } + const results: Record = {}; + for (const [k, v] of forward()) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual(testResults); +}); + +test("pairs iterable arrow function forward", () => { + util.testFunction` + ${testIterable} + const forward = () => testIterable; + const results: Record = {}; + for (const [k, v] of forward()) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual(testResults); +}); + +test("pairs iterable with __pairs metamethod", () => { + util.testFunction` + class PairsTest { + __pairs() { + const kvp = [ ["a1", "a2"], ["b1", "b2"], ["c1", "c2"] ]; + let i = 0; + return () => { + if (i < kvp.length) { + const [k, v] = kvp[i++]; + return $multi(k, v); + } + }; + } + } + const tester = new PairsTest() as PairsTest & LuaPairsIterable; + const results: Record = {}; + for (const [k, v] of tester) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .setOptions({ luaTarget: LuaTarget.Lua53 }) + .expectToEqual(testResults); +}); + +test.each(["for (const s of testIterable) {}", "let s; for (s of testIterable) {}"])( + "invalid LuaPairsIterable without destructuring (%p)", + statement => { + util.testFunction` + ${testIterable} + ${statement} + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot([invalidPairsIterableWithoutDestructuring.code]); + } +); + +const testKeyIterable = ` +const testKeyIterable = {a1: true, b1: true, c1: true} as unknown as LuaPairsKeyIterable; +`; + +test("pairs key iterable", () => { + util.testFunction` + ${testKeyIterable} + const results: Record = {}; + for (const k of testKeyIterable) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ a1: true, b1: true, c1: true }); +}); + +test("pairs key iterable with external control variable", () => { + util.testFunction` + ${testKeyIterable} + const results: Record = {}; + let k: string; + for (k of testKeyIterable) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ a1: true, b1: true, c1: true }); +}); + +test("pairs key iterable function forward", () => { + util.testFunction` + ${testKeyIterable} + function forward() { return testKeyIterable; } + const results: Record = {}; + for (const k of forward()) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ a1: true, b1: true, c1: true }); +}); + +test("pairs key iterable function indirect forward", () => { + util.testFunction` + ${testKeyIterable} + function forward() { const iter = testKeyIterable; return iter; } + const results: Record = {}; + for (const k of forward()) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ a1: true, b1: true, c1: true }); +}); + +test("pairs key iterable arrow function forward", () => { + util.testFunction` + ${testKeyIterable} + const forward = () => testKeyIterable; + const results: Record = {}; + for (const k of forward()) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ a1: true, b1: true, c1: true }); +}); + +test("pairs key iterable with __pairs metamethod", () => { + util.testFunction` + class PairsTest { + __pairs() { + const kvp = [ ["a1", true], ["b1", true], ["c1", true] ]; + let i = 0; + return () => { + if (i < kvp.length) { + const [k, v] = kvp[i++]; + return $multi(k, v); + } + }; + } + } + const tester = new PairsTest() as PairsTest & LuaPairsKeyIterable; + const results: Record = {}; + for (const k of tester) { + results[k] = true; + } + return results; + ` + .withLanguageExtensions() + .setOptions({ luaTarget: LuaTarget.Lua53 }) + .expectToEqual({ a1: true, b1: true, c1: true }); +}); diff --git a/test/unit/language-extensions/range.spec.ts b/test/unit/language-extensions/range.spec.ts index 56ac65251..3fc5539f6 100644 --- a/test/unit/language-extensions/range.spec.ts +++ b/test/unit/language-extensions/range.spec.ts @@ -1,12 +1,6 @@ -import * as path from "path"; import * as util from "../../util"; -import * as tstl from "../../../src"; import { invalidRangeControlVariable, invalidRangeUse } from "../../../src/transformation/utils/diagnostics"; -const rangeProjectOptions: tstl.CompilerOptions = { - types: [path.resolve(__dirname, "../../../language-extensions")], -}; - test("$range basic use", () => { util.testFunction` const result: number[] = []; @@ -15,7 +9,7 @@ test("$range basic use", () => { } return result; ` - .setOptions(rangeProjectOptions) + .withLanguageExtensions() .expectToEqual([1, 2, 3, 4, 5]); }); @@ -27,7 +21,7 @@ test("$range basic use with step", () => { } return result; ` - .setOptions(rangeProjectOptions) + .withLanguageExtensions() .expectToEqual([1, 3, 5, 7, 9]); }); @@ -39,7 +33,7 @@ test("$range basic use reverse", () => { } return result; ` - .setOptions(rangeProjectOptions) + .withLanguageExtensions() .expectToEqual([5, 4, 3, 2, 1]); }); @@ -48,7 +42,7 @@ test("$range invalid control variable", () => { let i: number; for (i of $range(1, 5)) {} ` - .setOptions(rangeProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidRangeControlVariable.code]); }); @@ -63,6 +57,6 @@ test.each([ util.testFunction` ${statement} ` - .setOptions(rangeProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidRangeUse.code]); }); diff --git a/test/unit/language-extensions/table.spec.ts b/test/unit/language-extensions/table.spec.ts index e6d485a04..13af766fa 100644 --- a/test/unit/language-extensions/table.spec.ts +++ b/test/unit/language-extensions/table.spec.ts @@ -1,15 +1,5 @@ -import * as path from "path"; import * as util from "../../util"; -import * as tstl from "../../../src"; -import { - invalidTableDeleteExpression, - invalidTableExtensionUse, - invalidTableSetExpression, -} from "../../../src/transformation/utils/diagnostics"; - -const tableProjectOptions: tstl.CompilerOptions = { - types: [path.resolve(__dirname, "../../../language-extensions")], -}; +import { invalidCallExtensionUse } from "../../../src/transformation/utils/diagnostics"; describe("LuaTableGet & LuaTableSet extensions", () => { test("stand-alone function", () => { @@ -21,11 +11,29 @@ describe("LuaTableGet & LuaTableSet extensions", () => { const result = getTable(tbl, "foo"); export { result } ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .setReturnExport("result") .expectToEqual(3); }); + test("stand-alone function with preceding statements", () => { + util.testModule` + declare const setTable: LuaTableSet<{}, string, string>; + const values: any[] = [] + const tbl: any = {}; + const get = (value: any) => { + values.push(value) + return value + } + let x = "a" + setTable(tbl, x += "b", x += "c") + export const result = tbl.ab + ` + .withLanguageExtensions() + .setReturnExport("result") + .expectToEqual("abc"); + }); + test("namespace function", () => { util.testModule` declare namespace Table { @@ -37,7 +45,7 @@ describe("LuaTableGet & LuaTableSet extensions", () => { const result = Table.get(tbl, "foo"); export { result } ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .setReturnExport("result") .expectToEqual(3); }); @@ -53,7 +61,7 @@ describe("LuaTableGet & LuaTableSet extensions", () => { const result = tbl.get("foo"); export { result } ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .setReturnExport("result") .expectToEqual(3); }); @@ -69,22 +77,8 @@ describe("LuaTableGet & LuaTableSet extensions", () => { declare const getTable: LuaTableGet<{}, string, number>; ${statement} ` - .setOptions(tableProjectOptions) - .expectDiagnosticsToMatchSnapshot([invalidTableExtensionUse.code]); - }); - - test.each([ - 'const foo = setTable({}, "foo", 3);', - 'const foo = `${setTable({}, "foo", 3)}`;', - 'declare function foo(arg: any): void; foo(setTable({}, "foo", 3));', - 'const foo = [setTable({}, "foo", 3)];', - ])("LuaTableSet invalid use as expression (%p)", expression => { - util.testModule` - declare const setTable: LuaTableSet<{}, string, number>; - ${expression} - ` - .setOptions(tableProjectOptions) - .expectDiagnosticsToMatchSnapshot([invalidTableSetExpression.code]); + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot([invalidCallExtensionUse.code]); }); }); @@ -97,7 +91,7 @@ describe("LuaTableHas extension", () => { export const hasFoo = tableHas(table, "foo"); export const hasBaz = tableHas(table, "baz"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ hasFoo: true, hasBaz: false }); }); @@ -108,7 +102,7 @@ describe("LuaTableHas extension", () => { export const result = \`table has foo: \${tableHas(table, "foo")}\`; ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ result: "table has foo: true" }); }); @@ -122,7 +116,7 @@ describe("LuaTableHas extension", () => { export const hasFoo = Table.tableHas(table, "foo"); export const hasBaz = Table.tableHas(table, "baz"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ hasFoo: true, hasBaz: false }); }); @@ -138,7 +132,7 @@ describe("LuaTableHas extension", () => { export const hasFoo = table.has("foo"); export const hasBaz = table.has("baz"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ hasFoo: true, hasBaz: false }); }); @@ -158,7 +152,7 @@ describe("LuaTableHas extension", () => { export const numCalls = count; ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ numCalls: 1 }); }); @@ -173,9 +167,33 @@ describe("LuaTableHas extension", () => { declare const tableHas: LuaTableHas<{}, string>; ${statement} ` - .setOptions(tableProjectOptions) - .expectDiagnosticsToMatchSnapshot([invalidTableExtensionUse.code]); + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot([invalidCallExtensionUse.code]); }); + + test.each(["LuaTable", "LuaMap", "LuaSet"])( + "invalid use method assignment (%p)", + type => { + util.testModule` + const table = new ${type}(); + const has = table.has; + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot([invalidCallExtensionUse.code]); + } + ); + + test.each(["LuaTable", "LuaMap", "LuaSet"])( + "invalid use method expression (%p)", + type => { + util.testModule` + const table = new ${type}(); + ["a", "b", "c"].map(table.has); + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot([invalidCallExtensionUse.code]); + } + ); }); describe("LuaTableDelete extension", () => { @@ -186,7 +204,7 @@ describe("LuaTableDelete extension", () => { export const table = { foo: "bar", baz: "baz" }; tableDelete(table, "foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ table: { baz: "baz" } }); }); @@ -199,11 +217,11 @@ describe("LuaTableDelete extension", () => { export const table = { foo: "bar", baz: "baz" }; Table.tableDelete(table, "foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ table: { baz: "baz" } }); }); - test("LuaTableHasMethod method", () => { + test("LuaTableDeleteMethod method", () => { util.testModule` interface TableWithDelete { delete: LuaTableDeleteMethod; @@ -214,22 +232,129 @@ describe("LuaTableDelete extension", () => { table.set("bar", 12); table.delete("foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ table: { bar: 12 } }); }); +}); + +describe("LuaTableAddKey extension", () => { + test("LuaTableAddKey standalone function", () => { + util.testModule` + declare const tableAddKey: LuaTableAddKey<{}, string>; + export const table = { foo: "bar" }; + tableAddKey(table, "baz"); + ` + .withLanguageExtensions() + .expectToEqual({ table: { foo: "bar", baz: true } }); + }); + + test("LuaTableAddKey namespace function", () => { + util.testModule` + declare namespace Table { + export const tableAddKey: LuaTableAddKey<{}, string>; + } + export const table = { foo: "bar" }; + Table.tableAddKey(table, "baz"); + ` + .withLanguageExtensions() + .expectToEqual({ table: { foo: "bar", baz: true } }); + }); + + test("LuaTableAddKey method", () => { + util.testModule` + interface TableWithAddKey { + addKey: LuaTableAddKeyMethod; + } + export const table = {} as TableWithAddKey; + table.addKey("bar"); + ` + .withLanguageExtensions() + .expectToEqual({ table: { bar: true } }); + }); +}); + +describe("LuaIsEmpty extension", () => { + test("LuaIsEmpty standalone function", () => { + util.testModule` + declare const isTableEmpty: LuaTableIsEmpty<{}>; + + const table = { foo: "bar", baz: "baz" }; + const emptyTable = {}; + + export const result = [isTableEmpty(table), isTableEmpty(emptyTable)]; + ` + .withLanguageExtensions() + .expectToEqual({ result: [false, true] }); + }); + + test("LuaIsEmpty namespace function", () => { + util.testModule` + declare namespace Table { + export const isTableEmpty: LuaTableIsEmpty<{}>; + } + + const table = { foo: "bar", baz: "baz" }; + const emptyTable = {}; + + export const result = [Table.isTableEmpty(table), Table.isTableEmpty(emptyTable)]; + ` + .withLanguageExtensions() + .expectToEqual({ result: [false, true] }); + }); + + test("LuaTableIsEmptyMethod method", () => { + util.testModule` + interface TableWithIsEmpty { + isEmpty: LuaTableIsEmptyMethod; + set: LuaTableSetMethod; + } + const table = {} as TableWithIsEmpty; + table.set("foo", 42); + table.set("bar", 12); + + const emptyTable = {} as TableWithIsEmpty; + + export const result = [table.isEmpty(), emptyTable.isEmpty()]; + ` + .withLanguageExtensions() + .expectToEqual({ result: [false, true] }); + }); +}); +describe("Table extensions use as expression", () => { test.each([ - 'const foo = tableDelete({}, "foo");', - 'const foo = `${tableDelete({}, "foo")}`;', - 'declare function foo(arg: any): void; foo(tableDelete({}, "foo"));', - 'const foo = [tableDelete({}, "foo")];', - ])("LuaTableDelete invalid use as expression (%p)", expression => { + ["LuaTableAddKey<{}, string>", 'func({}, "foo")', undefined], + ["LuaTableAddKey<{}, string>", '"truthy" && func({}, "foo")', undefined], + ["LuaTableDelete<{}, string>", 'func({}, "foo")', true], + ["LuaTableDelete<{}, string>", '"truthy" && func({}, "foo")', true], + ["LuaTableSet<{}, string, number>", 'func({}, "foo", 3)', undefined], + ["LuaTableIsEmpty<{}>", "func({})", true], + ["LuaTableIsEmpty<{}>", 'func({ foo: "bar", baz: "baz" })', false], + ["LuaTableIsEmpty<{}>", '"truthy" && func({})', true], + ])("functions used as expression", (funcType, expression, value) => { util.testModule` - declare const tableDelete: LuaTableDelete<{}, string>; - ${expression} + declare const func: ${funcType} + export const result = ${expression} ` - .setOptions(tableProjectOptions) - .expectDiagnosticsToMatchSnapshot([invalidTableDeleteExpression.code]); + .withLanguageExtensions() + .setReturnExport("result") + .ignoreDiagnostics([2872 /* TS2872: This kind of expression is always truthy. */]) + .expectToEqual(value); + }); + + test.each([ + ["LuaTableDeleteMethod", 'tbl.func("foo")', true], + ["LuaTableSetMethod", 'tbl.func("foo", 3)', undefined], + ["LuaTableAddKeyMethod", 'tbl.func("foo")', undefined], + ["LuaTableIsEmpty<{}>", "tbl.func({})", true], + ])("methods used as expression", (funcType, expression, value) => { + util.testModule` + const tbl = {} as { func: ${funcType} } + export const result = ${expression} + ` + .withLanguageExtensions() + .setReturnExport("result") + .expectToEqual(value); }); }); @@ -240,7 +365,7 @@ describe("LuaTable extension interface", () => { tbl.set("foo", 3); return tbl.get("foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual(3); }); @@ -250,7 +375,7 @@ describe("LuaTable extension interface", () => { tbl.set("foo", 3); return tbl.get("foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual(3); }); @@ -263,7 +388,7 @@ describe("LuaTable extension interface", () => { } return fill(new LuaTable()).get("foo"); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual(3); }); @@ -271,7 +396,8 @@ describe("LuaTable extension interface", () => { "LuaTable in strict mode does not accept key type that could be nil (%p)", keyType => { util.testExpression`new LuaTable<${keyType}, unknown>()` - .setOptions({ ...tableProjectOptions, strict: true }) + .withLanguageExtensions() + .setOptions({ strict: true }) .expectToHaveDiagnostics() .expectDiagnosticsToMatchSnapshot(); } @@ -285,7 +411,7 @@ describe("LuaTable extension interface", () => { tbl.set(key, 3); return tbl.get(key); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual(3); }); @@ -296,7 +422,7 @@ describe("LuaTable extension interface", () => { tbl.set(3, "bar"); return tbl.length(); ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual(1); }); @@ -306,7 +432,7 @@ describe("LuaTable extension interface", () => { tbl.set(3, "foo"); return [tbl.has(1), tbl.has(3)]; ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual([false, true]); }); @@ -320,14 +446,94 @@ describe("LuaTable extension interface", () => { tbl.delete("foo"); return tbl; ` - .setOptions(tableProjectOptions) + .withLanguageExtensions() .expectToEqual({ baz: 5 }); }); + test("table isEmpty", () => { + util.testFunction` + const tbl = new LuaTable(); + tbl.set("foo", 1); + + const emptyTbl = new LuaTable(); + + return [tbl.isEmpty(), emptyTbl.isEmpty()]; + ` + .withLanguageExtensions() + .expectToEqual([false, true]); + }); + + test("table add", () => { + util.testFunction` + const tbl = new LuaSet(); + tbl.add("foo"); + return tbl + ` + .withLanguageExtensions() + .expectToEqual({ foo: true }); + }); + test.each(['new LuaTable().get("foo");', 'new LuaTable().set("foo", "bar");'])( "table immediate access (%p)", statement => { - util.testFunction(statement).setOptions(tableProjectOptions).expectToHaveNoDiagnostics(); + util.testFunction(statement).withLanguageExtensions().expectToHaveNoDiagnostics(); } ); + + test("table pairs iterate", () => { + util.testFunction` + const tbl = new LuaTable(); + tbl.set("foo", 1); + tbl.set("bar", 3); + tbl.set("baz", 5); + const results: Record = {}; + for (const [k, v] of tbl) { + results[k] = v; + } + return results; + ` + .withLanguageExtensions() + .expectToEqual({ foo: 1, bar: 3, baz: 5 }); + }); +}); + +test.each([ + [undefined, undefined], + ["new LuaSet()", true], +])("call on optional table with strictNullChecks (%s)", (value, expected) => { + util.testFunction` + function getFoo(): LuaSet | undefined { + return ${value} + } + const foo = getFoo() + foo?.add("foo") + return foo?.has("foo") + ` + .setOptions({ + strictNullChecks: true, + }) + .withLanguageExtensions() + .expectToEqual(expected); +}); + +describe("does not crash on invalid extension use", () => { + test("global function", () => { + util.testModule` + declare const op: LuaTableGet<{}, string, any> + op({}) + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot(); + }); + + test("method", () => { + util.testModule` + const left = {} as { + op: LuaTableGet<{}, string, any> + } + left.op() + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot(); + }); }); diff --git a/test/unit/language-extensions/vararg.spec.ts b/test/unit/language-extensions/vararg.spec.ts index f92cc0f96..d5aa9fc69 100644 --- a/test/unit/language-extensions/vararg.spec.ts +++ b/test/unit/language-extensions/vararg.spec.ts @@ -1,23 +1,18 @@ -import * as path from "path"; import * as util from "../../util"; -import * as tstl from "../../../src"; import { invalidVarargUse } from "../../../src/transformation/utils/diagnostics"; -const varargProjectOptions: tstl.CompilerOptions = { - types: [path.resolve(__dirname, "../../../language-extensions")], -}; - test.each([ 'const result = [...$vararg].join("")', 'let result: string; { result = [...$vararg].join(""); }', 'let result: string; if (true) { result = [...$vararg].join(""); }', 'let result: string; do { result = [...$vararg].join(""); } while (false);', + 'function foo(...args: unknown[]) { return args.join(""); } const result = foo(...$vararg);', ])("$vararg valid use (%p)", statement => { util.testModule` ${statement} export { result }; ` - .setOptions(varargProjectOptions) + .withLanguageExtensions() .setLuaFactory(code => `return (function(...) ${code} end)("A", "B", "C", "D")`) .tap(builder => expect(builder.getMainLuaCodeChunk()).not.toMatch("unpack")) .expectToEqual({ result: "ABCD" }); @@ -33,6 +28,28 @@ test.each([ util.testModule` ${statement} ` - .setOptions(varargProjectOptions) + .withLanguageExtensions() .expectDiagnosticsToMatchSnapshot([invalidVarargUse.code]); }); + +test("$vararg in bundle entry point", () => { + util.testModule` + export const result = [...$vararg].join(""); + ` + .setMainFileName("src/main.ts") + .setOptions({ rootDir: "src", luaBundle: "bundle.lua", luaBundleEntry: "src/main.ts" }) + .withLanguageExtensions() + .setLuaFactory(code => `return (function(...) ${code} end)("A", "B", "C", "D")`) + .expectToEqual({ result: "ABCD" }); +}); + +test("$vararg in bundle sub-module", () => { + util.testModule` + export { result } from "./module"; + ` + .setMainFileName("src/main.ts") + .addExtraFile("src/module.ts", 'export const result = [...$vararg].join("")') + .setOptions({ rootDir: "src", luaBundle: "bundle.lua", luaBundleEntry: "src/main.ts" }) + .withLanguageExtensions() + .expectToEqual({ result: "module" }); +}); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index a3d4db239..e6ceab5db 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -1,5 +1,6 @@ import * as tstl from "../../src"; -import { forbiddenForIn, unsupportedForTarget } from "../../src/transformation/utils/diagnostics"; +import { LuaTarget } from "../../src"; +import { forbiddenForIn } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test("while", () => { @@ -14,8 +15,9 @@ test("while", () => { `.expectToMatchJsResult(); }); -test("while with continue", () => { - util.testFunction` +util.testEachVersion( + "while with continue", + () => util.testFunction` let arrTest = [0, 1, 2, 3, 4]; let i = 0; while (i < arrTest.length) { @@ -36,11 +38,13 @@ test("while with continue", () => { i++; } return arrTest; - `.expectToMatchJsResult(); -}); + `, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); -test("dowhile with continue", () => { - util.testFunction` +util.testEachVersion( + "dowhile with continue", + () => util.testFunction` let arrTest = [0, 1, 2, 3, 4]; let i = 0; do { @@ -61,8 +65,9 @@ test("dowhile with continue", () => { i++; } while (i < arrTest.length) return arrTest; - `.expectToMatchJsResult(); -}); + `, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); test("for", () => { util.testFunction` @@ -85,8 +90,9 @@ test("for with expression", () => { `.expectToMatchJsResult(); }); -test("for with continue", () => { - util.testFunction` +util.testEachVersion( + "for with continue", + () => util.testFunction` let arrTest = [0, 1, 2, 3, 4]; for (let i = 0; i < arrTest.length; i++) { if (i % 2 == 0) { @@ -101,8 +107,9 @@ test("for with continue", () => { } } return arrTest; - `.expectToMatchJsResult(); -}); + `, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); test("forMirror", () => { util.testFunction` @@ -201,7 +208,7 @@ test.each([ }, ])("forin[Object] (%p)", ({ inp }) => { util.testFunctionTemplate` - let objTest = ${inp}; + let objTest: Record = ${inp}; for (let key in objTest) { objTest[key] = objTest[key] + 1; } @@ -211,14 +218,27 @@ test.each([ test("forin[Array]", () => { util.testFunction` - const array = []; + const array = [1,2,3]; for (const key in array) {} `.expectDiagnosticsToMatchSnapshot([forbiddenForIn.code]); }); -test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 } }])("forin with continue (%p)", ({ inp }) => { +const luaTargetsExceptJit = [ + LuaTarget.Lua50, + LuaTarget.Lua51, + LuaTarget.Lua52, + LuaTarget.Lua53, + LuaTarget.Lua54, + LuaTarget.Universal, +]; + +test.each( + luaTargetsExceptJit.flatMap(target => + [{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 } }].map(testCase => [target, testCase] as const) + ) +)("forin with continue (%s %p)", (luaTarget, { inp }) => { util.testFunctionTemplate` - let obj = ${inp}; + let obj: Record = ${inp}; for (let i in obj) { if (obj[i] % 2 == 0) { continue; @@ -227,7 +247,9 @@ test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 } }])("forin with continue (%p) obj[i] = 0; } return obj; - `.expectToMatchJsResult(); + ` + .setOptions({ luaTarget }) + .expectToMatchJsResult(); }); test.each([{ inp: [0, 1, 2] }])("forof (%p)", ({ inp }) => { @@ -279,6 +301,39 @@ test("forof destructing", () => { `.expectToMatchJsResult(); }); +test("forof destructing scope", () => { + util.testFunction` + let x = 7; + for (let [x] of [[1], [2], [3]]) { + x *= 2; + } + return x; + `.expectToMatchJsResult(); +}); + +// This catches the case where x is falsely seen as globally scoped and the 'local' is stripped out +test("forof destructing scope (global)", () => { + util.testModule` + let x = 7; + for (let [x] of [[1], [2], [3]]) { + x *= 2; + } + if (x !== 7) throw x; + `.expectNoExecutionError(); +}); + +test("forof nested destructing", () => { + util.testFunction` + const obj = { a: [3], b: [5] }; + let result = 0; + + for(const [k, [v]] of Object.entries(obj)){ + result += v; + } + return result; + `.expectToMatchJsResult(); +}); + test("forof destructing with existing variables", () => { const input = [ [1, 2], @@ -298,8 +353,9 @@ test("forof destructing with existing variables", () => { `.expectToMatchJsResult(); }); -test("forof with continue", () => { - util.testFunction` +util.testEachVersion( + "forof with continue", + () => util.testFunction` let testArr = [0, 1, 2, 3, 4]; let a = 0; for (let i of testArr) { @@ -317,8 +373,9 @@ test("forof with continue", () => { a++; } return testArr; - `.expectToMatchJsResult(); -}); + `, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) +); test("forof with iterator", () => { util.testFunction` @@ -467,8 +524,12 @@ describe("for...of empty destructuring", () => { }); }; - describe("declaration", () => declareTests("const ")); - describe("assignment", () => declareTests("")); + describe("declaration", () => { + declareTests("const "); + }); + describe("assignment", () => { + declareTests(""); + }); }); for (const testCase of [ @@ -478,19 +539,42 @@ for (const testCase of [ "for (const a in {}) { continue; }", "for (const a of []) { continue; }", ]) { + const expectContinueVariable: util.TapCallback = builder => + expect(builder.getMainLuaCodeChunk()).toMatch(/local __continue\d+/); + const expectContinueGotoLabel: util.TapCallback = builder => - expect(builder.getMainLuaCodeChunk()).toMatch("::__continue2::"); + expect(builder.getMainLuaCodeChunk()).toMatch(/::__continue\d+::/); + + const expectContinueStatement: util.TapCallback = builder => + expect(builder.getMainLuaCodeChunk()).toMatch("continue;"); util.testEachVersion(`loop continue (${testCase})`, () => util.testModule(testCase), { - [tstl.LuaTarget.Universal]: builder => builder.expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]), - [tstl.LuaTarget.Lua51]: builder => builder.expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]), + [tstl.LuaTarget.Universal]: expectContinueVariable, + [tstl.LuaTarget.Lua50]: expectContinueVariable, + [tstl.LuaTarget.Lua51]: expectContinueVariable, [tstl.LuaTarget.Lua52]: expectContinueGotoLabel, [tstl.LuaTarget.Lua53]: expectContinueGotoLabel, [tstl.LuaTarget.Lua54]: expectContinueGotoLabel, + [tstl.LuaTarget.Lua55]: expectContinueGotoLabel, [tstl.LuaTarget.LuaJIT]: expectContinueGotoLabel, + [tstl.LuaTarget.Luau]: () => expectContinueStatement, }); } +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1638 +test.each([tstl.LuaTarget.Universal, tstl.LuaTarget.Lua50, tstl.LuaTarget.Lua51])( + "no unreachable code when using continue for target %s (#1638)", + target => { + util.testFunction` + let i = 0; + while(++i < 10) continue; + return i; + ` + .setOptions({ luaTarget: target }) + .expectToMatchJsResult(); + } +); + test("do...while", () => { util.testFunction` let result = 0; @@ -555,3 +639,12 @@ test("for...in with pre-defined variable keeps last value", () => { // Need custom matcher because order is not guaranteed in neither JS nor Lua expect([keyX, keyFoo]).toContain(result); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1631 +test("loop variables should not be global (#1631)", () => { + const code = util.testModule` + for (let val = 0; val < 2; ++val) {} + `.getMainLuaCodeChunk(); + + expect(code).toContain("local val"); +}); diff --git a/test/unit/modules/__snapshots__/resolution.spec.ts.snap b/test/unit/modules/__snapshots__/resolution.spec.ts.snap index 4db74c57f..8c40101e5 100644 --- a/test/unit/modules/__snapshots__/resolution.spec.ts.snap +++ b/test/unit/modules/__snapshots__/resolution.spec.ts.snap @@ -2,9 +2,9 @@ exports[`doesn't resolve paths out of root dir: code 1`] = ` "local ____exports = {} -local module = require(\\"module\\") +local module = require("module") local ____ = module return ____exports" `; -exports[`doesn't resolve paths out of root dir: diagnostics 1`] = `"error TSTL: Could not resolve require path '../module' in file main.ts."`; +exports[`doesn't resolve paths out of root dir: diagnostics 1`] = `"error TSTL: Could not resolve lua source files for require path '../module' in file main.ts."`; diff --git a/test/unit/modules/modules.spec.ts b/test/unit/modules/modules.spec.ts index ffdc36ce9..1969806d0 100644 --- a/test/unit/modules/modules.spec.ts +++ b/test/unit/modules/modules.spec.ts @@ -94,8 +94,7 @@ test("Default Import and Export Expression", () => { test("Import and Export Assignment", () => { util.testModule` - // @ts-ignore - import * as m from "./module"; + import m = require("./module"); export const value = m; ` .setOptions({ module: ts.ModuleKind.CommonJS }) @@ -280,3 +279,36 @@ test("namespace export with unsafe Lua name", () => { .addExtraFile("module.ts", moduleFile) .expectToMatchJsResult(); }); + +test("import expression", () => { + util.testModule` + let result; + import("./module").then(m => { result = m.foo(); }); + export { result }; + ` + .addExtraFile("module.ts", 'export function foo() { return "foo"; }') + .setOptions({ module: ts.ModuleKind.ESNext }) + .expectToEqual({ result: "foo" }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1572 +test("correctly exports @compileMembersOnly enums (#1572)", () => { + util.testModule` + export { val } from "./otherfile"; + ` + .addExtraFile( + "otherfile.ts", + ` + // Would put this in the main file, but we cannot transfer enum types over lua/js boundary + // but we still need to have an exported enum, hence it is in another file + /** @compileMembersOnly */ + export enum MyEnum { + A = 0, + B = 1, + C = 2 + } + export const val = MyEnum.B | MyEnum.C; + ` + ) + .expectToEqual({ val: 3 }); +}); diff --git a/test/unit/modules/resolution.spec.ts b/test/unit/modules/resolution.spec.ts index b2c7194b5..c6f97d5f9 100644 --- a/test/unit/modules/resolution.spec.ts +++ b/test/unit/modules/resolution.spec.ts @@ -1,5 +1,6 @@ +import * as path from "path"; import * as ts from "typescript"; -import { couldNotResolveRequire } from "../../../src/transpilation/diagnostics"; +import { couldNotResolveRequire, emitPathCollision } from "../../../src/transpilation/diagnostics"; import * as util from "../../util"; const requireRegex = /require\("(.*?)"\)/; @@ -87,6 +88,37 @@ test("doesn't resolve paths out of root dir", () => { .expectDiagnosticsToMatchSnapshot([couldNotResolveRequire.code]); }); +test("resolves non-standard requires", () => { + const { transpiledFiles } = util.testModule` + export * from "./externalLua"; + ` + .addExtraFile("externalLua.d.ts", "export const foo = 3;") + .addExtraFile( + "externalLua.lua", + ` + require("requiredLuaFile1") -- standard + require('requiredLuaFile2') -- single quote + require'requiredLuaFile3' -- no parentheses + require"requiredLuaFile4" -- no parentheses double quote + require "requiredLuaFile5" -- no parentheses and space + require "requiredLua'File6" -- no parentheses and space + require 'requiredLua"File7' -- no parentheses and space + ` + ) + .addExtraFile("requiredLuaFile1.lua", "") + .addExtraFile("requiredLuaFile2.lua", "") + .addExtraFile("requiredLuaFile3.lua", "") + .addExtraFile("requiredLuaFile4.lua", "") + .addExtraFile("requiredLuaFile5.lua", "") + .addExtraFile("requiredLua'File6.lua", "") + .addExtraFile('requiredLua"File7.lua', "") + .expectToHaveNoDiagnostics() + .getLuaResult(); + + // Expect main.lua, externalLua.lua and all 7 required lua files in there + expect(transpiledFiles.map(f => f.outPath)).toHaveLength(9); +}); + test.each([ { declarationStatement: ` @@ -135,6 +167,52 @@ test.each([ .tap(expectToRequire(expectedPath)); }); +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1445 +// Can't test this via execution because the test harness uses package.preload +// instead of real filesystem resolution, so require() always finds the module +// regardless of output path. We check the output path directly instead. +test("dots in directory names are replaced with underscores in output", () => { + const { transpiledFiles } = util.testModule` + import { answer } from "./Foo.Bar"; + export const result = answer; + ` + .addExtraFile("Foo.Bar/index.ts", "export const answer = 42;") + .setOptions({ rootDir: "." }) + .getLuaResult(); + + const dottedFile = transpiledFiles.find(f => f.lua?.includes("answer = 42")); + expect(dottedFile).toBeDefined(); + expect(dottedFile!.outPath).toContain(path.join("Foo_Bar", "index.lua")); + expect(dottedFile!.outPath).not.toContain("Foo.Bar"); +}); + +test("dots in file names are replaced with underscores in output", () => { + const { transpiledFiles } = util.testModule` + import { answer } from "./foo.test"; + export const result = answer; + ` + .addExtraFile("foo.test.ts", "export const answer = 42;") + .setOptions({ rootDir: "." }) + .getLuaResult(); + + const dottedFile = transpiledFiles.find(f => f.lua?.includes("answer = 42")); + expect(dottedFile).toBeDefined(); + expect(dottedFile!.outPath).toContain("foo_test.lua"); + expect(dottedFile!.outPath).not.toContain("foo.test"); +}); + +test("dots in paths that collide with existing paths produce a diagnostic", () => { + util.testModule` + import { a } from "./Foo.Bar"; + import { b } from "./Foo_Bar"; + export const result = a + b; + ` + .addExtraFile("Foo.Bar/index.ts", "export const a = 1;") + .addExtraFile("Foo_Bar/index.ts", "export const b = 2;") + .setOptions({ rootDir: "." }) + .expectToHaveDiagnostics([emitPathCollision.code]); +}); + test("import = require", () => { util.testModule` import foo = require("./foo/bar"); diff --git a/test/unit/namespaces.spec.ts b/test/unit/namespaces.spec.ts index 762152d67..7c98e7ef9 100644 --- a/test/unit/namespaces.spec.ts +++ b/test/unit/namespaces.spec.ts @@ -1,15 +1,5 @@ import * as util from "../util"; -test("legacy internal module syntax", () => { - util.testModule` - module Foo { - export const foo = "bar"; - } - - export const foo = Foo.foo; - `.expectToMatchJsResult(); -}); - test("global scoping", () => { util.testFunction("return a.foo();") .setTsHeader('namespace a { export function foo() { return "bar"; } }') @@ -42,7 +32,7 @@ test("context in namespace function", () => { util.testModule` namespace a { export const foo = "foo"; - export function bar() { return this.foo + "bar"; } + export function bar(this: typeof a) { return this.foo + "bar"; } } export const result = a.bar(); @@ -144,3 +134,15 @@ test("enum in a namespace", () => { export const result = Test.TestEnum.A; `.expectToMatchJsResult(); }); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1431 +test("nested namespaces (#1431)", () => { + util.testModule` + namespace Foo.Bar {} + namespace Foo.Bar { + export const baz = 32; + } + + export { Foo } + `.expectToMatchJsResult(); +}); diff --git a/test/unit/nullishCoalescing.spec.ts b/test/unit/nullishCoalescing.spec.ts index 67dbc1cec..56db55332 100644 --- a/test/unit/nullishCoalescing.spec.ts +++ b/test/unit/nullishCoalescing.spec.ts @@ -1,18 +1,26 @@ import * as util from "../util"; test.each(["null", "undefined"])("nullish-coalesing operator returns rhs", nullishValue => { - util.testExpression`${nullishValue} ?? "Hello, World!"`.expectToMatchJsResult(); + util.testExpression`${nullishValue} ?? "Hello, World!"` + .ignoreDiagnostics([2871 /* TS2871: This expression is always nullish. */]) + .expectToMatchJsResult(); }); test.each([3, "foo", {}, [], true, false])("nullish-coalesing operator returns lhs", value => { - util.testExpression`${util.formatCode(value)} ?? "Hello, World!"`.expectToMatchJsResult(); + util.testExpression`${util.formatCode(value)} ?? "Hello, World!"` + .ignoreDiagnostics([ + 2869 /* TS2869: Right operand of ?? is unreachable because the left operand is never nullish. */, + ]) + .expectToMatchJsResult(); }); test.each(["any", "unknown"])("nullish-coalesing operator with any/unknown type", type => { util.testFunction` const unknownType = false as ${type}; return unknownType ?? "This should not be returned!"; - `.expectToMatchJsResult(); + ` + .ignoreDiagnostics([2871 /* TS2871: This expression is always nullish. */]) + .expectToMatchJsResult(); }); test.each(["boolean | string", "number | false", "undefined | true"])( @@ -38,5 +46,30 @@ test("nullish-coalescing operator with side effect rhs", () => { let i = 0; const incI = () => ++i; return [i, undefined ?? incI(), i]; + ` + .ignoreDiagnostics([2871 /* TS2871: This expression is always nullish. */]) + .expectToMatchJsResult(); +}); + +test("nullish-coalescing operator with vararg", () => { + util.testFunction` + + function foo(...args: any[]){ + return args + } + function bar(...args: any[]) { + let x: boolean | undefined = false + const y = x ?? foo(...args) + } + return bar(1, 2) + `.expectToMatchJsResult(); +}); + +test.each([true, false, null])("nullish-coalescing with generic lhs (%p)", lhs => { + util.testFunction` + function coalesce(a: A, b: B) { + return a ?? b + } + return coalesce(${lhs}, "wasNull") `.expectToMatchJsResult(); }); diff --git a/test/unit/objectLiteral.spec.ts b/test/unit/objectLiteral.spec.ts index 819143e1f..16e7582d0 100644 --- a/test/unit/objectLiteral.spec.ts +++ b/test/unit/objectLiteral.spec.ts @@ -63,3 +63,66 @@ test.each(['{x: "foobar"}.x', '{x: "foobar"}["x"]', '{x: () => "foobar"}.x()', ' util.testExpression(expression).expectToMatchJsResult(); } ); + +describe("noSelf in functions", () => { + test("Explicit this: void parameter", () => { + // language=TypeScript + util.testFunction` + const obj: Record string> = { + method(a) { + return a; + }, + func: function(a) { + return a; + }, + arrow: (a) => { + return a; + } + }; + return [obj.method("a") ?? "nil", obj.func("b") ?? "nil", obj.arrow("c") ?? "nil"]; + `.expectToMatchJsResult(); + }); + + test("No self annotation", () => { + // language=TypeScript + util.testFunction` + const obj: Record string> = { + method(a) { + return a; + }, + func: function(a) { + return a; + }, + arrow: (a) => { + return a; + } + }; + return [obj.method("a") ?? "nil", obj.func("b") ?? "nil", obj.arrow("c") ?? "nil"]; + `.expectToMatchJsResult(); + }); + + test("individual function types", () => { + // language=TypeScript + util.testFunction` + interface FunctionContainer { + method: (this: void, a: string) => string + func: (this: void, a: string) => string + arrow: (this: void, a: string) => string + } + + const obj: FunctionContainer = { + method(a) { + return a + }, + func: function(a) { + return a + }, + arrow: (a) => { + return a + } + } + + return [obj.method("a") ?? "nil", obj.func("b") ?? "nil", obj.arrow("c") ?? "nil"]; + `.expectToMatchJsResult(); + }); +}); diff --git a/test/unit/optionalChaining.spec.ts b/test/unit/optionalChaining.spec.ts index 26deff810..10de7e792 100644 --- a/test/unit/optionalChaining.spec.ts +++ b/test/unit/optionalChaining.spec.ts @@ -1,22 +1,29 @@ +import { notAllowedOptionalAssignment } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test.each(["null", "undefined", '{ foo: "foo" }'])("optional chaining (%p)", value => { util.testFunction` - const obj: any = ${value}; + const obj = ${value} as {foo: string} | null | undefined; return obj?.foo; - `.expectToMatchJsResult(); + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should use "and" expression }); test("long optional chain", () => { util.testFunction` const a = { b: { c: { d: { e: { f: "hello!"}}}}}; return a.b?.c?.d.e.f; - `.expectToMatchJsResult(); + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should use "and" expression }); test.each(["undefined", "{}", "{ foo: {} }", "{ foo: {bar: 'baz'}}"])("nested optional chaining (%p)", value => { util.testFunction` - const obj: { foo?: { bar?: string } } | undefined = ${value}; + const obj = ${value} as { foo?: { bar?: string } } | undefined; return obj?.foo?.bar; `.expectToMatchJsResult(); }); @@ -25,7 +32,7 @@ test.each(["undefined", "{}", "{ foo: {} }", "{ foo: {bar: 'baz'}}"])( "nested optional chaining combined with coalescing (%p)", value => { util.testFunction` - const obj: { foo?: { bar?: string } } | undefined = ${value}; + const obj = ${value} as { foo?: { bar?: string } } | undefined; return obj?.foo?.bar ?? "not found"; `.expectToMatchJsResult(); } @@ -67,11 +74,97 @@ test("optional element function calls", () => { const fooKey = "foo"; const barKey = "bar"; return obj[barKey]?.(5) ?? obj[fooKey]?.(15); - `.expectToMatchJsResult(); + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should still use "and" statement, as functions have no self }); -test("optional element access method calls", () => { +test("unused expression", () => { util.testFunction` + const obj = { foo: "bar" }; + obj?.foo; + ` + .expectToHaveNoDiagnostics() + .expectNoExecutionError() + .expectLuaToMatchSnapshot(); + // should use if statement, as result is not used +}); + +test("unused call", () => { + util.testFunction` + let result + const obj = { + foo() { + result = "bar" + } + }; + obj?.foo(); + return result; + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should use if statement, as result is not used +}); + +test.each(["undefined", "{ foo: (v: any)=>v }"])("with preceding statements on right side", value => { + util.testFunction` + let i = 0 + const obj: any = ${value}; + return {result: obj?.foo(i++), i}; + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should use if statement, as there are preceding statements +}); + +// unused, with preceding statements on right side +test.each(["undefined", "{ foo(val: any) {return val} }"])( + "unused result with preceding statements on right side", + value => { + util.testFunction` + let i = 0 + const obj = ${value} as any; + obj?.foo(i++); + return i + ` + .expectToHaveNoDiagnostics() + .expectLuaToMatchSnapshot(); + // should use if statement, as there are preceding statements + } +); + +test.each(["undefined", "{ foo(v: any) { return v} }"])( + "with preceding statements on right side modifying left", + value => { + util.testFunction` + let i = 0 + let obj: any = ${value}; + function bar() { + if(obj) obj.foo = undefined + obj = undefined + return 1 + } + + return {result: obj?.foo(bar(), i++), obj, i} + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + // should use if statement, as there are preceding statements + } +); + +test("does not suppress error if left side is false", () => { + const result = util.testFunction` + const obj: any = false + return obj?.foo + `.getLuaExecutionResult(); + expect(result).toBeInstanceOf(util.ExecutionError); +}); + +describe("optional access method calls", () => { + test("element access call", () => { + util.testFunction` const obj: { value: string; foo?(prefix: string): string; bar?(prefix: string): string; } = { value: "foobar", foo(prefix: string) { return prefix + this.value; } @@ -80,6 +173,39 @@ test("optional element access method calls", () => { const barKey = "bar"; return obj[barKey]?.("bar?") ?? obj[fooKey]?.("foo?"); `.expectToMatchJsResult(); + }); + + test("property access call", () => { + util.testFunction` + const obj: { value: string; foo?(prefix: string): string; bar?(prefix: string): string; } = { + value: "foobar", + foo(prefix: string) { return prefix + this.value; } + } + return obj.foo?.("bar?") ?? obj.bar?.("foo?"); + `.expectToMatchJsResult(); + }); + + test("nested optional element access call", () => { + util.testFunction` + const obj: { value: string; foo?(prefix: string): string; bar?(prefix: string): string; } = { + value: "foobar", + foo(prefix: string) { return prefix + this.value; } + } + const fooKey = "foo"; + const barKey = "bar"; + return obj?.[barKey]?.("bar?") ?? obj?.[fooKey]?.("foo?"); + `.expectToMatchJsResult(); + }); + + test("nested optional property access call", () => { + util.testFunction` + const obj: { value: string; foo?(prefix: string): string; bar?(prefix: string): string; } = { + value: "foobar", + foo(prefix: string) { return prefix + this.value; } + } + return obj?.foo?.("bar?") ?? obj?.bar?.("foo?"); + `.expectToMatchJsResult(); + }); }); test("no side effects", () => { @@ -97,10 +223,19 @@ test("no side effects", () => { `.expectToMatchJsResult(); }); +// Test for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1044 +test("does not crash when incorrectly used in assignment (#1044)", () => { + const { diagnostics } = util.testFunction` + foo?.bar = "foo"; + `.getLuaResult(); + + expect(diagnostics.find(d => d.code === notAllowedOptionalAssignment.code)).toBeDefined(); +}); + describe("optional chaining function calls", () => { test.each(["() => 4", "undefined"])("stand-alone optional function (%p)", value => { util.testFunction` - const f: (() => number) | undefined = ${value}; + const f = (${value}) as (() => number) | undefined; return f?.(); `.expectToMatchJsResult(); }); @@ -122,7 +257,7 @@ describe("optional chaining function calls", () => { test("object with method can be undefined", () => { util.testFunction` - const objWithMethods: { foo: () => number, bar: (this: void) => number } | undefined = undefined; + const objWithMethods = undefined as { foo: () => number, bar: (this: void) => number } | undefined; return [objWithMethods?.foo() ?? "no foo", objWithMethods?.bar() ?? "no bar"]; `.expectToMatchJsResult(); }); @@ -134,8 +269,8 @@ describe("optional chaining function calls", () => { const objWithMethods: typeWithOptional = {}; const objWithMethods2: typeWithOptional = { a: { b: { c: () => 4 } } }; - return { - expectNil: objWithMethods.a?.b.c(), + return { + expectNil: objWithMethods.a?.b.c(), expectFour: objWithMethods2.a?.b.c() }; `.expectToMatchJsResult(); @@ -157,4 +292,169 @@ describe("optional chaining function calls", () => { return [obj.a?.().b.c?.() ?? "nil", obj2.a?.().b.c?.() ?? "nil", obj3.a?.().b.c?.() ?? "nil"]; `.expectToMatchJsResult(); }); + + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1085 + test("incorrect type, method is not a function", () => { + util.testFunction` + const obj: any = {}; + obj?.foo(); + `.expectToEqual(new util.ExecutionError("attempt to call a nil value (method 'foo')")); + }); + + describe("builtins", () => { + test.each([ + ["undefined", undefined], + ["{foo: 0}", true], + ])("LuaTable: %p", (expr, value) => { + util.testFunction` + const table: LuaTable = ${expr} as any + const bar = table?.has("foo") + return bar + ` + .withLanguageExtensions() + .expectToEqual(value); + }); + + test.each(["undefined", "foo"])("Function call: %p", e => { + util.testFunction` + const result = [] + function foo(this: unknown, arg: unknown) { + return [this, arg] + } + const bar = ${e} as typeof foo | undefined + return bar?.call(1, 2) + `.expectToMatchJsResult(); + }); + + test.each([undefined, "[1, 2, 3, 4]"])("Array: %p", expr => { + util.testFunction` + const value = ${expr} as any[] | undefined; + return value?.map(x=>x+1); + `.expectToMatchJsResult(); + }); + }); + + test.each([true, false])("Default call context, strict %s", strict => { + util.testFunction` + function func(this: unknown, arg: unknown) { + return [this === globalThis ? "_G" : this === undefined ? "nil" : "neither", arg]; + } + let i = 0 + const result = func?.(i++); + ` + .setOptions({ + strict, + }) + .expectToMatchJsResult(); + }); +}); + +describe("Unsupported optional chains", () => { + test("Language extensions", () => { + util.testModule` + new LuaTable().has?.(3) + ` + .withLanguageExtensions() + .expectDiagnosticsToMatchSnapshot(); + }); + + test("Builtin prototype method", () => { + util.testModule` + [1,2,3,4].forEach?.(()=>{}) + `.expectDiagnosticsToMatchSnapshot(); + }); + + test("Builtin global method", () => { + util.testModule` + Number?.("3") + `.expectDiagnosticsToMatchSnapshot(); + }); + + test("Builtin global property", () => { + util.testModule` + console?.log("3") + ` + .setOptions({ + lib: ["lib.esnext.d.ts", "lib.dom.d.ts"], + }) + .expectDiagnosticsToMatchSnapshot(); + }); + + test("Compile members only", () => { + util.testFunction` + /** @compileMembersOnly */ + enum TestEnum { + A = 0, + B = 2, + C, + D = "D", + } + + TestEnum?.B + `.expectDiagnosticsToMatchSnapshot(); + }); +}); + +describe("optional delete", () => { + test("successful", () => { + util.testFunction` + const table: { bar?: number } = { + bar: 3 + } + return [delete table?.bar, table] + `.expectToMatchJsResult(); + }); + + test("unsuccessful", () => { + util.testFunction` + const table : { + bar?: number + } = {} + return [delete table?.bar, table] + `.expectToMatchJsResult(); + }); + + test("delete on undefined", () => { + util.testFunction` + const table = undefined as { + bar?: number + } | undefined; + return [delete table?.bar, table ?? "nil"] + `.expectToMatchJsResult(); + }); +}); + +describe("Non-null chain", () => { + test("Single non-null chain", () => { + util.testFunction` + const foo = {a: { b: 3} } + return foo?.a!.b + `.expectToMatchJsResult(); + }); + + test("Many non-null chains", () => { + util.testFunction` + const foo = {a: { b: 3} } + return foo?.a!!!.b!!! + `.expectToMatchJsResult(); + }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1585 +test("optional chaining of super call (#1585)", () => { + util.testFunction` + class Parent { + private name = "foo"; + M2() { return this.name; } + } + + class Child extends Parent { + M2() { + return super.M2?.(); + } + } + + const c = new Child(); + return c.M2(); + `.expectToMatchJsResult(); }); diff --git a/test/unit/overloads.spec.ts b/test/unit/overloads.spec.ts index d18daa000..85752a64a 100644 --- a/test/unit/overloads.spec.ts +++ b/test/unit/overloads.spec.ts @@ -67,8 +67,8 @@ test("overload method2", () => { test("constructor1", () => { util.testFunction` class myclass { - num: number; - str: string; + num?: number; + str?: string; constructor(def: number); constructor(def: string); @@ -88,8 +88,8 @@ test("constructor1", () => { test("constructor2", () => { util.testFunction` class myclass { - num: number; - str: string; + num?: number; + str?: string; constructor(def: number); constructor(def: string); diff --git a/test/unit/precedingStatements.spec.ts b/test/unit/precedingStatements.spec.ts new file mode 100644 index 000000000..6dd8c6473 --- /dev/null +++ b/test/unit/precedingStatements.spec.ts @@ -0,0 +1,659 @@ +import * as util from "../util"; + +const shortCircuitTests: Array<{ operator: string; testValue: unknown }> = [ + { operator: "&&", testValue: true }, + { operator: "&&", testValue: false }, + { operator: "&&", testValue: null }, + { operator: "&&=", testValue: true }, + { operator: "&&=", testValue: false }, + { operator: "&&=", testValue: null }, + { operator: "||", testValue: true }, + { operator: "||", testValue: false }, + { operator: "||", testValue: null }, + { operator: "||=", testValue: true }, + { operator: "||=", testValue: false }, + { operator: "||=", testValue: null }, + { operator: "??", testValue: true }, + { operator: "??", testValue: false }, + { operator: "??", testValue: null }, + { operator: "??=", testValue: true }, + { operator: "??=", testValue: false }, + { operator: "??=", testValue: null }, +]; + +test.each(shortCircuitTests)("short circuit operator (%p)", ({ operator, testValue }) => { + util.testFunction` + let x: unknown = ${testValue}; + let y = 1; + const z = x ${operator} y++; + return {x, y, z}; + `.expectToMatchJsResult(); +}); + +test.each(shortCircuitTests)("short circuit operator on property (%p)", ({ operator, testValue }) => { + util.testFunction` + let x: { foo: unknown } = { foo: ${testValue} }; + let y = 1; + const z = x.foo ${operator} y++; + return {x: x.foo, y, z}; + `.expectToMatchJsResult(); +}); + +test.each([true, false])("ternary operator (%p)", condition => { + util.testFunction` + let a = 0, b = 0; + let condition: boolean = ${condition}; + const c = condition ? a++ : b++; + return [a, b, c]; + `.expectToMatchJsResult(); +}); + +describe("execution order", () => { + const sequenceTests = [ + "i++, i", + "i, i++, i, i++", + "...a", + "i, ...a", + "...a, i", + "i, ...a, i++, i, ...a", + "i, ...a, i++, i, ...a, i", + "...[1, i++, 2]", + "...[1, i++, 2], i++", + "i, ...[1, i++, 2]", + "i, ...[1, i++, 2], i", + "i, ...[1, i++, 2], i++", + "i, ...[1, i++, 2], i++, ...[3, i++, 4]", + "i, ...a, i++, ...[1, i++, 2], i, i++, ...a", + "i, inc(), i++", + "i, ...[1, i++, inc(), 2], i++", + "i, ...'foo', i++", + "i, ...([1, i++, 2] as any), i++", + ]; + + test.each(sequenceTests)("array literal ([%p])", sequence => { + util.testFunction` + const a = [7, 8, 9]; + let i = 0; + function inc() { ++i; return i; } + return [${sequence}]; + `.expectToMatchJsResult(); + }); + + test.each(sequenceTests)("function arguments (foo(%p))", sequence => { + util.testFunction` + const a = [7, 8, 9]; + let i = 0; + function inc() { ++i; return i; } + function foo(...args: unknown[]) { return args; } + return foo(${sequence}); + `.expectToMatchJsResult(); + }); + + test.each([ + "{a: i, b: i++}", + "{a: i, b: i++, c: i}", + "{a: i, ...{b: i++}, c: i}", + "{a: i, ...o, b: i++}", + "{a: i, ...[i], b: i++}", + "{a: i, ...[i++], b: i++}", + "{a: i, ...o, b: i++, ...[i], ...{c: i++}, d: i++}", + ])("object literal (%p)", literal => { + util.testFunction` + const o = {a: "A", b: "B", c: "C"}; + let i = 0; + const literal: Record = ${literal}; + const result: Record = {}; + (Object.keys(result) as Array).forEach( + key => { result[key.toString()] = literal[key]; } + ); + return result; + ` + // TS2783: duplicate property in spread — intentional, testing execution order + .ignoreDiagnostics([2783]) + .expectToMatchJsResult(); + }); + + test("object literal with computed property names", () => { + util.testFunction` + let i = "A"; + const o = {[i += "B"]: i += "C", [i += "D"]: i += "E"}; + return [i, o]; + `.expectToMatchJsResult(); + }); + + test("comma operator", () => { + util.testFunction` + let a = 0, b = 0, c = 0; + const d = (a++, b += a, c += b); + return [a, b, c, d]; + `.expectToMatchJsResult(); + }); + + test("template expression", () => { + util.testFunction` + let i = 0; + return \`\${i}, \${i++}, \${i}\`; + `.expectToMatchJsResult(); + }); + + test("tagged template literal", () => { + util.testFunction` + let i = 0; + + function func(strings: TemplateStringsArray, ...expressions: any[]) { + const x = i > 0 ? "a" : "b"; + return { strings: [x, ...strings], raw: strings.raw, expressions }; + } + + return func\`hello \${i} \${i++}\`; + `.expectToMatchJsResult(); + }); + + test("binary operators", () => { + util.testFunction` + let i = 0; + return i + i++; + `.expectToMatchJsResult(); + }); + + test("index expression", () => { + util.testFunction` + let i = 0; + const a = [["A1", "A2"], ["B1", "B2"]]; + const result = a[i][i++]; + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("void expression", () => { + util.testFunction` + function foo(x: number, y: number, z: number | undefined) { + return z; + } + let i = 0; + const result = foo(i, i++, void(i++)); + return {result, i}; + `.expectToMatchJsResult(); + }); +}); + +describe("assignment execution order", () => { + test("index assignment statement", () => { + util.testFunction` + let i = 0; + const a = [4, 5]; + a[i] = i++; + return [a, i]; + `.expectToMatchJsResult(); + }); + + test("index assignment expression", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + const result = a[i] = i++; + return [result, a, i]; + `.expectToMatchJsResult(); + }); + + test("indirect index assignment statement", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + const b = [7, 6]; + function foo(x: number) { return (x > 0) ? b : a; } + foo(i)[i] = i++; + return [a, b, i]; + `.expectToMatchJsResult(); + }); + + test("indirect index assignment expression", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + const b = [7, 6]; + function foo(x: number) { return (x > 0) ? b : a; } + const result = foo(i)[i] = i++; + return [result, a, b, i]; + `.expectToMatchJsResult(); + }); + + test("indirect property assignment statement", () => { + util.testFunction` + const a = {value: 10}; + const b = {value: 11}; + let i = 0; + function foo(x: number) { return (x > 0) ? b : a; } + foo(i).value = i++; + return [a, b, i]; + `.expectToMatchJsResult(); + }); + + test("indirect property assignment expression", () => { + util.testFunction` + const a = {value: 10}; + const b = {value: 11}; + let i = 0; + function foo(x: number) { return (x > 0) ? b : a; } + const result = foo(i).value = i++; + return [result, a, b, i]; + `.expectToMatchJsResult(); + }); + + test("compound index assignment statement", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + a[i] += i++; + return [a, i]; + `.expectToMatchJsResult(); + }); + + test("compound index assignment expression", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + const result = a[i] += i++; + return [result, a, i]; + `.expectToMatchJsResult(); + }); + + test("compound indirect index assignment statement", () => { + util.testFunction` + let i = 0; + const a = [9, 8]; + const b = [7, 6]; + function foo(x: number) { return (x > 0) ? b : a; } + foo(i)[i] += i++; + return [a, b, i]; + `.expectToMatchJsResult(); + }); + + test("compound indirect index assignment expression", () => { + util.testFunction` + let i = 1; + const a = [9, 8]; + const b = [7, 6]; + function foo(x: number) { return (x > 0) ? b : a; } + const result = foo(i)[i] += i++; + return [result, a, b, i]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment statement", () => { + util.testFunction` + const a = [10, 9, 8, 7, 6, 5]; + let i = 0; + [a[i], a[i++]] = [i++, i++]; + return [a, i]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment expression", () => { + util.testFunction` + const a = [10, 9, 8, 7, 6, 5]; + let i = 0; + const result = [a[i], a[i++]] = [i++, i++]; + return [a, i, result]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment statement with default", () => { + util.testFunction` + const a = [10, 9, 8, 7, 6, 5]; + let i = 0; + [a[i] = i++, a[i++]] = [i++, i++]; + return [a, i]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment expression with default", () => { + util.testFunction` + const a = [10, 9, 8, 7, 6, 5]; + let i = 0; + const result = [a[i] = i++, a[i++]] = [i++, i++]; + return [a, i, result]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment statement with spread", () => { + util.testFunction` + let i = 0; + let a: number[][] = [[9, 9, 9], [9, 9, 9], [9, 9, 9]]; + [a[0][i], ...a[i++]] = [i++, i++]; + return [a, i]; + `.expectToMatchJsResult(); + }); + + test("array destructuring assignment expression with spread", () => { + util.testFunction` + let i = 0; + let a: number[][] = [[9, 9, 9], [9, 9, 9], [9, 9, 9]]; + const result = [a[0][i], ...a[i++]] = [i++, i++]; + return [a, i, result]; + `.expectToMatchJsResult(); + }); + + test("object destructuring assignment statement", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDEFG: "success", result: ""}; + function c(x: string) { s = x + "C"; return o; } + function g(x: string) { s = x + "G"; return o; } + function e(x: string) { s = x + "E"; return s; } + ({ [e(s += "D")]: g(s += "F").result } = c(s += "B")); + return [s, o]; + `.expectToMatchJsResult(); + }); + + test("object destructuring assignment statement with default", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDEFGHIJ: "success", result: ""}; + function c(x: string) { s = x + "C"; return o; } + function g(x: string) { s = x + "G"; return o; } + function i(x: string) { s = x + "I"; return o; } + function e(x: string): any { s = x + "E"; return undefined; } + ({ [e(s += "D")]: g(s += "F").result = i(s += "H")[s += "J"] } = c(s += "B")); + return [o, s]; + `.expectToMatchJsResult(); + }); + + test("object destructuring assignment expression", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDEFG: "success", result: ""}; + function c(x: string) { s = x + "C"; return o; } + function g(x: string) { s = x + "G"; return o; } + function e(x: string) { s = x + "E"; return s; } + const result = ({ [e(s += "D")]: g(s += "F").result } = c(s += "B")); + return [s, o, result]; + `.expectToMatchJsResult(); + }); + + test("object destructuring assignment expression with default", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDEFGHIJ: "success", result: ""}; + function c(x: string) { s = x + "C"; return o; } + function g(x: string) { s = x + "G"; return o; } + function i(x: string) { s = x + "I"; return o; } + function e(x: string): any { s = x + "E"; return undefined; } + const result = ({ [e(s += "D")]: g(s += "F").result = i(s += "H")[s += "J"] } = c(s += "B")); + return [o, s, result]; + `.expectToMatchJsResult(); + }); + + test("object destructuring declaration", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDE: "success"}; + function c(x: string) { s = x + "C"; return o; } + function e(x: string) { s = x + "E"; return s; } + const { [e(s += "D")]: result } = c(s += "B"); + return [result, s]; + `.expectToMatchJsResult(); + }); + + test("object destructuring declaration with default", () => { + util.testFunction` + let s = "A"; + const o: Record = {ABCDEFGH: "success"}; + function c(x: string) { s = x + "C"; return o; } + function g(x: string) { s = x + "G"; return o; } + function e(x: string): any { s = x + "E"; return undefined; } + const { [e(s += "D")]: result = g(s += "F")[s += "H"]} = c(s += "B"); + return [result, s]; + `.expectToMatchJsResult(); + }); + + test("call expression", () => { + util.testFunction` + let i = 1; + function a(x: number) { return x * 10; } + function b(x: number) { return x * 100; } + function foo(x: number) { return (x > 0) ? b : a; } + const result = foo(i)(i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("call expression (function modified)", () => { + util.testFunction` + let i = 1; + let foo = (x: null, y: number) => { return y; }; + function changeFoo() { + foo = (x: null, y: number) => { return y * 10; }; + return null; + } + const result = foo(changeFoo(), i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("method call expression (method modified)", () => { + util.testFunction` + let i = 1; + let o = { + val: 3, + foo(x: null, y: number) { return y + this.val; } + }; + function changeFoo(this: void) { + o.foo = function(x: null, y: number) { return (y + this.val) * 10; }; + return null; + } + const result = o.foo(changeFoo(), i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("method element access call expression (method modified)", () => { + util.testFunction` + let i = 1; + let o = { + val: 3, + foo(x: null, y: number) { return y + this.val; } + }; + function changeFoo(this: void) { + o.foo = function(x: null, y: number) { return (y + this.val) * 10; }; + return null; + } + function getFoo() { return "foo" as const; } + function getO() { return o; } + const result = getO()[getFoo()](changeFoo(), i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("method call expression (object modified)", () => { + util.testFunction` + let i = 1; + let o = { + val: 3, + foo(x: null, y: number) { return y + this.val; } + }; + function changeO(this: void) { + o = { + val: 5, + foo: function(x: null, y: number) { return (y + this.val) * 10; } + }; + return null; + } + const result = o.foo(changeO(), i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("method element access call expression (object modified)", () => { + util.testFunction` + let i = 1; + let o = { + val: 3, + foo(x: null, y: number) { return y + this.val; } + }; + function changeO(this: void) { + o = { + val: 5, + foo: function(x: null, y: number) { return (y + this.val) * 10; } + }; + return null; + } + function getFoo() { return "foo" as const; } + function getO() { return o; } + const result = getO()[getFoo()](changeO(), i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("array method call", () => { + util.testFunction` + let a = [7]; + let b = [9]; + function foo(x: number) { return (x > 0) ? b : a; } + let i = 0; + foo(i).push(i, i++, i); + return [a, b, i]; + `.expectToMatchJsResult(); + }); + + test("function method call", () => { + util.testFunction` + let o = {val: 3}; + let a = function(this: typeof o, x: number) { return this.val + x; }; + let b = function(this: typeof o, x: number) { return (this.val + x) * 10; }; + function foo(x: number) { return (x > 0) ? b : a; } + let i = 0; + const result = foo(i).call(o, i++); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("string method call", () => { + util.testFunction` + function foo(x: number) { return (x > 0) ? "foo" : "bar"; } + let i = 0; + const result = foo(i).substr(++i); + return [result, i]; + `.expectToMatchJsResult(); + }); + + test("new call", () => { + util.testFunction` + class A { public val = 3; constructor(x: number) { this.val += x; } }; + class B { public val = 5; constructor(x: number) { this.val += (x * 10); } }; + function foo(x: number) { return (x > 0) ? B : A; } + let i = 0; + const result = new (foo(i))(i++).val; + return [result, i]; + `.expectToMatchJsResult(); + }); +}); + +describe("loop expressions", () => { + test("while loop", () => { + util.testFunction` + let i = 0, j = 0; + while (i++ < 5) { + ++j; + if (j >= 10) { + break; + } + } + return [i, j]; + `.expectToMatchJsResult(); + }); + + test("for loop", () => { + util.testFunction` + let j = 0; + for (let i = 0; i++ < 5;) { + ++j; + if (j >= 10) { + break; + } + } + return j; + `.expectToMatchJsResult(); + }); + + test("do while loop", () => { + util.testFunction` + let i = 0, j = 0; + do { + ++j; + if (j >= 10) { + break; + } + } while (i++ < 5); + return [i, j]; + `.expectToMatchJsResult(); + }); + + test("do while loop scoping", () => { + util.testFunction` + let x = 0; + let result = 0; + do { + let x = -10; + ++result; + } while (x++ >= 0 && result < 2); + return result; + `.expectToMatchJsResult(); + }); +}); + +test("switch", () => { + util.testFunction` + let i = 0; + let x = 0; + let result = ""; + switch (x) { + case i++: + result = "test"; + break; + case i++: + } + return [i, result]; + `.expectToMatchJsResult(); +}); + +test("else if", () => { + util.testFunction` + let i = 0; + if (i++ === 0) { + } else if (i++ === 1) { + } + return i; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1208 +test("class member initializers", () => { + util.testFunction` + class MyClass { + myField = false ?? true; + constructor(public foo: number = 0 ?? 5) {} + } + const inst = new MyClass(); + return [inst.myField, inst.foo]; + ` + .ignoreDiagnostics([ + 2869 /* TS2869: Right operand of ?? is unreachable because the left operand is never nullish. */, + ]) + .expectToMatchJsResult(); +}); + +test("class member initializers in extended class", () => { + util.testFunction` + class A {} + class MyClass extends A { + myField = false ?? true; + } + const inst = new MyClass(); + return inst.myField; + ` + .ignoreDiagnostics([ + 2869 /* TS2869: Right operand of ?? is unreachable because the left operand is never nullish. */, + ]) + .expectToMatchJsResult(); +}); diff --git a/test/unit/printer/__snapshots__/semicolons.spec.ts.snap b/test/unit/printer/__snapshots__/semicolons.spec.ts.snap index af1deb303..ac34dbdf8 100644 --- a/test/unit/printer/__snapshots__/semicolons.spec.ts.snap +++ b/test/unit/printer/__snapshots__/semicolons.spec.ts.snap @@ -3,9 +3,9 @@ exports[`semicolon insertion ("{}") 1`] = ` "local ____exports = {} function ____exports.__main(self) - local result = \\"\\" + local result = "" local function foo(self) - result = \\"foo\\" + result = "foo" end do end @@ -18,9 +18,9 @@ return ____exports" exports[`semicolon insertion ("const a = 1; const b = a;") 1`] = ` "local ____exports = {} function ____exports.__main(self) - local result = \\"\\" + local result = "" local function foo(self) - result = \\"foo\\" + result = "foo" end local a = 1 local b = a; @@ -33,9 +33,9 @@ return ____exports" exports[`semicolon insertion ("const a = 1; let b: number; b = a;") 1`] = ` "local ____exports = {} function ____exports.__main(self) - local result = \\"\\" + local result = "" local function foo(self) - result = \\"foo\\" + result = "foo" end local a = 1 local b @@ -49,9 +49,9 @@ return ____exports" exports[`semicolon insertion ("function bar() {} bar();") 1`] = ` "local ____exports = {} function ____exports.__main(self) - local result = \\"\\" + local result = "" local function foo(self) - result = \\"foo\\" + result = "foo" end local function bar(self) end diff --git a/test/unit/printer/deadCodeAfterBreak.spec.ts b/test/unit/printer/deadCodeAfterBreak.spec.ts new file mode 100644 index 000000000..fe1b9073c --- /dev/null +++ b/test/unit/printer/deadCodeAfterBreak.spec.ts @@ -0,0 +1,93 @@ +import * as tstl from "../../../src"; +import * as util from "../../util"; + +// In Lua 5.0, 5.1, and LuaJIT, break must be the last statement in a block. +// Any code after break is a syntax error (e.g. `while true do break; local b = 8 end` +// fails with "'end' expected near 'local'"). Lua 5.2+ relaxed this restriction. +// TSTL should strip dead code after break on all targets to avoid these errors. + +function expectNoDeadCode(builder: util.TestBuilder) { + const lua = builder.getMainLuaCodeChunk(); + expect(lua).not.toContain("local b = 8"); +} + +const affectedVersions: Record void) | boolean> = { + [tstl.LuaTarget.Universal]: false, + [tstl.LuaTarget.Lua50]: builder => builder.tap(expectNoDeadCode).expectToMatchJsResult(), + [tstl.LuaTarget.Lua51]: builder => builder.tap(expectNoDeadCode).expectToMatchJsResult(), + [tstl.LuaTarget.Lua52]: false, + [tstl.LuaTarget.Lua53]: false, + [tstl.LuaTarget.Lua54]: false, + [tstl.LuaTarget.Lua55]: false, + [tstl.LuaTarget.LuaJIT]: builder => builder.tap(expectNoDeadCode), + [tstl.LuaTarget.Luau]: false, +}; + +util.testEachVersion( + "for dead code after break", + () => util.testFunction` + let result = 0; + for (let i = 0; i < 10; i++) { result = i; break; const b = 8; } + return result; + `, + affectedVersions +); + +util.testEachVersion( + "for..in dead code after break", + () => util.testFunction` + let result = ""; + for (let a in {"a": 5, "b": 8}) { result = a; break; const b = 8; } + return result; + `, + affectedVersions +); + +util.testEachVersion( + "for..of dead code after break", + () => util.testFunction` + let result = 0; + for (let a of [1,2,4]) { result = a; break; const b = 8; } + return result; + `, + affectedVersions +); + +util.testEachVersion( + "while dead code after break", + () => util.testFunction` + let result = "done"; + while (true) { break; const b = 8; } + return result; + `, + affectedVersions +); + +util.testEachVersion( + "switch dead code after break", + () => util.testFunction` + let result = "none"; + switch ("abc" as string) { + case "def": + result = "def"; + break; + let abc = 4; + case "abc": + result = "abc"; + break; + let def = 6; + } + return result; + `, + affectedVersions +); + +util.testEachVersion( + "do-while dead code after break", + () => util.testFunction` + let result = "done"; + do { break; const b = 8; } while (true); + return result; + `, + affectedVersions +); diff --git a/test/unit/printer/semicolons.spec.ts b/test/unit/printer/semicolons.spec.ts index addb66e53..7be461d0f 100644 --- a/test/unit/printer/semicolons.spec.ts +++ b/test/unit/printer/semicolons.spec.ts @@ -10,6 +10,7 @@ test.each(["const a = 1; const b = a;", "const a = 1; let b: number; b = a;", "{ (undefined || foo)(); return result; ` + .ignoreDiagnostics([2873 /* TS2873: This kind of expression is always falsy. */]) .expectToMatchJsResult() .expectLuaToMatchSnapshot(); } diff --git a/test/unit/printer/sourcemaps.spec.ts b/test/unit/printer/sourcemaps.spec.ts index 371c50df9..478f482d6 100644 --- a/test/unit/printer/sourcemaps.spec.ts +++ b/test/unit/printer/sourcemaps.spec.ts @@ -1,7 +1,9 @@ -import { Position, SourceMapConsumer } from "source-map"; +import { SourceMapConsumer } from "source-map"; import * as tstl from "../../../src"; +import { LuaTarget, transpileString } from "../../../src"; import { couldNotResolveRequire } from "../../../src/transpilation/diagnostics"; import * as util from "../../util"; +import { lineAndColumnOf } from "./utils"; test.each([ { @@ -87,7 +89,7 @@ test.each([ assertPatterns: [ { luaPattern: "Bar = __TS__Class()", typeScriptPattern: "class Bar" }, { luaPattern: "Bar.name =", typeScriptPattern: "class Bar" }, - { luaPattern: "__TS__ClassExtends", typeScriptPattern: "extends" }, + { luaPattern: "__TS__ClassExtends(", typeScriptPattern: "extends" }, // find use of function, not import { luaPattern: "Foo", typeScriptPattern: "Foo" }, { luaPattern: "function Bar.prototype.____constructor", typeScriptPattern: "constructor" }, ], @@ -162,25 +164,35 @@ test.each([ }); test.each([ - { fileName: "/proj/foo.ts", config: {} }, + { + fileName: "/proj/foo.ts", + config: {}, + expectedSourcePath: "foo.ts", // ts and lua will be emitted to same directory + }, { fileName: "/proj/src/foo.ts", - config: { outDir: "/proj/dst" }, + config: { + outDir: "/proj/dst", + }, + expectedSourcePath: "../src/foo.ts", // path from proj/dst outDir to proj/src/foo.ts }, { fileName: "/proj/src/foo.ts", config: { rootDir: "/proj/src", outDir: "/proj/dst" }, + expectedSourcePath: "../src/foo.ts", // path from proj/dst outDir to proj/src/foo.ts }, { fileName: "/proj/src/sub/foo.ts", config: { rootDir: "/proj/src", outDir: "/proj/dst" }, + expectedSourcePath: "../../src/sub/foo.ts", // path from proj/dst/sub outDir to proj/src/sub/foo.ts }, { fileName: "/proj/src/sub/main.ts", - config: { rootDir: "/proj/src", outDir: "/proj/dst", sourceRoot: "bin" }, - fullSource: "bin/proj/src/sub/main.ts", + config: { rootDir: "/proj/src", outDir: "/proj/dst", sourceRoot: "bin/binsub/binsubsub" }, + expectedSourcePath: "../../src/sub/main.ts", // path from proj/dst/sub outDir to proj/src/sub/foo.ts + fullSource: "bin/src/sub/main.ts", }, -])("Source map has correct sources (%p)", async ({ fileName, config, fullSource }) => { +])("Source map has correct sources (%p)", async ({ fileName, config, fullSource, expectedSourcePath }) => { const file = util.testModule` const foo = "foo" ` @@ -190,11 +202,11 @@ test.each([ const sourceMap = JSON.parse(file.luaSourceMap); expect(sourceMap.sources).toHaveLength(1); - expect(sourceMap.sources[0]).toBe(fileName); + expect(sourceMap.sources[0]).toBe(expectedSourcePath); const consumer = await new SourceMapConsumer(file.luaSourceMap); expect(consumer.sources).toHaveLength(1); - expect(consumer.sources[0]).toBe(fullSource ?? fileName); + expect(consumer.sources[0]).toBe(fullSource ?? expectedSourcePath); }); test.each([ @@ -272,6 +284,24 @@ test("sourceMapTraceback saves sourcemap in _G", () => { } }); +test("sourceMapTraceback gives traceback", () => { + const builder = util.testFunction` + return (debug.traceback as (this: void)=>string)(); + `.setOptions({ sourceMapTraceback: true }); + + const traceback = builder.getLuaExecutionResult(); + expect(traceback).toEqual(expect.any(String)); +}); + +test("inline sourceMapTraceback gives traceback", () => { + const builder = util.testFunction` + return (debug.traceback as (this: void)=>string)(); + `.setOptions({ sourceMapTraceback: true, luaLibImport: tstl.LuaLibImportKind.Inline }); + + const traceback = builder.getLuaExecutionResult(); + expect(traceback).toEqual(expect.any(String)); +}); + test("Inline sourcemaps", () => { const code = ` function abc() { @@ -298,26 +328,23 @@ test("Inline sourcemaps", () => { expect(inlineSourceMap).toBe(file.luaSourceMap); }); -// Helper functions - -function lineAndColumnOf(text: string, pattern: string): Position { - const pos = text.indexOf(pattern); - if (pos === -1) { - return { line: -1, column: -1 }; - } - - const lineLengths = text.split("\n").map(s => s.length); - - let totalPos = 0; - for (let line = 1; line <= lineLengths.length; line++) { - // Add + 1 for the removed \n - const lineLength = lineLengths[line - 1] + 1; - if (pos < totalPos + lineLength) { - return { line, column: pos - totalPos }; +test("loadstring sourceMapTraceback gives traceback", () => { + const loadStrCode = transpileString( + `function bar() { + const trace = (debug.traceback as (this: void)=>string)(); + return trace; } + return bar();`, + { sourceMapTraceback: true, luaTarget: LuaTarget.Lua51 } + ).file?.lua; - totalPos += lineLengths[line - 1] + 1; - } + const builder = util.testModule` + const luaCode = \`${loadStrCode}\`; + return loadstring(luaCode, "foo.lua")(); + ` + .setTsHeader("declare function loadstring(this: void, string: string, chunkname: string): () => unknown") + .setOptions({ sourceMapTraceback: true, luaTarget: LuaTarget.Lua51 }); - return { line: -1, column: -1 }; -} + const traceback = builder.getLuaExecutionResult(); + expect(traceback).toContain("foo.ts"); +}); diff --git a/test/unit/printer/utils.ts b/test/unit/printer/utils.ts new file mode 100644 index 000000000..a9f58b44f --- /dev/null +++ b/test/unit/printer/utils.ts @@ -0,0 +1,25 @@ +// Helper functions + +import { Position } from "source-map"; + +export function lineAndColumnOf(text: string, pattern: string): Position { + const pos = text.indexOf(pattern); + if (pos === -1) { + return { line: -1, column: -1 }; + } + + const lineLengths = text.split("\n").map(s => s.length); + + let totalPos = 0; + for (let line = 1; line <= lineLengths.length; line++) { + // Add + 1 for the removed \n + const lineLength = lineLengths[line - 1] + 1; + if (pos < totalPos + lineLength) { + return { line, column: pos - totalPos }; + } + + totalPos += lineLengths[line - 1] + 1; + } + + return { line: -1, column: -1 }; +} diff --git a/test/unit/spread.spec.ts b/test/unit/spread.spec.ts index 5d7ed93a7..93936f29b 100644 --- a/test/unit/spread.spec.ts +++ b/test/unit/spread.spec.ts @@ -1,4 +1,3 @@ -import * as path from "path"; import * as tstl from "../../src"; import * as util from "../util"; import { formatCode } from "../util"; @@ -23,15 +22,16 @@ describe.each(["function call", "array literal"] as const)("in %s", kind => { util.testExpression(factory(expression)).expectToMatchJsResult(); }); - test.each(arrayLiteralCases)("of tuple return call (%p)", expression => { + test.each(arrayLiteralCases)("of multi return call (%p)", expression => { util.testFunction` - /** @tupleReturn */ function tuple(...args: any[]) { - return args; + return $multi(...args); } return ${factory(`...tuple(${expression})`)}; - `.expectToMatchJsResult(); + ` + .withLanguageExtensions() + .expectToMatchJsResult(); }); test("of multiple string literals", () => { @@ -76,10 +76,13 @@ describe("in function call", () => { { [tstl.LuaTarget.Universal]: builder => builder.tap(expectLualibUnpack).expectToMatchJsResult(), [tstl.LuaTarget.LuaJIT]: builder => builder.tap(expectUnpack), + [tstl.LuaTarget.Lua50]: builder => builder.tap(expectUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua51]: builder => builder.tap(expectUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua52]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua53]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua54]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), + [tstl.LuaTarget.Lua55]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), + [tstl.LuaTarget.Luau]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), } ); }); @@ -88,10 +91,13 @@ describe("in array literal", () => { util.testEachVersion(undefined, () => util.testExpression`[...[0, 1, 2]]`, { [tstl.LuaTarget.Universal]: builder => builder.tap(expectLualibUnpack).expectToMatchJsResult(), [tstl.LuaTarget.LuaJIT]: builder => builder.tap(expectUnpack), + [tstl.LuaTarget.Lua50]: builder => builder.tap(expectUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua51]: builder => builder.tap(expectUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua52]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua53]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), [tstl.LuaTarget.Lua54]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), + [tstl.LuaTarget.Lua55]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), + [tstl.LuaTarget.Luau]: builder => builder.tap(expectTableUnpack).expectToMatchJsResult(), }); test("of array literal /w OmittedExpression", () => { @@ -110,6 +116,17 @@ describe("in object literal", () => { "{ ...{ x: false }, x: true }", "{ ...{ x: false }, x: false, ...{ x: true } }", ])("of object literal (%p)", expression => { + util.testExpression(expression) + .ignoreDiagnostics([2783]) // duplicate property in spread — intentional, testing spread override behavior + .expectToMatchJsResult(); + }); + + test.each([ + "{ ...((false && { a: 1 }) as any) }", + "{ ...((true && { a: 1 }) as any) }", + "{ a: 1, ...((false && { b: 2 }) as any) }", + "{ ...(null as any), ...(undefined as any) }", + ])("of short-circuited operand (%p)", expression => { util.testExpression(expression).expectToMatchJsResult(); }); @@ -133,58 +150,55 @@ describe("in object literal", () => { }); describe("vararg spread optimization", () => { - test("basic use", () => { - util.testFunction` + util.testEachVersion( + "basic use", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { return pick(...args); } - return test("a", "b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("body-less arrow function", () => { - util.testFunction` + util.testEachVersion( + "body-less arrow function", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } const test = (...args: string[]) => pick(...args); - return test("a", "b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("if statement", () => { - util.testFunction` + util.testEachVersion( + "if statement", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { if (true) { return pick(...args); } } - return test("a", "b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("loop statement", () => { - util.testFunction` + util.testEachVersion( + "loop statement", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { do { return pick(...args); } while (false); } - return test("a", "b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("block statement", () => { - util.testFunction` + util.testEachVersion( + "block statement", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { let result: string; @@ -193,14 +207,13 @@ describe("vararg spread optimization", () => { } return result; } - return test("a", "b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("finally clause", () => { - util.testFunction` + util.testEachVersion( + "finally clause", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { try { @@ -210,11 +223,9 @@ describe("vararg spread optimization", () => { return pick(...args); } } - return test("a" ,"b", "c"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); test("$multi", () => { util.testFunction` @@ -226,61 +237,71 @@ describe("vararg spread optimization", () => { } return test("a" ,"b", "c"); ` - .setOptions({ types: [path.resolve(__dirname, "../../language-extensions")] }) + .withLanguageExtensions() .expectLuaToMatchSnapshot() .expectToEqual("b"); }); - test("curry", () => { - util.testFunction` + util.testEachVersion( + "curry", + () => util.testFunction` function test(fn: (...args: A) => void, ...args: A) { return fn(...args); } - return test((arg: string) => arg, "foobar"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test((arg: string) => arg, "foobar");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("curry with indirect type", () => { - util.testFunction` + util.testEachVersion( + "curry with indirect type", + () => util.testFunction` function test(obj: {fn: (...args: A) => void}, ...args: A) { const fn = obj.fn; return fn(...args); } - return test({fn: (arg: string) => arg}, "foobar"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + return test({fn: (arg: string) => arg}, "foobar");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("function type declared inside scope", () => { - util.testFunction` + util.testEachVersion( + "function type declared inside scope", + () => util.testFunction` function test(...args: A) { const fn: (...args: A) => A[0] = (...args) => args[0]; return fn(...args); } - test("foobar"); - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); + test("foobar");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); + + util.testEachVersion( + "With cast", + () => util.testFunction` + function pick(...args: any[]) { return args[1]; } + function testany>(...args: Parameters) { + return pick(...(args as any[])); + } + return test<(...args: string[])=>void>("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); }); describe("vararg spread de-optimization", () => { - test("array modification", () => { - util.testFunction` + util.testEachVersion( + "array modification", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { args[1] = "foobar"; return pick(...args); } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("array modification in hoisted function", () => { - util.testFunction` + util.testEachVersion( + "array modification in hoisted function", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { hoisted(); @@ -288,12 +309,13 @@ describe("vararg spread de-optimization", () => { function hoisted() { args[1] = "foobar"; } return result; } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("array modification in secondary hoisted function", () => { - util.testFunction` + util.testEachVersion( + "array modification in secondary hoisted function", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { function triggersHoisted() { hoisted(); } @@ -302,103 +324,112 @@ describe("vararg spread de-optimization", () => { function hoisted() { args[1] = "foobar"; } return result; } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); }); describe("vararg spread in IIFE", () => { - test("comma operator", () => { - util.testFunction` + util.testEachVersion( + "comma operator", + () => util.testFunction` function dummy() { return "foobar"; } function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { return (dummy(), pick(...args)); } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("assignment expression", () => { - util.testFunction` + util.testEachVersion( + "assignment expression", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { let x: string; return (x = pick(...args)); } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("destructured assignment expression", () => { - util.testFunction` + util.testEachVersion( + "destructured assignment expression", + () => util.testFunction` function pick(...args: string[]) { return [args[1]]; } function test(...args: string[]) { let x: string; return ([x] = pick(...args)); } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("property-access assignment expression", () => { - util.testFunction` + util.testEachVersion( + "property-access assignment expression", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { let x: {val?: string} = {}; return (x.val = pick(...args)); } - return test("a", "b", "c"); - `.expectToMatchJsResult(); - }); + return test("a", "b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("binary compound assignment", () => { - util.testFunction` + util.testEachVersion( + "binary compound assignment", + () => util.testFunction` function pick(...args: number[]) { return args[1]; } function test(...args: number[]) { let x = 1; return x += pick(...args); } - return test(1, 2, 3); - `.expectToMatchJsResult(); - }); + return test(1, 2, 3);`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("postfix unary compound assignment", () => { - util.testFunction` + util.testEachVersion( + "postfix unary compound assignment", + () => util.testFunction` function pick(...args: number[]) { return args[1]; } function test(...args: number[]) { let x = [7, 8, 9]; return x[pick(...args)]++; } - return test(1, 2, 3); - `.expectToMatchJsResult(); - }); + return test(1, 2, 3);`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("prefix unary compound assignment", () => { - util.testFunction` + util.testEachVersion( + "prefix unary compound assignment", + () => util.testFunction` function pick(...args: number[]) { return args[1]; } function test(...args: number[]) { let x = [7, 8, 9]; return ++x[pick(...args)]; } - return test(1, 2, 3); - `.expectToMatchJsResult(); - }); + return test(1, 2, 3);`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("try clause", () => { - util.testFunction` + util.testEachVersion( + "try clause", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { try { return pick(...args) } catch {} } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("catch clause", () => { - util.testFunction` + util.testEachVersion( + "catch clause", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { try { @@ -407,62 +438,153 @@ describe("vararg spread in IIFE", () => { return pick(...args) } } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("class expression", () => { - util.testFunction` + util.testEachVersion( + "class expression", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } function test(...args: string[]) { const fooClass = class Foo { foo = pick(...args); }; return new fooClass().foo; } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("self-referencing function expression", () => { - util.testFunction` + util.testEachVersion( + "self-referencing function expression", + () => util.testFunction` function pick(...args: string[]) { return args[1]; } const test = function testName(...args: string[]) { return \`\${typeof testName}:\${pick(...args)}\`; } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("method indirect access (access args)", () => { - util.testFunction` + util.testEachVersion( + "method indirect access (access args)", + () => util.testFunction` const obj = { $method: () => obj.arg, arg: "foobar" }; function getObj(...args: string[]) { obj.arg = args[1]; return obj; } function test(...args: string[]) { return getObj(...args).$method(); } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("method indirect access (method args)", () => { - util.testFunction` + util.testEachVersion( + "method indirect access (method args)", + () => util.testFunction` const obj = { $pick: (...args: string[]) => args[1] }; function getObj() { return obj; } function test(...args: string[]) { return getObj().$pick(...args); } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); - test("tagged template method indirect access", () => { - util.testFunction` + util.testEachVersion( + "tagged template method indirect access", + () => util.testFunction` const obj = { $tag: (t: TemplateStringsArray, ...args: string[]) => args[1] }; function getObj() { return obj; } function pick(...args: string[]): string { return args[1]; } function test(...args: string[]) { return getObj().$tag\`FOO\${pick(...args)}BAR\`; } - return test("a" ,"b", "c"); - `.expectToMatchJsResult(); - }); + return test("a" ,"b", "c");`, + util.expectEachVersionExceptJit(builder => builder.expectToMatchJsResult()) + ); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1244 +test.each(["pairs", "ipairs"])("can spread %s (#1244)", func => { + util.testFunction` + const arr = ["a", "b", "c"]; + return [...${func}(arr)]; + ` + .withLanguageExtensions() + .setTsHeader( + ` + declare function ipairs(this: void, t: T): LuaIterable]>>; + declare function pairs(this: void, t: T): LuaIterable]>>; + ` + ) + .expectToEqual([ + [1, "a"], + [2, "b"], + [3, "c"], + ]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1244 +test.each(["LuaTable", "LuaMap"])("can spread %s with pairs (#1244)", type => { + const result: Array<[string, string]> = util.testFunction` + const tbl = new ${type}(); + tbl.set("foo", "bar"); + tbl.set("fizz", "buzz"); + return [...pairs(tbl)]; + ` + .withLanguageExtensions() + .setTsHeader( + "declare function pairs(this: void, t: T): LuaIterable]>>;" + ) + .getLuaExecutionResult(); + + // We don't know the order so match like this + expect(result).toHaveLength(2); + expect(result).toContainEqual(["foo", "bar"]); + expect(result).toContainEqual(["fizz", "buzz"]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1384 +test.each(["LuaTable", "LuaMap"])("can spread %s (#1384)", type => { + const result: Array<[string, string]> = util.testFunction` + const tbl = new ${type}(); + tbl.set("foo", "bar"); + tbl.set("fizz", "buzz"); + return [...tbl]; + ` + .withLanguageExtensions() + .getLuaExecutionResult(); + + // We don't know the order so match like this + expect(result).toHaveLength(2); + expect(result).toContainEqual(["foo", "bar"]); + expect(result).toContainEqual(["fizz", "buzz"]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1384 +test("can spread LuaSet (#1384)", () => { + const result: Array<[string, string]> = util.testFunction` + const tbl = new LuaSet(); + tbl.add("foo"); + tbl.add("bar"); + return [...tbl]; + ` + .withLanguageExtensions() + .getLuaExecutionResult(); + + // We don't know the order so match like this + expect(result).toHaveLength(2); + expect(result).toContain("foo"); + expect(result).toContain("bar"); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1426 +test.each([true, false])("spread a decorator or array union type (#1426)", choice => { + util.testFunction` + function* things() { + yield "a"; + yield "b" + } + const c: boolean = ${util.formatCode(choice)}; + return [...(c ? things() : ["c", "d"])]; + `.expectToMatchJsResult(); }); diff --git a/test/unit/switch.spec.ts b/test/unit/switch.spec.ts index dd3e2a09c..1b8410a68 100644 --- a/test/unit/switch.spec.ts +++ b/test/unit/switch.spec.ts @@ -1,5 +1,3 @@ -import * as tstl from "../../src"; -import { unsupportedForTarget } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; test.each([0, 1, 2, 3])("switch (%p)", inp => { @@ -139,7 +137,7 @@ test("switch using variable re-declared in cases", () => { let foo: number = 0; switch (foo) { case 0: - let foo = true; + let foo: boolean | undefined = true; case 1: return foo; } @@ -209,7 +207,7 @@ test.each([0, 1, 2, 3])("switchWithBrackets (%p)", inp => { `.expectToMatchJsResult(); }); -test.each([0, 1, 2, 3])("switchWithBracketsBreakInConditional (%p)", inp => { +test.each([0, 1, 2, 3, 4])("switchWithBracketsBreakInConditional (%p)", inp => { util.testFunction` let result: number = -1; @@ -225,6 +223,11 @@ test.each([0, 1, 2, 3])("switchWithBracketsBreakInConditional (%p)", inp => { } case 2: { result = 2; + + if (result != 2) break; + } + case 3: { + result = 3; break; } } @@ -261,41 +264,27 @@ test.each([0, 1, 2, 3])("switchWithBracketsBreakInInternalLoop (%p)", inp => { `.expectToMatchJsResult(); }); -test("switch uses elseif", () => { - test("array", () => { - util.testFunction` - let result: number = -1; - - switch (2 as number) { - case 0: { - result = 200; - break; - } - - case 1: { - result = 100; - break; - } - - case 2: { - result = 1; - break; - } +test("switch executes only one clause", () => { + util.testFunction` + let result: number = -1; + switch (2 as number) { + case 0: { + result = 200; + break; } - return result; - ` - .expectLuaToMatchSnapshot() - .expectToMatchJsResult(); - }); -}); + case 1: { + result = 100; + break; + } -test("switch not allowed in 5.1", () => { - util.testFunction` - switch ("abc") {} - ` - .setOptions({ luaTarget: tstl.LuaTarget.Lua51 }) - .expectDiagnosticsToMatchSnapshot([unsupportedForTarget.code]); + case 2: { + result = 1; + break; + } + } + return result; + `.expectToMatchJsResult(); }); // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/967 @@ -323,6 +312,17 @@ test("switch default case not last - second", () => { `.expectToMatchJsResult(); }); +test("switch default case only", () => { + util.testFunction` + let out = 0; + switch (4 as number) { + default: + out = 1 + } + return out; + `.expectToMatchJsResult(); +}); + test("switch fallthrough enters default", () => { util.testFunction` const out = []; @@ -361,3 +361,304 @@ test("switch fallthrough stops after default", () => { return out; `.expectToMatchJsResult(); }); + +test.each([0, 1])("switch empty fallthrough to default (%p)", inp => { + util.testFunction` + const out = []; + switch (${inp} as number) { + case 1: + default: + out.push("default"); + + } + return out; + ` + .expectLuaToMatchSnapshot() + .expectToMatchJsResult(); +}); + +test("switch does not pollute parent scope", () => { + util.testFunction` + let x: number = 0; + let y = 1; + switch (x) { + case 0: + let y = 2; + } + return y; + `.expectToMatchJsResult(); +}); + +test.each([0, 1, 2, 3, 4])("switch handles side-effects (%p)", inp => { + util.testFunction` + const out = []; + + let y = 0; + function foo() { + return y++; + } + + let x = ${inp} as number; + switch (x) { + case foo(): + out.push(1); + case foo(): + out.push(2); + case foo(): + out.push(3); + default: + out.push("default"); + case foo(): + } + + out.push(y); + return out; + `.expectToMatchJsResult(); +}); + +test.each([1, 2])("switch handles side-effects with empty fallthrough (%p)", inp => { + util.testFunction` + const out = []; + + let y = 0; + function foo() { + return y++; + } + + let x = 0 as number; + switch (x) { + // empty fallthrough 1 or many times + ${new Array(inp).fill("case foo():").join("\n")} + default: + out.push("default"); + + } + + out.push(y); + return out; + `.expectToMatchJsResult(); +}); + +test.each([1, 2])("switch handles side-effects with empty fallthrough (preceding clause) (%p)", inp => { + util.testFunction` + const out = []; + + let y = 0; + function foo() { + return y++; + } + + let x = 0 as number; + switch (x) { + case 1: + out.push(1); + // empty fallthrough 1 or many times + ${new Array(inp).fill("case foo():").join("\n")} + default: + out.push("default"); + + } + + out.push(y); + return out; + `.expectToMatchJsResult(); +}); + +test.each([0, 1, 2, 3, 4])("switch handles async side-effects (%p)", inp => { + util.testFunction` + (async () => { + const out = []; + + let y = 0; + async function foo() { + return new Promise((resolve) => y++ && resolve(0)); + } + + let x = ${inp} as number; + switch (x) { + case await foo(): + out.push(1); + case await foo(): + out.push(2); + case await foo(): + out.push(3); + default: + out.push("default"); + case await foo(): + } + + out.push(y); + return out; + })(); + `.expectToMatchJsResult(); +}); + +const optimalOutput = (c: number) => util.testFunction` + let x: number = 0; + const out = []; + switch (${c} as number) { + case 0: + case 1: + case 2: + out.push("0,1,2"); + break; + default: + x++; + out.push("default = " + x); + case 3: { + out.push("3"); + break; + } + case 4: + } + out.push(x.toString()); + return out; +`; + +test("switch produces optimal output", () => { + optimalOutput(0).expectLuaToMatchSnapshot(); +}); + +test.each([0, 1, 2, 3, 4, 5])("switch produces valid optimal output (%p)", inp => { + optimalOutput(inp).expectToMatchJsResult(); +}); + +describe("switch hoisting", () => { + test("hoisting between cases", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case 1: + result = hoisted(); + break; + case 2: + function hoisted() { + return "hoisted"; + } + break; + } + return result; + `.expectToMatchJsResult(); + }); + + test("indirect hoisting between cases", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case 1: + function callHoisted() { + return hoisted(); + } + result = callHoisted(); + break; + case 2: + function hoisted() { + return "hoisted"; + } + break; + } + return result; + `.expectToMatchJsResult(); + }); + + test("hoisting in case expression", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case hoisted(): + result = "hoisted"; + break; + case 2: + function hoisted() { + return 1; + } + break; + } + return result; + `.expectToMatchJsResult(); + }); + + test("hoisting from default clause", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case 1: + result = hoisted(); + break; + default: + function hoisted() { + return "hoisted"; + } + break; + } + return result; + `.expectToMatchJsResult(); + }); + + test("hoisting from default clause is not duplicated when falling through", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case 1: + result = hoisted(); + break; + case 2: + result = "2"; + default: + function hoisted() { + return "hoisted"; + } + result = "default"; + case 3: + result = "3"; + } + return result; + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + }); + + test("hoisting from fallthrough clause after default is not duplicated", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + case 1: + result = hoisted(); + break; + case 2: + result = "2"; + default: + result = "default"; + case 3: + function hoisted() { + return "hoisted"; + } + result = "3"; + } + return result; + ` + .expectToMatchJsResult() + .expectLuaToMatchSnapshot(); + }); + + test("hoisting in a solo default clause", () => { + util.testFunction` + let x = 1; + let result = ""; + switch (x) { + default: + result = hoisted(); + function hoisted() { + return "hoisted"; + } + } + return result; + `.expectToMatchJsResult(); + }); +}); diff --git a/test/unit/templateLiterals.spec.ts b/test/unit/templateLiterals.spec.ts index d5dc519a5..318804ee9 100644 --- a/test/unit/templateLiterals.spec.ts +++ b/test/unit/templateLiterals.spec.ts @@ -83,3 +83,26 @@ test.each(["string", "'string literal type'", "string & unknown"])( .expectToMatchJsResult(); } ); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1637 +test("tagged template literal returned from function call (#1637)", () => { + util.testModule` + function templateFactory() { + return (template: TemplateStringsArray) => { + return "bar"; + } + } + export let result = templateFactory()\`foo\`; + `.expectToEqual({ result: "bar" }); +}); + +test("tagged template literal returned from function call, explicit no context (#1637)", () => { + util.testModule` + function templateFactory() { + return function(this: void, template: TemplateStringsArray) { + return "bar"; + } + } + export let result = templateFactory()\`foo\`; + `.expectToEqual({ result: "bar" }); +}); diff --git a/test/unit/using.spec.ts b/test/unit/using.spec.ts new file mode 100644 index 000000000..33749cb37 --- /dev/null +++ b/test/unit/using.spec.ts @@ -0,0 +1,255 @@ +import { LuaLibImportKind } from "../../src"; +import * as util from "../util"; + +const usingTestLib = ` + export const logs: string[] = []; + + function loggedDisposable(id: string): Disposable { + logs.push(\`Creating \${id}\`); + + return { + [Symbol.dispose]() { + logs.push(\`Disposing \${id}\`); + } + } + }`; + +test("using disposes object at end of function", () => { + util.testModule` + function func() { + using a = loggedDisposable("a"); + using b = loggedDisposable("b"); + + logs.push("function content"); + } + + func(); + ` + .setTsHeader(usingTestLib) + .expectToEqual({ logs: ["Creating a", "Creating b", "function content", "Disposing b", "Disposing a"] }); +}); + +test("handles multi-variable declarations", () => { + util.testModule` + function func() { + using a = loggedDisposable("a"), b = loggedDisposable("b"); + + logs.push("function content"); + } + + func(); + ` + .setTsHeader(usingTestLib) + .expectToEqual({ logs: ["Creating a", "Creating b", "function content", "Disposing b", "Disposing a"] }); +}); + +test("using disposes object at end of nested block", () => { + util.testModule` + function func() { + using a = loggedDisposable("a"); + + { + using b = loggedDisposable("b"); + logs.push("nested block"); + } + + logs.push("function content"); + } + + func(); + ` + .setTsHeader(usingTestLib) + .expectToEqual({ + logs: ["Creating a", "Creating b", "nested block", "Disposing b", "function content", "Disposing a"], + }); +}); + +test("using does not affect function return value", () => { + util.testModule` + function func() { + using a = loggedDisposable("a"); + using b = loggedDisposable("b"); + + logs.push("function content"); + + return "success"; + } + + export const result = func(); + ` + .setTsHeader(usingTestLib) + .expectToEqual({ + result: "success", + logs: ["Creating a", "Creating b", "function content", "Disposing b", "Disposing a"], + }); +}); + +test("using disposes even when error happens", () => { + util.testModule` + function func() { + using a = loggedDisposable("a"); + using b = loggedDisposable("b"); + + throw "test-induced exception"; + } + + try + { + func(); + } + catch (e) + { + logs.push(\`caught exception: \${e}\`); + } + ` + .setTsHeader(usingTestLib) + .expectToEqual({ + logs: [ + "Creating a", + "Creating b", + "Disposing b", + "Disposing a", + "caught exception: test-induced exception", + ], + }); +}); + +test("await using disposes object with await at end of function", () => { + util.testModule` + let disposeAsync: (() => void) | undefined; + + function loggedAsyncDisposable(id: string): AsyncDisposable { + logs.push(\`Creating \${id}\`); + + return { + [Symbol.asyncDispose]() { + logs.push(\`Disposing async \${id}\`); + return new Promise(resolve => { + disposeAsync = () => { + logs.push(\`Disposed \${id}\`); + resolve(); + }; + }); + } + } + } + + async function func() { + await using a = loggedAsyncDisposable("a"); + + logs.push("function content"); + return "function result"; + } + + const p = func().then(r => logs.push("promise resolved", r)); + + logs.push("function returned"); + + disposeAsync!(); + ` + .setTsHeader(usingTestLib) + .setOptions({ luaLibImport: LuaLibImportKind.Inline }) + .expectToEqual({ + logs: [ + "Creating a", + "function content", + "Disposing async a", + "function returned", + "Disposed a", + "promise resolved", + "function result", + ], + }); +}); + +test("await using can handle non-async disposables", () => { + util.testModule` + async function func() { + await using a = loggedDisposable("a"); + + logs.push("function content"); + } + + func(); + ` + .setTsHeader(usingTestLib) + .expectToEqual({ logs: ["Creating a", "function content", "Disposing a"] }); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1571 +test("await using no extra diagnostics (#1571)", () => { + util.testModule` + async function getResource(): Promise { + return { + [Symbol.asyncDispose]: async () => {} + }; + } + + async function someOtherAsync() {} + + async function main() { + await using resource = await getResource(); + await someOtherAsync(); + } + `.expectToHaveNoDiagnostics(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1622 +test("await-using with nested async arrow that also has await-using (runtime divergence)", () => { + util.testFunction` + const logs: any[] = []; + async function getA(): Promise { + return { [Symbol.asyncDispose]: async () => {} }; + } + async function outer(): Promise { + await using a = await getA(); + const inner = async (): Promise => { + await using b = await getA(); + return 42; + }; + return inner(); + } + outer().then(v => logs.push(v)); + return logs; + `.expectToEqual([42]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1584 +test("works with disposable classes (#1584)", () => { + util.testFunction` + const log: string[] = []; + + class Scoped { + action(): void { + log.push("action") + } + [Symbol.dispose]() { + log.push("cleanup") + } + } + + function TestScoped(): void { + using s = new Scoped(); + s.action(); + } + + TestScoped(); + return log; + `.expectToEqual(["action", "cleanup"]); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1632 +test("works on root level (#1632)", () => { + util.testModule` + export let disposed = false; + + class A { + [Symbol.dispose] = function (this: A) { + disposed = true; + } + } + using a = new A(); + `.expectToEqual({ + disposed: true, + }); +}); diff --git a/test/unit/void.spec.ts b/test/unit/void.spec.ts new file mode 100644 index 000000000..024f0cf7e --- /dev/null +++ b/test/unit/void.spec.ts @@ -0,0 +1,34 @@ +import * as util from "../util"; + +test.each(["0", "1", '"a"'])("void evaluates to undefined (%p)", value => { + util.testExpression`void (${value})`.expectToMatchJsResult(); +}); + +test("void applies to function declarations", () => { + util.testFunction` + let result = 0; + void function setResult() { + result = 1; + }(); + return result; + `.expectToMatchJsResult(); +}); + +test("void used to ignore function return values", () => { + util.testFunction` + let result = 0; + function setResult() { + result = 1; + return 3 + }; + + void(setResult()); + + return result; + `.expectToMatchJsResult(); +}); + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1102 +test("void works with lambdas", () => { + util.testExpression`void (() => {})()`.expectToMatchJsResult(); +}); diff --git a/test/util.ts b/test/util.ts index b493f43e0..1e191fb28 100644 --- a/test/util.ts +++ b/test/util.ts @@ -9,16 +9,27 @@ import * as ts from "typescript"; import * as vm from "vm"; import * as tstl from "../src"; import { createEmitOutputCollector } from "../src/transpilation/output-collector"; -import { getEmitOutDir, transpileProject } from "../src"; +import { EmitHost, getEmitOutDir, transpileProject } from "../src"; import { formatPathToLuaPath, normalizeSlashes } from "../src/utils"; +import { resolveLuaLibDir } from "../src/LuaLib"; -const jsonLib = fs.readFileSync(path.join(__dirname, "json.lua"), "utf8"); -const luaLib = fs.readFileSync(path.resolve(__dirname, "../dist/lualib/lualib_bundle.lua"), "utf8"); +function readLuaLib(target: tstl.LuaTarget) { + return fs.readFileSync(path.join(resolveLuaLibDir(target), "lualib_bundle.lua"), "utf8"); +} + +function jsonLib(target: tstl.LuaTarget): string { + const fileName = target === tstl.LuaTarget.Lua50 ? "json.50.lua" : "json.lua"; + return fs.readFileSync(path.join(__dirname, fileName), "utf8"); +} // Using `test` directly makes eslint-plugin-jest consider this file as a test const defineTest = test; function getLuaBindingsForVersion(target: tstl.LuaTarget): { lauxlib: LauxLib; lua: Lua; lualib: LuaLib } { + if (target === tstl.LuaTarget.Lua50) { + const { lauxlib, lua, lualib } = require("lua-wasm-bindings/dist/lua.50"); + return { lauxlib, lua, lualib }; + } if (target === tstl.LuaTarget.Lua51) { const { lauxlib, lua, lualib } = require("lua-wasm-bindings/dist/lua.51"); return { lauxlib, lua, lualib }; @@ -32,7 +43,7 @@ function getLuaBindingsForVersion(target: tstl.LuaTarget): { lauxlib: LauxLib; l return { lauxlib, lua, lualib }; } if (target === tstl.LuaTarget.LuaJIT) { - throw Error("Can't use executeLua() or expectToMatchJsResult() wit LuaJIT as target!"); + throw Error("Can't use executeLua() or expectToMatchJsResult() with LuaJIT as target!"); } const { lauxlib, lua, lualib } = require("lua-wasm-bindings/dist/lua.54"); @@ -40,7 +51,7 @@ function getLuaBindingsForVersion(target: tstl.LuaTarget): { lauxlib: LauxLib; l } export function assert(value: any, message?: string | Error): asserts value { - nativeAssert(value, message); + nativeAssert.ok(value, message); } export const formatCode = (...values: unknown[]) => values.map(e => stringify(e)).join(", "); @@ -52,7 +63,7 @@ export function testEachVersion( ): void { for (const version of Object.values(tstl.LuaTarget) as tstl.LuaTarget[]) { const specialBuilder = special?.[version]; - if (specialBuilder === false) return; + if (specialBuilder === false) continue; const testName = name === undefined ? version : `${name} [${version}]`; defineTest(testName, () => { @@ -65,17 +76,31 @@ export function testEachVersion( } } -const memoize: MethodDecorator = (_target, _propertyKey, descriptor) => { - const originalFunction = descriptor.value as any; +export function expectEachVersionExceptJit( + expectation: (builder: T) => void +): Record void) | boolean> { + return { + [tstl.LuaTarget.Universal]: expectation, + [tstl.LuaTarget.Lua50]: expectation, + [tstl.LuaTarget.Lua51]: expectation, + [tstl.LuaTarget.Lua52]: expectation, + [tstl.LuaTarget.Lua53]: expectation, + [tstl.LuaTarget.Lua54]: expectation, + [tstl.LuaTarget.Lua55]: expectation, + [tstl.LuaTarget.LuaJIT]: false, // Exclude JIT + [tstl.LuaTarget.Luau]: false, + }; +} + +const memoize = (originalFunction: any) => { const memoized = new WeakMap(); - descriptor.value = function (this: any, ...args: any[]): any { + return function (this: any, ...args: any[]): any { if (!memoized.has(this)) { memoized.set(this, originalFunction.apply(this, args)); } return memoized.get(this); - } as any; - return descriptor; + }; }; export class ExecutionError extends Error { @@ -97,77 +122,92 @@ export abstract class TestBuilder { // TODO: Use testModule in these cases? protected tsHeader = ""; public setTsHeader(tsHeader: string): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setTsHeader"); this.tsHeader = tsHeader; return this; } private luaHeader = ""; public setLuaHeader(luaHeader: string): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setLuaHeader"); this.luaHeader += luaHeader; return this; } protected jsHeader = ""; public setJsHeader(jsHeader: string): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setJsHeader"); this.jsHeader += jsHeader; return this; } protected abstract getLuaCodeWithWrapper(code: string): string; public setLuaFactory(luaFactory: (code: string) => string): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setLuaFactory"); this.getLuaCodeWithWrapper = luaFactory; return this; } private semanticCheck = true; public disableSemanticCheck(): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("disableSemanticCheck"); this.semanticCheck = false; return this; } protected options: tstl.CompilerOptions = { - luaTarget: tstl.LuaTarget.Lua54, + luaTarget: tstl.LuaTarget.Lua55, noHeader: true, skipLibCheck: true, target: ts.ScriptTarget.ES2017, lib: ["lib.esnext.d.ts"], - moduleResolution: ts.ModuleResolutionKind.NodeJs, + moduleResolution: ts.ModuleResolutionKind.Bundler, resolveJsonModule: true, - experimentalDecorators: true, sourceMap: true, }; public setOptions(options: tstl.CompilerOptions = {}): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setOptions"); Object.assign(this.options, options); return this; } + public withLanguageExtensions(): this { + const langExtTypes = path.resolve(__dirname, "..", "language-extensions"); + this.options.types = this.options.types ? [...this.options.types, langExtTypes] : [langExtTypes]; + // Polyfill lualib for JS + this.setJsHeader(` + function $multi(...args) { return args; } + `); + return this; + } + protected mainFileName = "main.ts"; public setMainFileName(mainFileName: string): this { - expect(this.hasProgram).toBe(false); - this.mainFileName = normalizeSlashes(mainFileName); + this.throwIfProgramExists("setMainFileName"); + this.mainFileName = mainFileName; return this; } protected extraFiles: Record = {}; public addExtraFile(fileName: string, code: string): this { - expect(this.hasProgram).toBe(false); - this.extraFiles[fileName] = code; + this.throwIfProgramExists("addExtraFile"); + this.extraFiles[fileName] = normalizeSlashes(code); return this; } private customTransformers?: ts.CustomTransformers; public setCustomTransformers(customTransformers?: ts.CustomTransformers): this { - expect(this.hasProgram).toBe(false); + this.throwIfProgramExists("setCustomTransformers"); this.customTransformers = customTransformers; return this; } + private throwIfProgramExists(name: string) { + if (this.hasProgram) { + throw new Error(`${name}() should not be called after an .expect() or .debug()`); + } + } + // Transpilation and execution public getTsCode(): string { @@ -178,26 +218,38 @@ export abstract class TestBuilder { @memoize public getProgram(): ts.Program { this.hasProgram = true; - return tstl.createVirtualProgram( - { ...this.extraFiles, [normalizeSlashes(this.mainFileName)]: this.getTsCode() }, - this.options + + // Exclude lua files from TS program, but keep them in extraFiles so module resolution can find them + const nonLuaExtraFiles = Object.fromEntries( + Object.entries(this.extraFiles).filter(([fileName]) => !fileName.endsWith(".lua")) ); + + return tstl.createVirtualProgram({ ...nonLuaExtraFiles, [this.mainFileName]: this.getTsCode() }, this.options); + } + + private getEmitHost(): EmitHost { + return { + fileExists: (path: string) => normalizeSlashes(path) in this.extraFiles, + directoryExists: (path: string) => + Object.keys(this.extraFiles).some(f => f.startsWith(normalizeSlashes(path))), + getCurrentDirectory: () => ".", + readFile: (path: string) => this.extraFiles[normalizeSlashes(path)] ?? ts.sys.readFile(path), + writeFile() {}, + }; } @memoize public getLuaResult(): tstl.TranspileVirtualProjectResult { const program = this.getProgram(); - const collector = createEmitOutputCollector(); - const { diagnostics: transpileDiagnostics } = new tstl.Transpiler().emit({ + const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); + const collector = createEmitOutputCollector(this.options.extension); + const { diagnostics: transpileDiagnostics } = new tstl.Transpiler({ emitHost: this.getEmitHost() }).emit({ program, customTransformers: this.customTransformers, writeFile: collector.writeFile, }); - const diagnostics = ts.sortAndDeduplicateDiagnostics([ - ...ts.getPreEmitDiagnostics(program), - ...transpileDiagnostics, - ]); + const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); return { diagnostics: [...diagnostics], transpiledFiles: collector.files }; } @@ -205,11 +257,18 @@ export abstract class TestBuilder { @memoize public getMainLuaFileResult(): ExecutableTranspiledFile { const { transpiledFiles } = this.getLuaResult(); + const mainFileName = normalizeSlashes(this.mainFileName); const mainFile = this.options.luaBundle ? transpiledFiles[0] - : transpiledFiles.find(({ sourceFiles }) => - sourceFiles.some(f => normalizeSlashes(f.fileName) === this.mainFileName) - ); + : transpiledFiles.find(({ sourceFiles }) => sourceFiles.some(f => f.fileName === mainFileName)); + + if (mainFile === undefined) { + throw new Error( + `No source file could be found matching main file: ${mainFileName}.\nSource files in test:\n${transpiledFiles + .flatMap(f => f.sourceFiles.map(sf => sf.fileName)) + .join("\n")}` + ); + } expect(mainFile).toMatchObject({ lua: expect.any(String), luaSourceMap: expect.any(String) }); return mainFile as ExecutableTranspiledFile; @@ -231,7 +290,7 @@ export abstract class TestBuilder { const program = this.getProgram(); program.getCompilerOptions().module = ts.ModuleKind.CommonJS; - const collector = createEmitOutputCollector(); + const collector = createEmitOutputCollector(this.options.extension); const { diagnostics } = program.emit(undefined, collector.writeFile); return { transpiledFiles: collector.files, diagnostics: [...diagnostics] }; } @@ -266,11 +325,24 @@ export abstract class TestBuilder { // Actions - public debug(): this { - const transpiledFiles = this.getLuaResult().transpiledFiles; - const luaCode = transpiledFiles.map(f => `[${f.outPath}]:\n${f.lua?.replace(/^/gm, " ")}`); - const value = prettyFormat(this.getLuaExecutionResult()).replace(/^/gm, " "); + public debug(includeLualib = false): this { + const { transpiledFiles, diagnostics } = this.getLuaResult(); + const luaCode = transpiledFiles + .filter(f => includeLualib || f.outPath !== "lualib_bundle.lua") + .map(f => `[${f.outPath}]:\n${f.lua?.replace(/^/gm, " ")}`); + const value = prettyFormat.format(this.getLuaExecutionResult()).replace(/^/gm, " "); console.log(`Lua Code:\n${luaCode.join("\n")}\n\nValue:\n${value}`); + + if (diagnostics.length > 0) { + console.log( + ts.formatDiagnostics(diagnostics.map(tstl.prepareDiagnosticForFormatting), { + getCurrentDirectory: () => "", + getCanonicalFileName: fileName => fileName, + getNewLine: () => "\n", + }) + ); + } + return this; } @@ -298,6 +370,11 @@ export abstract class TestBuilder { return this; } + public expectNoTranspileException(): this { + expect(() => this.getLuaResult()).not.toThrow(); + return this; + } + public expectNoExecutionError(): this { const luaResult = this.getLuaExecutionResult(); if (luaResult instanceof ExecutionError) { @@ -366,20 +443,21 @@ export abstract class TestBuilder { // Main file const mainFile = this.getMainLuaCodeChunk(); - const { lauxlib, lua, lualib } = getLuaBindingsForVersion(this.options.luaTarget ?? tstl.LuaTarget.Lua54); + const luaTarget = this.options.luaTarget ?? tstl.LuaTarget.Lua55; + const { lauxlib, lua, lualib } = getLuaBindingsForVersion(luaTarget); const L = lauxlib.luaL_newstate(); lualib.luaL_openlibs(L); // Load modules // Json - this.packagePreloadLuaFile(L, lua, lauxlib, "json", jsonLib); + this.injectLuaFile(L, lua, lauxlib, "json", jsonLib(luaTarget)); // Lua lib if ( this.options.luaLibImport === tstl.LuaLibImportKind.Require || mainFile.includes('require("lualib_bundle")') ) { - this.packagePreloadLuaFile(L, lua, lauxlib, "lualib_bundle", luaLib); + this.injectLuaFile(L, lua, lauxlib, "lualib_bundle", readLuaLib(luaTarget)); } // Load all transpiled files into Lua's package cache @@ -387,7 +465,7 @@ export abstract class TestBuilder { for (const transpiledFile of transpiledFiles) { if (transpiledFile.lua) { const filePath = path.relative(getEmitOutDir(this.getProgram()), transpiledFile.outPath); - this.packagePreloadLuaFile(L, lua, lauxlib, filePath, transpiledFile.lua); + this.injectLuaFile(L, lua, lauxlib, filePath, transpiledFile.lua); } } @@ -418,12 +496,26 @@ end)());`; } } - private packagePreloadLuaFile(state: LuaState, lua: Lua, lauxlib: LauxLib, fileName: string, fileContent: string) { - // Adding source Lua to the package.preload cache will allow require to find it - lua.lua_getglobal(state, "package"); - lua.lua_getfield(state, -1, "preload"); - lauxlib.luaL_loadstring(state, fileContent); - lua.lua_setfield(state, -2, formatPathToLuaPath(fileName.replace(".lua", ""))); + private injectLuaFile(state: LuaState, lua: Lua, lauxlib: LauxLib, fileName: string, fileContent: string) { + let extension = this.options.extension ?? ".lua"; + if (!extension.startsWith(".")) { + extension = `.${extension}`; + } + const modName = fileName.endsWith(extension) + ? formatPathToLuaPath(fileName.substring(0, fileName.length - extension.length)) + : fileName; + if (this.options.luaTarget === tstl.LuaTarget.Lua50) { + // Adding source Lua to the _LOADED cache will allow require to find it + lua.lua_getglobal(state, "_LOADED"); + lauxlib.luaL_dostring(state, fileContent); + lua.lua_setfield(state, -2, modName); + } else { + // Adding source Lua to the package.preload cache will allow require to find it + lua.lua_getglobal(state, "package"); + lua.lua_getfield(state, -1, "preload"); + lauxlib.luaL_loadstring(state, fileContent); + lua.lua_setfield(state, -2, modName); + } } private executeJs(): any { @@ -440,8 +532,9 @@ end)());`; const moduleExports = {}; globalContext.exports = moduleExports; globalContext.module = { exports: moduleExports }; + const baseName = fileName.replace("./", ""); const transpiledExtraFile = transpiledFiles.find(({ sourceFiles }) => - sourceFiles.some(f => f.fileName === fileName.replace("./", "") + ".ts") + sourceFiles.some(f => f.fileName === baseName + ".ts" || f.fileName === baseName + "/index.ts") ); if (transpiledExtraFile?.js) { @@ -463,6 +556,8 @@ end)());`; try { result = vm.runInContext(this.getJsCodeWithWrapper(), globalContext); } catch (error) { + const hasMessage = (error: any): error is { message: string } => error.message !== undefined; + assert(hasMessage(error)); return new ExecutionError(error.message); } @@ -501,7 +596,7 @@ class AccessorTestBuilder extends TestBuilder { protected accessor = ""; protected getLuaCodeWithWrapper(code: string) { - return `return (function()\n${code}\nend)()${this.accessor}`; + return `return (function(...)\n${code}\nend)()${this.accessor}`; } @memoize @@ -551,7 +646,7 @@ class ProjectTestBuilder extends ModuleTestBuilder { @memoize public getLuaResult(): tstl.TranspileVirtualProjectResult { // Override getLuaResult to use transpileProject with tsconfig.json instead - const collector = createEmitOutputCollector(); + const collector = createEmitOutputCollector(this.options.extension); const { diagnostics } = transpileProject(this.tsConfig, this.options, collector.writeFile); return { diagnostics: [...diagnostics], transpiledFiles: collector.files }; diff --git a/tsconfig-schema.json b/tsconfig-schema.json new file mode 100644 index 000000000..6bffd5e46 --- /dev/null +++ b/tsconfig-schema.json @@ -0,0 +1,114 @@ +{ + "title": "tsconfig.json with TSTL", + "description": "JSON schema for the TypeScript compiler's configuration file with TSTL", + "$schema": "http://json-schema.org/draft-07/schema", + "allOf": [ + { + "$ref": "https://json.schemastore.org/tsconfig" + } + ], + "properties": { + "tstl": { + "description": "TypeScriptToLua compiler options.", + "type": "object", + "definitions": { + "//": { + "reference": "https://typescripttolua.github.io/docs/configuration#custom-options" + } + }, + "properties": { + "buildMode": { + "description": "Use buildMode: \"library\" to build publishable library packages.", + "type": "string", + "default": "library", + "enum": ["default", "library"] + }, + "extension": { + "description": "File extension for the resulting Lua files. Defaults to \".lua\"", + "type": "string" + }, + "lua51AllowTryCatchInAsyncAwait": { + "description": "Disable the warning that try/catch is not allowed in async functions in Lua 5.1, in case you are using a patched 5.1 lua version that supports this.", + "type": "boolean", + "default": false + }, + "luaBundle": { + "description": "The name of the lua file to bundle output lua to. Requires luaBundleEntry.", + "type": "string" + }, + "luaBundleEntry": { + "description": "The entry *.ts file that will be executed when entering the luaBundle. Requires luaBundle.", + "type": "string" + }, + "luaLibImport": { + "description": "Specifies how js standard features missing in lua are imported.", + "type": "string", + "default": "require", + "enum": ["none", "inline", "require", "require-minimal"] + }, + "luaTarget": { + "description": "Specifies the Lua version you want to generate code for.", + "type": "string", + "default": "universal", + "enum": ["5.0", "universal", "5.1", "5.2", "5.3", "5.4", "5.5", "JIT", "Luau"] + }, + "noImplicitGlobalVariables": { + "description": "Always declare all root-level variables as local, even if the file is not a module and they would be global in TypeScript.", + "type": "boolean", + "default": false + }, + "noImplicitSelf": { + "description": "If true, treats all project files as if they were prefixed with\n/** @noSelfInFile **/.", + "type": "boolean", + "default": false + }, + "noHeader": { + "description": "Specify if a header will be added to compiled files.", + "type": "boolean", + "default": false + }, + "noResolvePaths": { + "description": "An array of import paths that should not be resolved but copied verbatim to output lua.", + "type": "array" + }, + "sourceMapTraceback": { + "description": "Applies the source map to show source TS files and lines in error tracebacks.", + "default": false, + "type": "boolean" + }, + "tstlVerbose": { + "description": "Give verbose tstl output, helpful when diagnosing tstl issues.", + "type": "boolean", + "default": false + }, + "luaPlugins": { + "description": "List of TypeScriptToLua plugins.", + "type": "array", + "items": { + "description": "Describes TypeScriptToLua plugin", + "type": "object", + "required": ["name"], + "properties": { + "name": { + "description": "Path to the JS file, that contains the plugin code", + "type": "string" + }, + "import": { + "type": "string" + } + } + } + }, + "measurePerformance": { + "description": "Measure and report performance of the tstl compiler.", + "type": "boolean" + } + }, + "dependencies": { + "luaBundle": ["luaBundleEntry"], + "luaBundleEntry": ["luaBundle"] + } + } + }, + "allowTrailingCommas": true +} diff --git a/tsconfig.json b/tsconfig.json index bf121bd20..1fcbb6d79 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,6 @@ "lib": ["es2019"], "types": ["node"], "module": "commonjs", - "experimentalDecorators": true, "rootDir": "src", "outDir": "dist",