From 2e140ff3aea62e800ce01e5f73f413ca6f49638e Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 05:00:57 +0500 Subject: [PATCH 01/24] Migrate tests to Jest --- .gitignore | 22 +- .prettierignore | 6 + .travis.yml | 14 +- CONTRIBUTING.md | 59 +- appveyor.yml | 2 +- build_lualib.ts | 4 +- jest.config.js | 19 + package-lock.json | 6124 +++++++++++++---- package.json | 58 +- src/Compiler.ts | 26 +- src/TranspileError.ts | 5 +- test/compiler/errorreport.spec.ts | 64 +- test/compiler/outfile.spec.ts | 84 +- test/compiler/project.spec.ts | 160 +- test/compiler/projects/baseurl/tsconfig.json | 1 + .../projects/basic/test_src/test_lib/file.ts | 2 +- .../basic/tsconfig.bothDirOptions.json | 0 test/compiler/projects/basic/tsconfig.json | 5 +- .../projects/basic/tsconfig.outDir.json | 0 .../projects/basic/tsconfig.rootDir.json | 0 .../compiler/projects/watchmode/tsconfig.json | 5 +- test/compiler/projects/watchmode/watch.ts | 2 +- test/compiler/testfiles/out_file.ts | 4 +- test/compiler/testfiles/watch.ts | 2 +- test/compiler/watcher_proccess.js | 6 + test/compiler/watcher_proccess.ts | 5 - test/compiler/watchmode.spec.ts | 101 +- test/{src => }/json.lua | 0 test/runner.ts | 63 - test/test_thread.ts | 36 - test/threaded_runner.ts | 83 - test/translation/builder.spec.ts | 61 +- .../lua/modulesChangedVariableExport.lua | 2 +- .../translation/lua/modulesVariableExport.lua | 2 +- .../lua/modulesVariableNoExport.lua | 2 +- test/translation/ts/callNamespace.ts | 2 +- .../translation/ts/characterEscapeSequence.ts | 10 +- test/translation/ts/classExtension2.ts | 3 +- test/translation/ts/classPureAbstract.ts | 2 +- test/translation/ts/do.ts | 6 +- test/translation/ts/enum.ts | 4 +- test/translation/ts/enumHeterogeneous.ts | 6 +- test/translation/ts/enumString.ts | 6 +- test/translation/ts/exportStatement.ts | 8 +- test/translation/ts/for.ts | 3 +- test/translation/ts/forIn.ts | 8 +- test/translation/ts/getSetAccessors.ts | 4 +- .../ts/modulesChangedVariableExport.ts | 4 +- test/translation/ts/modulesImportAll.ts | 2 +- test/translation/ts/modulesImportNamed.ts | 2 +- .../ts/modulesImportNamedSpecialChars.ts | 10 +- test/translation/ts/modulesImportRenamed.ts | 2 +- .../ts/modulesImportRenamedSpecialChars.ts | 10 +- .../ts/modulesNamespaceExportEnum.ts | 8 +- test/translation/ts/modulesVariableExport.ts | 2 +- .../translation/ts/modulesVariableNoExport.ts | 2 +- test/translation/ts/namespace.ts | 2 +- test/translation/ts/namespacePhantom.ts | 2 +- test/translation/ts/tupleReturn.ts | 68 +- test/translation/ts/typeAssert.ts | 2 +- test/translation/ts/while.ts | 2 +- test/tsconfig.json | 11 +- test/tslint.json | 59 + test/unit/accessors.spec.ts | 709 +- test/unit/array.spec.ts | 284 +- test/unit/assignmentDestructuring.spec.ts | 100 +- test/unit/assignments.spec.ts | 1702 ++--- test/unit/bindingpatterns.spec.ts | 151 +- test/unit/class.spec.ts | 1569 ++--- test/unit/commandLineParser.spec.ts | 474 +- .../configuration/mixed/index.spec.ts | 66 +- .../compiler/configuration/options.spec.ts | 36 +- test/unit/conditionals.spec.ts | 730 +- test/unit/console.spec.ts | 130 +- test/unit/curry.spec.ts | 25 +- test/unit/declarations.spec.ts | 210 +- test/unit/decoratorCustomConstructor.spec.ts | 81 +- test/unit/decoratorMetaExtension.spec.ts | 104 +- test/unit/enum.spec.ts | 361 +- test/unit/error.spec.ts | 117 +- test/unit/expressions.spec.ts | 1037 +-- test/unit/functions.spec.ts | 838 ++- test/unit/hoisting.spec.ts | 454 +- test/unit/importexport.spec.ts | 25 +- test/unit/json.spec.ts | 39 +- test/unit/loops.spec.ts | 1459 ++-- test/unit/lualib/inlining.spec.ts | 89 +- test/unit/lualib/lualib.spec.ts | 921 ++- test/unit/lualib/map.spec.ts | 316 +- test/unit/lualib/set.spec.ts | 282 +- test/unit/lualib/symbol.spec.ts | 123 +- test/unit/lualib/weakMap.spec.ts | 273 +- test/unit/lualib/weakSet.spec.ts | 150 +- test/unit/math.spec.ts | 485 +- test/unit/modules.spec.ts | 116 +- test/unit/objectLiteral.spec.ts | 52 +- test/unit/overloads.spec.ts | 194 +- test/unit/require.spec.ts | 143 +- test/unit/spreadElement.spec.ts | 74 +- test/unit/string.spec.ts | 592 +- test/unit/tshelper.spec.ts | 289 +- test/unit/tuples.spec.ts | 463 +- test/unit/typechecking.spec.ts | 257 +- test/{src => }/util.ts | 143 +- tsconfig.json | 9 +- tslint.json | 68 +- 106 files changed, 12908 insertions(+), 10111 deletions(-) create mode 100644 .prettierignore create mode 100644 jest.config.js mode change 100755 => 100644 test/compiler/projects/basic/test_src/test_lib/file.ts mode change 100755 => 100644 test/compiler/projects/basic/tsconfig.bothDirOptions.json mode change 100755 => 100644 test/compiler/projects/basic/tsconfig.json mode change 100755 => 100644 test/compiler/projects/basic/tsconfig.outDir.json mode change 100755 => 100644 test/compiler/projects/basic/tsconfig.rootDir.json create mode 100644 test/compiler/watcher_proccess.js delete mode 100644 test/compiler/watcher_proccess.ts rename test/{src => }/json.lua (100%) delete mode 100644 test/runner.ts delete mode 100644 test/test_thread.ts delete mode 100644 test/threaded_runner.ts create mode 100644 test/tslint.json rename test/{src => }/util.ts (51%) diff --git a/.gitignore b/.gitignore index 987b45888..0878aa261 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,10 @@ -*.js -node_modules/ -yarn.lock - -.vscode/ +/node_modules +/dist +/coverage -coverage/ -.nyc* -*.js.map +yarn.lock +.vscode +.idea # Release *.tgz @@ -14,11 +12,3 @@ coverage/ # OSX .DS_Store *.lcov - -# IDEA IDEs -.idea/ - -typescript_lualib.lua -lualib_bundle.lua - -dist/* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..5048d1b5a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +/dist +/coverage +/__tests__/compiler/testfiles/invalid_syntax.ts + +/src +*.md diff --git a/.travis.yml b/.travis.yml index 14b56e048..79fcbeed8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,13 @@ language: node_js node_js: -- stable -install: -- npm install + - stable + script: -- npm run build -- npm run coverage -after_success: -- codecov + - npm run lint + - npm run build + - npm test -- --coverage +after_success: npx codecov + deploy: provider: npm email: lorenz.junglas@student.kit.edu diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13f2db018..130a8ed03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,59 +14,24 @@ To get familiar with the project structure, here is a short overview of each dir * `src/targets/` - Version-specific transpiler overrides for the different Lua targets. The main transpiler transpiles Lua 5.0, each target-specific transpiler extends the transpiler of the version before it, so the 5.3 inherits 5.2 which inherits 5.1 which inherits 5.0. LuaJIT is based on 5.2 so inherits from the 5.2 transpiler. * *Compiler.ts* - Main entry point of the transpiler, this is what interfaces with the TypeScript compiler API. - * *Transpiler.ts* - Main transpiler code, transforms a TypeScript AST to a Lua string. + * *LuaTransformer.ts* - Main transpiler code, transforms a TypeScript AST to a Lua AST. + * *LuaPrinter.ts* - Transforms a Lua AST to a string. * *TSHelper.ts* - Helper methods used during the transpilation process. -- `test/` +- `__tests__/` * This directory contains all testing code for the transpiler. - * `test/src/` - - Contains all extra source and utility used to run tests. - * `test/unit/` + * `__tests__/unit/` - Unit/Functional tests for the transpiler. Tests in here are grouped by functionality they are testing. Generally each of these tests uses the transpiler to transpile some TypeScript to Lua, then executes it using the Fengari Lua VM. Assertion is done on the result of the lua code. - * `test/translation/` + * `__tests__/translation/` - **[Obsolete]** Contains tests that only check the transpiled Lua String. We prefer adding unit/functional tests over translation tests. This directory will probably be removed at some point. ## Running Tests -The tests for this project can be executed using the standard `npm test`. This runs all tests (can take a while!). +The tests for this project can be executed using the standard `npm test`. This runs all tests. -### Testing while developing -Due to the time required to run all tests, it is impractical to run every test while developing part of the transpiler. To speed up the test run you can import `FocusTest` or `FocusTests` from Alsatian. If a class is decorated with `@FocusTests`, all other test classes will be ignored. Similarly, if any test method is decorated with `@FocusTest`, only `@FocusTest` methods will be run during `npm test`. - -For example: -```ts -import { Expect, FocusTests, Test, TestCase } from "alsatian"; - -@FocusTests -export class FunctionTests { - // All tests in here will be executed. -} - -// All other tests will be ignored. -``` - -Or - -```ts -import { Expect, FocusTest, Test, TestCase } from "alsatian"; - -export class FunctionTests { - @FocusTest - @Test("Example test 1") - public test1(): void { // Will be executed - } - - @FocusTest - @Test("Example test 2") - public test2(): void { // Will also be executed - } - - @Test("Example test 3") - public test3(): void { // Will be ignored - } -} - -// All other tests will be ignored. -``` +Due to the time required to run all tests, it is impractical to run every test while developing part of the transpiler. To speed up the test run you can: +- Use `npm test -- --watchAll` to start tests and rerun them on change +- Use `npm test name` or interactive watching interface to run tests that match a file name pattern +- Add `.only` to test definition to run a single test in the file ## Testing Guidelines When submitting a pull request with new functionality, we require some functional (transpile and execute Lua) to be added, to ensure the new functionality works as expected, and will continue to work that way. @@ -74,7 +39,9 @@ When submitting a pull request with new functionality, we require some functiona Translation tests are discouraged as in most cases as we do not really care about the exact Lua output, as long as executing it results in the correct result (which is tested by functional tests). ## Coding Conventions -Most coding conventions are enforced by the ts-lint configuration. The test process will fail if code does not pass the linter. Some extra conventions worth mentioning: +Most coding conventions are enforced by the TSLint and Prettier. You can check your code locally by running `npm run lint`. CI process will fail if code does not pass the linter. You also might want to get extensions for your code editor to get immediate feedback. + +Some extra conventions worth mentioning: * Do not abbreviate variable names. The exception here are inline lambda arguments, if it is obvious what the argument is you can abbreviate to the first letter, e.g: `statements.filter(s => ts.VariableStatement(s))` * Readability of code is more important than the amount of space it takes. If extra line breaks make your code more readable, add them. * Functional style is encouraged! diff --git a/appveyor.yml b/appveyor.yml index 513dd7593..6ae337099 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ install: # Get the latest stable version of Node.js or io.js - ps: Install-Product node $env:nodejs_version # install modules - - npm install + - npm ci # Post-install test scripts. test_script: diff --git a/build_lualib.ts b/build_lualib.ts index 7ca05f26f..e9f456217 100644 --- a/build_lualib.ts +++ b/build_lualib.ts @@ -1,7 +1,7 @@ import * as fs from "fs"; import * as glob from "glob"; -import {compile} from "./src/Compiler"; -import {LuaLib as luaLib, LuaLibFeature} from "./src/LuaLib"; +import { compile } from "./src/Compiler"; +import { LuaLib as luaLib, LuaLibFeature } from "./src/LuaLib"; const bundlePath = "./dist/lualib/lualib_bundle.lua"; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..4ee118e9c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,19 @@ +// @ts-check +const isCI = require("is-ci"); + +/** @type {Partial} */ +module.exports = { + testMatch: ["**/__tests__/**/*.test.ts"], + collectCoverageFrom: ["/src/**/*", "!/src/lualib/**/*"], + watchPathIgnorePatterns: ["/watch\\.ts$"], + + testEnvironment: "node", + testRunner: "jest-circus/runner", + preset: "ts-jest", + globals: { + "ts-jest": { + tsConfig: "/__tests__/tsconfig.json", + diagnostics: { warnOnly: !isCI }, + }, + }, +}; diff --git a/package-lock.json b/package-lock.json index 0d029c704..e9985dd62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,103 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.0.tgz", + "integrity": "sha512-Dzl7U0/T69DFOTwqz/FJdnOSWS57NpjNfCwMKHABr589Lg8uX1RrlBIJ7L5Dubt/xkLsx0xH5EBFzlBVes1ayA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helpers": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", + "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", + "dev": true, + "requires": { + "@babel/types": "^7.4.0" + } + }, + "@babel/parser": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.2.tgz", + "integrity": "sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==", + "dev": true + }, + "@babel/template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", + "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/traverse": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.0.tgz", + "integrity": "sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", + "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "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.3.2", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.2.tgz", @@ -54,6 +151,12 @@ "@babel/types": "^7.0.0" } }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, "@babel/helper-split-export-declaration": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", @@ -63,6 +166,92 @@ "@babel/types": "^7.0.0" } }, + "@babel/helpers": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.2.tgz", + "integrity": "sha512-gQR1eQeroDzFBikhrCccm5Gs2xBjZ57DNjGbqTaHo911IpmSxflOQWMAHPw/TXk8L3isv7s9lYzUkexOeTQUYg==", + "dev": true, + "requires": { + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", + "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", + "dev": true, + "requires": { + "@babel/types": "^7.4.0" + } + }, + "@babel/parser": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.2.tgz", + "integrity": "sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==", + "dev": true + }, + "@babel/template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", + "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0" + } + }, + "@babel/traverse": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.0.tgz", + "integrity": "sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", + "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, + "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/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -117,6 +306,15 @@ "integrity": "sha512-QzNUC2RO1gadg+fs21fi0Uu0OuGNzRKEmgCxoLNzbCdoprLwjfmZwzUrpUNfJPaVRwBpDY47A17yYEGWyRelnQ==", "dev": true }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, "@babel/template": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", @@ -156,1535 +354,3700 @@ "to-fast-properties": "^2.0.0" } }, - "@types/events": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", - "dev": true - }, - "@types/glob": { - "version": "5.0.35", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", - "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@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": "9.6.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.23.tgz", - "integrity": "sha512-d2SJJpwkiPudEQ3+9ysANN2Nvz4QJKUPoe/WL5zyQzI0RaEeZWH5K5xjvUIGszTItHQpFPdH+u51f6G/LkS8Cg==", - "dev": true - }, - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "alsatian": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/alsatian/-/alsatian-2.3.0.tgz", - "integrity": "sha512-e83K7JpH9Hj1+TUYyZialNKDln5gW56C82CVcd0AMt2whLFtKzYiddE5Dz2biUWjT8KzF11lkwonzf9wOCQyAA==", + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", "dev": true, "requires": { - "@types/node": ">=4.0.0", - "extendo-error": "^1.0.1", - "glob": "^7.0.3", - "reflect-metadata": "^0.1.3", - "tap-bark": "1.0.0" + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "@jest/console": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.3.0.tgz", + "integrity": "sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "@jest/source-map": "^24.3.0", + "@types/node": "*", + "chalk": "^2.0.1", + "slash": "^2.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" + } + }, + "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" + } + } } }, - "argv": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", - "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "@jest/core": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.5.0.tgz", + "integrity": "sha512-RDZArRzAs51YS7dXG1pbXbWGxK53rvUu8mCDYsgqqqQ6uSOaTjcVyBl2Jce0exT2rSLk38ca7az7t2f3b0/oYQ==", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "@jest/console": "^24.3.0", + "@jest/reporters": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.5.0", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve-dependencies": "^24.5.0", + "jest-runner": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "jest-watcher": "^24.5.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "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" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "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" + } + } } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "@jest/environment": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.5.0.tgz", + "integrity": "sha512-tzUHR9SHjMXwM8QmfHb/EJNbF0fjbH4ieefJBvtwO8YErLTrecc1ROj0uo2VnIT6SlpEGZnvdCK6VgKYBo8LsA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@jest/fake-timers": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-mock": "^24.5.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 - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "@jest/fake-timers": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.5.0.tgz", + "integrity": "sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "@jest/types": "^24.5.0", + "@types/node": "*", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0" } }, - "codecov": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.2.0.tgz", - "integrity": "sha512-3NJvNARXxilqnqVfgzDHyVrF4oeVgaYW1c1O6Oi5mn93exE7HTSSFNiYdwojWW6IwrCZABJ8crpNbKoo9aUHQw==", + "@jest/reporters": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.5.0.tgz", + "integrity": "sha512-vfpceiaKtGgnuC3ss5czWOihKOUSyjJA4M4udm6nH8xgqsuQYcyDCi4nMMcBKsHXWgz9/V5G7iisnZGfOh1w6Q==", "dev": true, "requires": { - "argv": "^0.0.2", - "ignore-walk": "^3.0.1", - "js-yaml": "^3.12.0", - "teeny-request": "^3.7.0", - "urlgrey": "^0.4.4" + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-api": "^2.1.1", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-source-maps": "^3.0.1", + "jest-haste-map": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "node-notifier": "^5.2.1", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" }, "dependencies": { - "js-yaml": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", - "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", - "dev": true, + "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": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "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" + } + }, + "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" } } } }, - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "@jest/source-map": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", + "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", "dev": true, "requires": { - "color-name": "1.1.1" + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" } }, - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", - "dev": true + "@jest/test-result": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.5.0.tgz", + "integrity": "sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/types": "^24.5.0", + "@types/istanbul-lib-coverage": "^1.1.0" + } }, - "commander": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", - "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", - "dev": true + "@jest/transform": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.5.0.tgz", + "integrity": "sha512-XSsDz1gdR/QMmB8UCKlweAReQsZrD/DK7FuDlNo/pE8EcKMrfi2kqLRk8h8Gy/PDzgqJj64jNEzOce9pR8oj1w==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-util": "^24.5.0", + "micromatch": "^3.1.10", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "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" + } + }, + "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" + } + } + } }, - "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 + "@jest/types": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.5.0.tgz", + "integrity": "sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^1.1.0", + "@types/yargs": "^12.0.9" + } }, - "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 + "@types/babel__core": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.0.tgz", + "integrity": "sha512-wJTeJRt7BToFx3USrCDs2BhEi4ijBInTQjOIukj6a/5tEkwpFMVZ+1ppgmE+Q/FQyc5P/VWUbx7I9NELrKruHA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "@babel/types": "^7.0.0" } }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true + "@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" + } }, - "diff": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", - "dev": true + "@types/babel__traverse": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", + "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "@types/events": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", "dev": true }, - "es6-promise": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", - "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "@types/glob": { + "version": "5.0.35", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", + "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", "dev": true }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "@types/jest": { + "version": "24.0.11", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.11.tgz", + "integrity": "sha512-2kLuPC5FDnWIDvaJBzsGTBQaBbnDweznicvK7UGYzlIJP4RJR2a4A/ByLUXEyEgag6jz8eHdlWExGDtH3EYUXQ==", "dev": true, "requires": { - "es6-promise": "^4.0.3" + "@types/jest-diff": "*" } }, - "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=", + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "@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 }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "@types/node": { + "version": "9.6.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.23.tgz", + "integrity": "sha512-d2SJJpwkiPudEQ3+9ysANN2Nvz4QJKUPoe/WL5zyQzI0RaEeZWH5K5xjvUIGszTItHQpFPdH+u51f6G/LkS8Cg==", "dev": true }, - "eventemitter3": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", - "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=", + "@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 }, - "events-to-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", - "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", + "@types/yargs": { + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.10.tgz", + "integrity": "sha512-WsVzTPshvCSbHThUduGGxbmnwcpkgSctHGHTqzWyFg4lYAuV5qXlyFPOsP3OWqCINfmg/8VXP+zJaa4OxEsBQQ==", "dev": true }, - "extendo-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/extendo-error/-/extendo-error-1.0.1.tgz", - "integrity": "sha1-MDJeDPbC+l+RAj0hAO0CGCbmMX0=", + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", "dev": true }, - "fengari": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.2.tgz", - "integrity": "sha512-NleQtQymPtbjBPnGOQiXfZfKpP3R7si+Sbkke631PWNnZt86eZSlymRJ0qv/KUTcz0fSsWO1iltZYz5/JV1uYQ==", + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", "dev": true, "requires": { - "readline-sync": "^1.4.9", - "sprintf-js": "^1.1.1", - "tmp": "^0.0.33" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" }, "dependencies": { - "sprintf-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", - "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=", + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "dev": true } } }, - "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", "dev": true }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "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" + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, - "https-proxy-agent": { + "ansi-styles": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "agent-base": "^4.1.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "default-require-extensions": "^2.0.0" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "sprintf-js": "~1.0.2" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "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 }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "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 }, - "istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "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 }, - "istanbul-lib-instrument": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", - "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", - "dev": true, - "requires": { - "@babel/generator": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/template": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "istanbul-lib-coverage": "^2.0.3", - "semver": "^5.5.0" - } + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "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 }, - "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "safer-buffer": "~2.1.0" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "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 }, - "make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "lodash": "^4.17.11" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "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 }, - "native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "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 }, - "node-fetch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", - "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==", + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, - "nyc": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.3.0.tgz", - "integrity": "sha512-P+FwIuro2aFG6B0Esd9ZDWUd51uZrAEoGutqZxzrVmYl3qSfkLgcQpBPBjtDFsUQLFY1dvTQJPOyeqr8S9GF8w==", + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^3.0.1", - "convert-source-map": "^1.6.0", - "find-cache-dir": "^2.0.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.3", - "istanbul-lib-hook": "^2.0.3", - "istanbul-lib-instrument": "^3.1.0", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.2", - "istanbul-reports": "^2.1.1", - "make-dir": "^1.3.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.1.0", - "uuid": "^3.3.2", - "yargs": "^12.0.5", - "yargs-parser": "^11.1.1" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.5.0.tgz", + "integrity": "sha512-0fKCXyRwxFTJL0UXDJiT2xYxO9Lu2vBd9n+cC+eDjESzcVG3s2DRGAxbzJX21fceB1WYoBjAh8pQ83dKcl003g==", + "dev": true, + "requires": { + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.3.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "append-transform": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "async": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "caching-transform": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "hasha": "^3.0.0", - "make-dir": "^1.3.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.3.0" - } - }, - "camelcase": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "cliui": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "commander": { - "version": "2.17.1", - "bundled": true, - "dev": true, - "optional": true - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cross-spawn": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "debug": { - "version": "4.1.1", - "bundled": true, + "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": { - "ms": "^2.1.1" + "color-convert": "^1.9.0" } }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "default-require-extensions": { - "version": "2.0.0", - "bundled": true, + "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": { - "strip-bom": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "end-of-stream": { - "version": "1.4.1", - "bundled": 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": { - "once": "^1.4.0" + "has-flag": "^3.0.0" } - }, - "error-ex": { - "version": "1.3.2", - "bundled": true, + } + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.3.0.tgz", + "integrity": "sha512-nWh4N1mVH55Tzhx2isvUN5ebM5CDUvIpXPZYMRazQughie/EqGnbR+czzoQlhUmJG9pPJmYDRhvocotb2THl1w==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.3.0.tgz", + "integrity": "sha512-VGTV2QYBa/Kn3WCOKdfS31j9qomaXSgJqi65B6o05/1GsJyj9LVhSljM9ro4S+IBGj/ENhNBuH9bpqzztKAQSw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.3.0" + } + }, + "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-arrayish": "^0.2.1" + "is-descriptor": "^1.0.0" } }, - "es6-error": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "execa": { + "is-accessor-descriptor": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "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" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "bundled": true, - "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" - } - } + "kind-of": "^6.0.0" } }, - "find-cache-dir": { - "version": "2.0.0", - "bundled": true, + "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": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^3.0.0" + "kind-of": "^6.0.0" } }, - "find-up": { - "version": "3.0.0", - "bundled": true, + "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": { - "locate-path": "^3.0.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } - }, - "foreground-child": { - "version": "1.5.6", - "bundled": true, + } + } + }, + "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": "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": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" + "is-extendable": "^0.1.0" } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, + } + } + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "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 - }, - "get-caller-file": { - "version": "1.0.3", - "bundled": 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.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "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 + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "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.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "camelcase": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.2.0.tgz", + "integrity": "sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ==", + "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": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "get-stream": { - "version": "4.1.0", - "bundled": true, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "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": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", + "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", + "dev": true + }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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 + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "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-env": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", + "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.5", + "is-windows": "^1.0.0" + } + }, + "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.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", + "dev": true + }, + "cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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 + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "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": { - "pump": "^3.0.0" + "kind-of": "^6.0.0" } }, - "glob": { - "version": "7.1.3", - "bundled": true, + "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": { - "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" + "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": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "dev": true + }, + "diff-sequences": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", + "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "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" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "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.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "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.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "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": "24.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.5.0.tgz", + "integrity": "sha512-p2Gmc0CLxOgkyA93ySWmHFYHUPFIHG6XZ06l7WArWAsrqYVaVEkOU5NtT5i68KUyGKbkQgDCkiT65bWmdoL6Bw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.3.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-regex-util": "^24.3.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" + } + } + } + }, + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "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 + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fengari": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.2.tgz", + "integrity": "sha512-NleQtQymPtbjBPnGOQiXfZfKpP3R7si+Sbkke631PWNnZt86eZSlymRJ0qv/KUTcz0fSsWO1iltZYz5/JV1uYQ==", + "dev": true, + "requires": { + "readline-sync": "^1.4.9", + "sprintf-js": "^1.1.1", + "tmp": "^0.0.33" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", + "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=", + "dev": true + } + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "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" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "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.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "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.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz", + "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "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==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "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": { + "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.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "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" + } + }, + "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" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.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.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "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.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "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-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.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "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-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-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", + "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==", + "dev": true + }, + "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" + } + } + } + }, + "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-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "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-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "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-api": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "compare-versions": "^3.2.1", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.3", + "istanbul-lib-hook": "^2.0.3", + "istanbul-lib-instrument": "^3.1.0", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.2", + "istanbul-reports": "^2.1.1", + "js-yaml": "^3.12.0", + "make-dir": "^1.3.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", + "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", + "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "supports-color": "^6.0.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", + "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", + "dev": true, + "requires": { + "handlebars": "^4.1.0" + } + }, + "jest": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.5.0.tgz", + "integrity": "sha512-lxL+Fq5/RH7inxxmfS2aZLCf8MsS+YCUBfeiNO6BWz/MmjhDGaIEA/2bzEf9q4Q0X+mtFHiinHFvQ0u+RvW/qQ==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.5.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" } }, - "graceful-fs": { - "version": "4.1.15", - "bundled": true, - "dev": true - }, - "handlebars": { - "version": "4.1.0", - "bundled": true, + "jest-cli": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.5.0.tgz", + "integrity": "sha512-P+Jp0SLO4KWN0cGlNtC7JV0dW1eSFR7eRpoOucP2UM0sqlzp/bVHeo71Omonvigrj9AvCKy7NtQANtqJ7FXz8g==", "dev": true, "requires": { - "async": "^2.5.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } + "@jest/core": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^12.0.2" } }, - "has-flag": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "hasha": { - "version": "3.0.0", - "bundled": 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": { - "is-stream": "^1.0.1" + "has-flag": "^3.0.0" } - }, - "hosted-git-info": { - "version": "2.7.1", - "bundled": true, - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, + } + } + }, + "jest-changed-files": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.5.0.tgz", + "integrity": "sha512-Ikl29dosYnTsH9pYa1Tv9POkILBhN/TLZ37xbzgNsZ1D2+2n+8oEZS2yP1BrHn/T4Rs4Ggwwbp/x8CKOS5YJOg==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-circus": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-24.5.0.tgz", + "integrity": "sha512-meGSoAA5rMv+93Wz8KY3FZcJ7aEbXqrgI2F/emPRCVzGXOvR8oQl8GvYBrIbpJW7G0vwnVSjLQMeTMHs1geu5g==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.5.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0", + "stack-utils": "^1.0.1", + "throat": "^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": { - "once": "^1.3.0", - "wrappy": "1" + "color-convert": "^1.9.0" } }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.3", - "bundled": true, + "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": { - "append-transform": "^1.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "istanbul-lib-report": { - "version": "2.0.4", - "bundled": 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": { - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "supports-color": "^6.0.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "has-flag": "^3.0.0" } - }, - "istanbul-lib-source-maps": { - "version": "3.0.2", - "bundled": true, + } + } + }, + "jest-config": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.5.0.tgz", + "integrity": "sha512-t2UTh0Z2uZhGBNVseF8wA2DS2SuBiLOL6qpLq18+OZGfFUxTM7BzUVKyHFN/vuN+s/aslY1COW95j1Rw81huOQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.5.0", + "babel-jest": "^24.5.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.5.0", + "jest-environment-node": "^24.5.0", + "jest-get-type": "^24.3.0", + "jest-jasmine2": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.5.0", + "realpath-native": "^1.1.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": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.3", - "make-dir": "^1.3.0", - "rimraf": "^2.6.2", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } + "color-convert": "^1.9.0" } }, - "istanbul-reports": { - "version": "2.1.1", - "bundled": true, + "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": { - "handlebars": "^4.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "json-parse-better-errors": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "lcid": { - "version": "2.0.0", - "bundled": 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": { - "invert-kv": "^2.0.0" + "has-flag": "^3.0.0" } - }, - "load-json-file": { - "version": "4.0.0", - "bundled": true, + } + } + }, + "jest-diff": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.5.0.tgz", + "integrity": "sha512-mCILZd9r7zqL9Uh6yNoXjwGQx0/J43OD2vvWVKwOEOLZliQOsojXwqboubAQ+Tszrb6DHGmNU7m4whGeB9YOqw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.3.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.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": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "color-convert": "^1.9.0" } }, - "locate-path": { - "version": "3.0.0", - "bundled": true, + "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": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "lodash": { - "version": "4.17.11", - "bundled": true, - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "bundled": true, - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "bundled": 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": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "has-flag": "^3.0.0" } - }, - "make-dir": { - "version": "1.3.0", - "bundled": true, + } + } + }, + "jest-docblock": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", + "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.5.0.tgz", + "integrity": "sha512-6gy3Kh37PwIT5sNvNY2VchtIFOOBh8UCYnBlxXMb5sr5wpJUDPTUATX2Axq1Vfk+HWTMpsYPeVYp4TXx5uqUBw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.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": { - "pify": "^3.0.0" + "color-convert": "^1.9.0" } }, - "map-age-cleaner": { - "version": "0.1.3", - "bundled": true, + "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": { - "p-defer": "^1.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "mem": { - "version": "4.1.0", - "bundled": 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": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^2.0.0" + "has-flag": "^3.0.0" } - }, - "merge-source-map": { - "version": "1.1.0", - "bundled": true, + } + } + }, + "jest-environment-jsdom": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.5.0.tgz", + "integrity": "sha512-62Ih5HbdAWcsqBx2ktUnor/mABBo1U111AvZWcLKeWN/n/gc5ZvDBKe4Og44fQdHKiXClrNGC6G0mBo6wrPeGQ==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.5.0.tgz", + "integrity": "sha512-du6FuyWr/GbKLsmAbzNF9mpr2Iu2zWSaq/BNHzX+vgOcts9f2ayXBweS7RAhr+6bLp6qRpMB6utAMF5Ygktxnw==", + "dev": true, + "requires": { + "@jest/environment": "^24.5.0", + "@jest/fake-timers": "^24.5.0", + "@jest/types": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0" + } + }, + "jest-get-type": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.3.0.tgz", + "integrity": "sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow==", + "dev": true + }, + "jest-haste-map": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.5.0.tgz", + "integrity": "sha512-mb4Yrcjw9vBgSvobDwH8QUovxApdimGcOkp+V1ucGGw4Uvr3VzZQBJhNm1UY3dXYm4XXyTW2G7IBEZ9pM2ggRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.4.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3" + } + }, + "jest-jasmine2": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.5.0.tgz", + "integrity": "sha512-sfVrxVcx1rNUbBeyIyhkqZ4q+seNKyAG6iM0S2TYBdQsXjoFDdqWFfsUxb6uXSsbimbXX/NMkJIwUZ1uT9+/Aw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.5.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "pretty-format": "^24.5.0", + "throat": "^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": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } + "color-convert": "^1.9.0" } }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, + "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": { - "brace-expansion": "^1.1.7" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "minimist": { - "version": "0.0.10", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": 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": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - } + "has-flag": "^3.0.0" + } + } + } + }, + "jest-leak-detector": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.5.0.tgz", + "integrity": "sha512-LZKBjGovFRx3cRBkqmIg+BZnxbrLqhQl09IziMk3oeh1OV81Hg30RUIx885mq8qBv1PA0comB9bjKcuyNO1bCQ==", + "dev": true, + "requires": { + "pretty-format": "^24.5.0" + } + }, + "jest-matcher-utils": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.5.0.tgz", + "integrity": "sha512-QM1nmLROjLj8GMGzg5VBra3I9hLpjMPtF1YqzQS3rvWn2ltGZLrGAO1KQ9zUCVi5aCvrkbS5Ndm2evIP9yZg1Q==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.5.0", + "jest-get-type": "^24.3.0", + "pretty-format": "^24.5.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" } }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "bundled": true, + "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": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "npm-run-path": { - "version": "2.0.2", - "bundled": 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": { - "path-key": "^2.0.0" + "has-flag": "^3.0.0" } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "once": { - "version": "1.4.0", - "bundled": true, + } + } + }, + "jest-message-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.5.0.tgz", + "integrity": "sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "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": { - "wrappy": "1" + "color-convert": "^1.9.0" } }, - "optimist": { - "version": "0.6.1", - "bundled": true, + "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": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "bundled": 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": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "has-flag": "^3.0.0" } - }, - "p-defer": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-is-promise": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "2.1.0", - "bundled": true, + } + } + }, + "jest-mock": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.5.0.tgz", + "integrity": "sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-regex-util": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", + "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==", + "dev": true + }, + "jest-resolve": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.5.0.tgz", + "integrity": "sha512-ZIfGqLX1Rg8xJpQqNjdoO8MuxHV1q/i2OO1hLXjgCWFWs5bsedS8UrOdgjUqqNae6DXA+pCyRmdcB7lQEEbXew==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.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": { - "p-try": "^2.0.0" + "color-convert": "^1.9.0" } }, - "p-locate": { - "version": "3.0.0", - "bundled": true, + "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": { - "p-limit": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "p-try": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "package-hash": { - "version": "3.0.0", - "bundled": 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": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" + "has-flag": "^3.0.0" } - }, - "parse-json": { - "version": "4.0.0", - "bundled": true, + } + } + }, + "jest-resolve-dependencies": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.5.0.tgz", + "integrity": "sha512-dRVM1D+gWrFfrq2vlL5P9P/i8kB4BOYqYf3S7xczZ+A6PC3SgXYSErX/ScW/469pWMboM1uAhgLF+39nXlirCQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.5.0" + } + }, + "jest-runner": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.5.0.tgz", + "integrity": "sha512-oqsiS9TkIZV5dVkD+GmbNfWBRPIvxqmlTQ+AQUJUQ07n+4xTSDc40r+aKBynHw9/tLzafC00DIbJjB2cOZdvMA==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.5.0", + "jest-jasmine2": "^24.5.0", + "jest-leak-detector": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "jest-runtime": "^24.5.0", + "jest-util": "^24.5.0", + "jest-worker": "^24.4.0", + "source-map-support": "^0.5.6", + "throat": "^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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "color-convert": "^1.9.0" } }, - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "bundled": true, - "dev": true - }, - "path-type": { - "version": "3.0.0", - "bundled": true, + "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": { - "pify": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "pify": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "bundled": 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": { - "find-up": "^3.0.0" + "has-flag": "^3.0.0" } - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "pump": { - "version": "3.0.0", - "bundled": true, + } + } + }, + "jest-runtime": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.5.0.tgz", + "integrity": "sha512-GTFHzfLdwpaeoDPilNpBrorlPoNZuZrwKKzKJs09vWwHo+9TOsIIuszK8cWOuKC7ss07aN1922Ge8fsGdsqCuw==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/environment": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/yargs": "^12.0.2", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.5.0", + "jest-haste-map": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-mock": "^24.5.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.5.0", + "jest-snapshot": "^24.5.0", + "jest-util": "^24.5.0", + "jest-validate": "^24.5.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^12.0.2" + }, + "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": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "color-convert": "^1.9.0" } }, - "read-pkg": { - "version": "3.0.0", - "bundled": true, + "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": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "read-pkg-up": { - "version": "4.0.0", - "bundled": true, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" + "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" } }, - "release-zalgo": { - "version": "1.0.0", - "bundled": 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": { - "es6-error": "^4.0.1" + "has-flag": "^3.0.0" } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "resolve": { - "version": "1.10.0", - "bundled": true, + } + } + }, + "jest-serializer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", + "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==", + "dev": true + }, + "jest-snapshot": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.5.0.tgz", + "integrity": "sha512-eBEeJb5ROk0NcpodmSKnCVgMOo+Qsu5z9EDl3tGffwPzK1yV37mjGWF2YeIz1NkntgTzP+fUL4s09a0+0dpVWA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.5.0", + "chalk": "^2.0.1", + "expect": "^24.5.0", + "jest-diff": "^24.5.0", + "jest-matcher-utils": "^24.5.0", + "jest-message-util": "^24.5.0", + "jest-resolve": "^24.5.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.5.0", + "semver": "^5.5.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": { - "path-parse": "^1.0.6" + "color-convert": "^1.9.0" } }, - "resolve-from": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, + "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": { - "glob": "^7.1.3" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.6.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": 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": { - "shebang-regex": "^1.0.0" + "has-flag": "^3.0.0" } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "spawn-wrap": { - "version": "1.4.2", - "bundled": true, + } + } + }, + "jest-util": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.5.0.tgz", + "integrity": "sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q==", + "dev": true, + "requires": { + "@jest/console": "^24.3.0", + "@jest/fake-timers": "^24.5.0", + "@jest/source-map": "^24.3.0", + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.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": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" + "color-convert": "^1.9.0" } }, - "spdx-correct": { - "version": "3.1.0", - "bundled": true, + "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": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "spdx-exceptions": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": 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": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "has-flag": "^3.0.0" } - }, - "spdx-license-ids": { - "version": "3.0.3", - "bundled": true, - "dev": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, + } + } + }, + "jest-validate": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.5.0.tgz", + "integrity": "sha512-gg0dYszxjgK2o11unSIJhkOFZqNRQbWOAB2/LOUdsd2LfD9oXiMeuee8XsT0iRy5EvSccBgB4h/9HRbIo3MHgQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "camelcase": "^5.0.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.3.0", + "leven": "^2.1.0", + "pretty-format": "^24.5.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": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "color-convert": "^1.9.0" } }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, + "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-regex": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "strip-bom": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "test-exclude": { - "version": "5.1.0", - "bundled": 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": { - "arrify": "^1.0.1", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^1.0.1" + "has-flag": "^3.0.0" } - }, - "uglify-js": { - "version": "3.4.9", - "bundled": true, + } + } + }, + "jest-watcher": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.5.0.tgz", + "integrity": "sha512-/hCpgR6bg0nKvD3nv4KasdTxuhwfViVMHUATJlnGCD0r1QrmIssimPbmc5KfAQblAVxkD8xrzuij9vfPUk1/rA==", + "dev": true, + "requires": { + "@jest/test-result": "^24.5.0", + "@jest/types": "^24.5.0", + "@types/node": "*", + "@types/yargs": "^12.0.9", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.5.0", + "string-length": "^2.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, - "optional": true, "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - } + "color-convert": "^1.9.0" } }, - "uuid": { - "version": "3.3.2", - "bundled": true, - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "bundled": true, + "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": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "which": { - "version": "1.3.1", - "bundled": 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": { - "isexe": "^2.0.0" + "has-flag": "^3.0.0" } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "bundled": true, - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, + } + } + }, + "jest-worker": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.4.0.tgz", + "integrity": "sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "has-flag": "^3.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "2.4.2", - "bundled": true, + } + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "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": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "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-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "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-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.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "kleur": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.2.tgz", + "integrity": "sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "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" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "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 + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "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-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "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" + } + }, + "mem": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.2.0.tgz", + "integrity": "sha512-5fJxa68urlY0Ir8ijatKa3eRz5lwXnRCTvo9+TbTGAuTFJOwpGcY0X05moBd0nW45965Njt4CDI2GFQoG8DvqA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "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" + } + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "~1.38.0" + } + }, + "mimic-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.0.0.tgz", + "integrity": "sha512-jbex9Yd/3lmICXwYT6gA/j2mNQGU48wCh/VzRd+/Y/PjYQtlg1gLMdZqvu9s/xH7qKvngxRObl56XZR609IMbA==", + "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.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "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": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-plain-object": "^2.0.4" } - }, - "y18n": { - "version": "4.0.0", - "bundled": true, + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true, + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "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 + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "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": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.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" + }, + "dependencies": { + "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==", "dev": true }, - "yargs": { - "version": "12.0.5", - "bundled": true, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "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" + } + }, + "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" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.1.tgz", + "integrity": "sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg==", + "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": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "is-descriptor": "^0.1.0" } }, - "yargs-parser": { - "version": "11.1.1", - "bundled": true, + "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": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "is-buffer": "^1.1.5" } } } }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "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.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "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" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1694,36 +4057,334 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "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-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-try": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.1.0.tgz", + "integrity": "sha512-H2RyIJ7+A3rjkwKC2l5GGtU4H1vkxKCAGsWasNVd0Set+6i4znxbWy6/j16YDPJDWxhsgZiKAstMEP8wCdSpjA==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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.5", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.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 + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "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": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "dev": true + }, + "pretty-format": { + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.5.0.tgz", + "integrity": "sha512-/3RuSghukCf8Riu5Ncve0iI+BzVkbRU5EeUoArKARZobREycuH5O4waxvaNIloEXdb0qwgmEAed5vTpX1HNROQ==", + "dev": true, + "requires": { + "@jest/types": "^24.5.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "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" + } + } + } + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, + "prompts": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.4.tgz", + "integrity": "sha512-HTzM3UWp/99A0gk51gAegwo1QRYA7xjcZufMNe33rCclFszUYAuHe1fIN/3ZmiHeGPkUsNaRyQm1hHOfM0PKxA==", + "dev": true, + "requires": { + "kleur": "^3.0.2", + "sisteransi": "^1.0.0" + } + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "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 + }, + "react-is": { + "version": "16.8.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz", + "integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, "readable-stream": { "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1740,10 +4401,125 @@ "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=", "dev": true }, - "reflect-metadata": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", - "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==", + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "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" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "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.0", + "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.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "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 + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "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-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve": { @@ -1755,6 +4531,33 @@ "path-parse": "^1.0.5" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "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 + }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -1780,40 +4583,444 @@ } } }, + "rsvp": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz", + "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA==", + "dev": true + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "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" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "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.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "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 + }, + "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.0", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", + "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "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 + } + } + }, + "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, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^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" + } + }, + "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" + } + } + } + }, + "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, + "requires": { + "kind-of": "^3.2.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" + } + } + } + }, "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-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==", + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "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 + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "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 + }, + "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, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "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, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "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" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "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, + "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" + } + } + } + }, + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "string_decoder": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -1832,98 +5039,129 @@ "ansi-regex": "^2.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "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 + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, - "tap-bark": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tap-bark/-/tap-bark-1.0.0.tgz", - "integrity": "sha1-bAPcUWh/7Xh3+COtSx3dHvXrVnQ=", - "dev": true, - "requires": { - "@types/node": ">=0.0.2", - "chalk": "^1.1.3", - "duplexer": "^0.1.1", - "tap-parser": "^3.0.3", - "through2": "^2.0.1" - } + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true }, - "tap-parser": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-3.0.5.tgz", - "integrity": "sha1-uUf2ngs+U9S5IBH2zFUuFtrcfsk=", + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", "dev": true, "requires": { - "events-to-array": "^1.0.1", - "js-yaml": "^3.2.7", - "readable-stream": "^2" + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" } }, - "teeny-request": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", - "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", - "dev": true, - "requires": { - "https-proxy-agent": "^2.2.1", - "node-fetch": "^2.2.0", - "uuid": "^3.3.2" - } + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true }, - "threads": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/threads/-/threads-0.12.0.tgz", - "integrity": "sha512-4B7hd61lDsVW1Z/+FAVX7D9QbiQYUbtGMHVkkwWT/nKPKas8u4FEc+Rg8E8h2erhNTQGNqNJ0TsholmhpKNPRg==", + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "eventemitter3": "^2.0.2", - "native-promise-only": "^0.8.1" + "os-tmpdir": "~1.0.2" } }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "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 + }, + "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, "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "kind-of": "^3.0.2" }, "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "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": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "is-buffer": "^1.1.5" } } } }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "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, "requires": { - "os-tmpdir": "~1.0.2" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, - "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 + "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" + } + }, + "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" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } }, "trim-right": { "version": "1.0.1", @@ -1931,6 +5169,40 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "ts-jest": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.0.tgz", + "integrity": "sha512-o8BO3TkMREpAATaFTrXkovMsCpBl2z4NDBoLJuWZcJJj1ijI49UnvDMfVpj+iogn/Jl8Pbhuei5nc/Ti+frEHw==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "json5": "2.x", + "make-error": "1.x", + "mkdirp": "0.x", + "resolve": "1.x", + "semver": "^5.5", + "yargs-parser": "10.x" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, "ts-node": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.0.tgz", @@ -2013,15 +5285,149 @@ "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=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "typescript": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.1.tgz", "integrity": "sha512-cTmIDFW7O0IHbn1DPYjkiebHxwtCMU+eTy30ZtJNBPF9j2O1ITu5XH2YnBeVRKWHqF+3JQwWJv0Q0aUgX8W7IA==" }, - "urlgrey": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", - "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=", + "uglify-js": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.1.tgz", + "integrity": "sha512-kI+3c+KphOAKIikQsZoT2oDsVYH5qvhpTtFObfMCdhPAYnjSvmW4oTWMhvDD4jtAGHJwztlBXQgozGcq3Xw9oQ==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true, + "optional": true + } + } + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "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" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "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, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "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 + } + } + }, + "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, + "requires": { + "punycode": "^2.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 }, "util-deprecate": { @@ -2030,24 +5436,214 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, + "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, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "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==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "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": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.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 + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "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 + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, "yn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", diff --git a/package.json b/package.json index 0ae952e43..cb6292246 100644 --- a/package.json +++ b/package.json @@ -19,34 +19,36 @@ "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", "build-lualib": "ts-node ./build_lualib.ts", - "pretest": "npm run clean && npm run style-check && npm run build && tsc -p ./test/tsconfig.json", - "test": "node ./test/runner.js", - "posttest": "npm run clean", - "coverage": "nyc --source-map=true npm test && nyc report --reporter=text-lcov > coverage.lcov", - "coverage-html": "nyc --source-map=true npm test && nyc report --reporter=html", - "test-threaded": "npm run pretest && node ./test/threaded_runner.js && npm run posttest", - "test-fast": "npm run pretest && node ./test/runner.js --ignoreDiagnostics && npm run posttest", - "clean": "rimraf \"src/**/*.js\" \"src/**/*.js.map\" \"test/**/*.js\" \"test/**/*.js.map\" \"test/compiler/testfiles/*.lua\"", - "release-patch": "npm version patch", - "release-minor": "npm version minor", + "test": "jest", + "test-fast": "cross-env JEST_IGNORE_DIAGNOSTICS=true jest", + "lint": "npm run lint:tslint && npm run lint:prettier", + "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", + "lint:tslint": "tslint -p . && tslint -p __tests__ && tslint src/lualib/*.ts", "release-major": "npm version major", + "release-minor": "npm version minor", + "release-patch": "npm version patch", "preversion": "npm run build && npm test", - "postversion": "git push && git push --tags", - "style-check": "tslint -p . && tslint -c ./tslint.json src/lualib/*.ts" + "postversion": "git push && git push --tags" }, "bin": { "tstl": "./dist/tstl.js" }, - "nyc": { - "all": true, - "extension": [ - ".ts" - ], - "include": [ - "src/**/*" - ], - "exclude": [ - "src/lualib/*" + "prettier": { + "endOfLine": "lf", + "printWidth": 100, + "proseWrap": "always", + "tabWidth": 4, + "trailingComma": "all", + "overrides": [ + { + "files": [ + "**/*.yml", + "**/.*.yml" + ], + "options": { + "tabWidth": 2 + } + } ] }, "engines": { @@ -57,16 +59,16 @@ }, "devDependencies": { "@types/glob": "^5.0.35", + "@types/jest": "^24.0.11", "@types/node": "^9.6.23", - "alsatian": "^2.3.0", - "codecov": "^3.2.0", - "deep-equal": "^1.0.1", + "cross-env": "^5.2.0", "fengari": "^0.1.2", - "flatted": "^2.0.0", "glob": "^7.1.2", - "nyc": "^13.3.0", + "jest": "^24.5.0", + "jest-circus": "^24.5.0", + "prettier": "^1.16.4", "rimraf": "^2.6.3", - "threads": "^0.12.0", + "ts-jest": "^24.0.0", "ts-node": "^7.0.0", "tslint": "^5.10.0" } diff --git a/src/Compiler.ts b/src/Compiler.ts index 0659ea527..a92f1279b 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -105,7 +105,7 @@ export function compileFilesWithOptions(fileNames: string[], options: CompilerOp transpiler.emitFilesAndReportErrors(); } -const libCache: {[key: string]: string} = {}; +const libCache: {[key: string]: ts.SourceFile} = {}; const defaultCompilerOptions: CompilerOptions = { luaLibImport: LuaLibImportKind.Require, @@ -122,7 +122,7 @@ export function createStringCompilerProgram( fileExists: (fileName): boolean => true, getCanonicalFileName: fileName => fileName, getCurrentDirectory: () => "", - getDefaultLibFileName: () => "lib.es6.d.ts", + getDefaultLibFileName: ts.getDefaultLibFileName, getDirectories: () => [], getNewLine: () => "\n", @@ -139,19 +139,17 @@ export function createStringCompilerProgram( } break; } - if (filename.indexOf(".d.ts") !== -1) { - if (!libCache[filename]) { - const typeScriptDir = path.dirname(require.resolve("typescript")); - const filePath = path.join(typeScriptDir, filename); - if (fs.existsSync(filePath)) { - libCache[filename] = fs.readFileSync(filePath).toString(); - } else { - const pathWithLibPrefix = path.join(typeScriptDir, "lib." + filename); - libCache[filename] = fs.readFileSync(pathWithLibPrefix).toString(); - } - } - return ts.createSourceFile(filename, libCache[filename], ts.ScriptTarget.Latest, false); + + if (filename.startsWith('lib.')) { + if (libCache[filename]) return libCache[filename]; + const typeScriptDir = path.dirname(require.resolve("typescript")); + const filePath = path.join(typeScriptDir, filename); + const content = fs.readFileSync(filePath, 'utf8'); + + libCache[filename] = ts.createSourceFile(filename, content, ts.ScriptTarget.Latest, false); + return libCache[filename]; } + return undefined; }, diff --git a/src/TranspileError.ts b/src/TranspileError.ts index c05b7a703..35ce051c3 100644 --- a/src/TranspileError.ts +++ b/src/TranspileError.ts @@ -1,9 +1,8 @@ import * as ts from "typescript"; export class TranspileError extends Error { - public node: ts.Node; - constructor(message: string, node: ts.Node) { + public name = 'TranspileError'; + constructor(message: string, public node?: ts.Node) { super(message); - this.node = node; } } diff --git a/test/compiler/errorreport.spec.ts b/test/compiler/errorreport.spec.ts index f5f9c8782..1c588ee04 100644 --- a/test/compiler/errorreport.spec.ts +++ b/test/compiler/errorreport.spec.ts @@ -1,42 +1,24 @@ -import { Any, Expect, Setup, SpyOn, Teardown, Test, TestCase } from "alsatian"; -import * as fs from "fs"; import * as path from "path"; -import * as ts from "typescript"; -import { compile, compileFilesWithOptions } from "../../src/Compiler"; - -export class CompilerErrorReportTests { - private originalStdErr: any; - private originalStdOut: any; - private originalProcessExit: any; - - @TestCase("Encountered error parsing file: Default Imports are not supported, please use named imports instead!\n", - "default_import.ts") - @Test("Compile project") - public compileProject(errorMsg: string, ...fileNames: string[]) { - fileNames = fileNames.map((file) => path.resolve(__dirname, "testfiles", file)); - compileFilesWithOptions(fileNames, {outDir: ".", rootDir: "."}); - - Expect(process.stderr.write).toHaveBeenCalledWith(errorMsg, Any); - - Expect(process.exit).toHaveBeenCalledWith(1); - } - - @Setup - private _spyProcess() { - this.originalProcessExit = process.exit; - this.originalStdOut = process.stdout.write; - this.originalStdErr = process.stderr.write; - - SpyOn(process, "exit").andStub(); - SpyOn(process.stderr, "write").andStub(); - SpyOn(process.stdout, "write").andStub(); - } - - @Teardown - private _resetProcess() { - process.exit = this.originalProcessExit; - process.stdout.write = this.originalStdOut; - process.stderr.write = this.originalStdErr; - } - -} +import { compileFilesWithOptions } from "../../src/Compiler"; + +test.each([ + { + errorMsg: + "Encountered error parsing file: Default Imports are not supported, please use named imports instead!", + fileName: "default_import.ts", + }, +])("Compile project (%p)", ({ errorMsg, fileName }) => { + jest.spyOn(console, "log").mockReturnValue(undefined); + const errorMock = jest.spyOn(console, "error").mockReturnValue(undefined); + const exitMock = jest.spyOn(process, "exit").mockReturnValue(undefined as never); + + fileName = path.resolve(__dirname, "testfiles", fileName); + compileFilesWithOptions([fileName], { outDir: ".", rootDir: ".", types: [] }); + + jest.restoreAllMocks(); + + expect(exitMock).toHaveBeenCalledWith(1); + expect(errorMock).toHaveBeenCalledTimes(2); + expect(errorMock).toHaveBeenNthCalledWith(1, errorMsg); + expect(errorMock).toHaveBeenNthCalledWith(2, expect.any(String)); +}); diff --git a/test/compiler/outfile.spec.ts b/test/compiler/outfile.spec.ts index 1b0fa7a44..03ca23d9d 100644 --- a/test/compiler/outfile.spec.ts +++ b/test/compiler/outfile.spec.ts @@ -1,47 +1,45 @@ -import { Expect, SetupFixture, Teardown, Test, TestCase } from "alsatian"; import * as fs from "fs"; import * as path from "path"; import { compile } from "../../src/Compiler"; -export class CompilerOutFileTests { - - private outFileRelPath: string; - private outFileAbsPath: string; - - @SetupFixture - public setupFixture() { - this.outFileRelPath = "./testfiles/out_file.script"; - this.outFileAbsPath = path.join(__dirname, this.outFileRelPath); - } - - @Test("Outfile absoulte path") - public outFileAbsTest() { - // Compile project - compile(["--outFile", this.outFileAbsPath, path.join(__dirname, "./testfiles/out_file.ts")]); - - Expect(fs.existsSync(this.outFileAbsPath)).toBe(true); - } - - @Test("Outfile relative path") - public outFileRelTest() { - // Compile project - compile([ - "--outDir", - __dirname, - "--outFile", - this.outFileRelPath, - path.join(__dirname, "./testfiles/out_file.ts"), - ]); - - Expect(fs.existsSync(this.outFileAbsPath)).toBe(true); - } - - @Teardown - public teardown() { - fs.unlink(this.outFileAbsPath, (err) => { - if (err) { - throw err; - } - }); - } -} +let outFileRelPath: string; +let outFileAbsPath: string; + +beforeAll(() => { + outFileRelPath = "./testfiles/out_file.script"; + outFileAbsPath = path.join(__dirname, outFileRelPath); +}); + +afterEach(() => { + fs.unlink(outFileAbsPath, err => { + if (err) { + throw err; + } + }); +}); + +test("Outfile absoulte path", () => { + compile([ + "--types", + "node", + "--outFile", + outFileAbsPath, + path.join(__dirname, "./testfiles/out_file.ts"), + ]); + + expect(fs.existsSync(outFileAbsPath)).toBe(true); +}); + +test("Outfile relative path", () => { + compile([ + "--types", + "node", + "--outDir", + __dirname, + "--outFile", + outFileRelPath, + path.join(__dirname, "./testfiles/out_file.ts"), + ]); + + expect(fs.existsSync(outFileAbsPath)).toBe(true); +}); diff --git a/test/compiler/project.spec.ts b/test/compiler/project.spec.ts index 329fa4083..c72c0041e 100644 --- a/test/compiler/project.spec.ts +++ b/test/compiler/project.spec.ts @@ -1,4 +1,3 @@ -import { Expect, Setup, Teardown, Test, TestCase } from "alsatian"; import * as fs from "fs"; import * as path from "path"; import { compile } from "../../src/Compiler"; @@ -7,88 +6,97 @@ import { compile } from "../../src/Compiler"; * Find all files inside a dir, recursively. */ function getAllFiles(dir: string): string[] { - return fs.readdirSync(dir).reduce( - (files, file) => { - const name = path.join(dir, file); - const isDirectory = fs.statSync(name).isDirectory(); - return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name]; - }, - [] - ); + return fs.readdirSync(dir).reduce((files, file) => { + const name = path.join(dir, file); + const isDirectory = fs.statSync(name).isDirectory(); + return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name]; + }, []); } -export class CompilerProjectTests { - - private existingFiles: string[]; - private filesAfterCompile: string[]; +let existingFiles: string[]; +let filesAfterCompile: string[]; - @TestCase("basic", - "tsconfig.json", - "lualib_bundle.lua", - "test_src/test_lib/file.lua", - "test_src/main.lua") - @TestCase("basic", - ".", - "lualib_bundle.lua", - "test_src/test_lib/file.lua", - "test_src/main.lua") - @TestCase("basic", - "test_src/main.ts", - "lualib_bundle.lua", - "test_src/test_lib/file.lua", - "test_src/main.lua") - @TestCase("basic", - "tsconfig.outDir.json", - "out_dir/lualib_bundle.lua", - "out_dir/test_src/test_lib/file.lua", - "out_dir/test_src/main.lua") - @TestCase("basic", - "tsconfig.rootDir.json", - "test_src/lualib_bundle.lua", - "test_src/test_lib/file.lua", - "test_src/main.lua") - @TestCase("basic", - "tsconfig.bothDirOptions.json", - "out_dir/lualib_bundle.lua", - "out_dir/test_lib/file.lua", - "out_dir/main.lua") - @TestCase("baseurl", - "tsconfig.json", - "out_dir/lualib_bundle.lua", - "out_dir/test_src/test_lib/nested/lib_file.lua", - "out_dir/test_src/main.lua") - @Test("Compile project") - public compileProject(projectName: string, tsconfig: string, ...expectedFiles: string[]) { - const relPathToProject = path.join("projects", projectName); +afterEach(() => { + // Remove files that were created by the test + const createdFiles = filesAfterCompile.filter(v => existingFiles.indexOf(v) < 0); + for (const file of createdFiles) { + fs.unlinkSync(file); + } + existingFiles = []; + filesAfterCompile = []; +}); - // Setup we cant do this in @setup because we need the projectname - this.existingFiles = getAllFiles(path.resolve(__dirname, relPathToProject)); - this.filesAfterCompile = []; - // Setup End +test.each([ + { + projectName: "basic", + tsconfig: "tsconfig.json", + expectedFiles: ["lualib_bundle.lua", "test_src/test_lib/file.lua", "test_src/main.lua"], + }, + { + projectName: "basic", + tsconfig: ".", + expectedFiles: ["lualib_bundle.lua", "test_src/test_lib/file.lua", "test_src/main.lua"], + }, + { + projectName: "basic", + tsconfig: "test_src/main.ts", + expectedFiles: ["lualib_bundle.lua", "test_src/test_lib/file.lua", "test_src/main.lua"], + }, + { + projectName: "basic", + tsconfig: "tsconfig.outDir.json", + expectedFiles: [ + "out_dir/lualib_bundle.lua", + "out_dir/test_src/test_lib/file.lua", + "out_dir/test_src/main.lua", + ], + }, + { + projectName: "basic", + tsconfig: "tsconfig.rootDir.json", + expectedFiles: [ + "test_src/lualib_bundle.lua", + "test_src/test_lib/file.lua", + "test_src/main.lua", + ], + }, + { + projectName: "basic", + tsconfig: "tsconfig.bothDirOptions.json", + expectedFiles: [ + "out_dir/lualib_bundle.lua", + "out_dir/test_lib/file.lua", + "out_dir/main.lua", + ], + }, + { + projectName: "baseurl", + tsconfig: "tsconfig.json", + expectedFiles: [ + "out_dir/lualib_bundle.lua", + "out_dir/test_src/test_lib/nested/lib_file.lua", + "out_dir/test_src/main.lua", + ], + }, +])("Compile project (%p)", ({ projectName, tsconfig, expectedFiles }) => { + const relPathToProject = path.join("projects", projectName); - const tsconfigPath = path.resolve(__dirname, relPathToProject, tsconfig); + // Setup we cant do this in beforeEach because we need the projectname + existingFiles = getAllFiles(path.resolve(__dirname, relPathToProject)); + filesAfterCompile = []; + // Setup End - // Compile project - compile(["-p", tsconfigPath]); + const tsconfigPath = path.resolve(__dirname, relPathToProject, tsconfig); - this.filesAfterCompile = getAllFiles(path.resolve(__dirname, relPathToProject)); - expectedFiles = expectedFiles.map(relPath => path.resolve(__dirname, relPathToProject, relPath)); - expectedFiles.push(...this.existingFiles); + compile(["-p", tsconfigPath]); - for (const existingFile of this.filesAfterCompile) { - Expect(expectedFiles).toContain(existingFile); - } - } + filesAfterCompile = getAllFiles(path.resolve(__dirname, relPathToProject)); + expectedFiles = expectedFiles.map(relPath => + path.resolve(__dirname, relPathToProject, relPath), + ); + expectedFiles.push(...existingFiles); - @Teardown - public teardown() { - // Remove files that were created by the test - const createdFiles = this.filesAfterCompile.filter(v => this.existingFiles.indexOf(v) < 0); - for (const file of createdFiles) { - fs.unlinkSync(file); - } - this.existingFiles = []; - this.filesAfterCompile = []; + for (const existingFile of filesAfterCompile) { + expect(expectedFiles).toContain(existingFile); } - -} +}); diff --git a/test/compiler/projects/baseurl/tsconfig.json b/test/compiler/projects/baseurl/tsconfig.json index 69a82043b..8a0c35a68 100644 --- a/test/compiler/projects/baseurl/tsconfig.json +++ b/test/compiler/projects/baseurl/tsconfig.json @@ -4,5 +4,6 @@ "outDir": "./out_dir", "rootDir": ".", "baseUrl": "./test_src/test_lib", + "types": [] } } diff --git a/test/compiler/projects/basic/test_src/test_lib/file.ts b/test/compiler/projects/basic/test_src/test_lib/file.ts old mode 100755 new mode 100644 index d764cbd99..4ac2b8fe0 --- a/test/compiler/projects/basic/test_src/test_lib/file.ts +++ b/test/compiler/projects/basic/test_src/test_lib/file.ts @@ -1 +1 @@ -const test = true; +const foo = true; diff --git a/test/compiler/projects/basic/tsconfig.bothDirOptions.json b/test/compiler/projects/basic/tsconfig.bothDirOptions.json old mode 100755 new mode 100644 diff --git a/test/compiler/projects/basic/tsconfig.json b/test/compiler/projects/basic/tsconfig.json old mode 100755 new mode 100644 index e5a835e99..40e0fb248 --- a/test/compiler/projects/basic/tsconfig.json +++ b/test/compiler/projects/basic/tsconfig.json @@ -1,3 +1,6 @@ { - "luaTarget": "JIT" + "luaTarget": "JIT", + "compilerOptions": { + "types": [] + } } diff --git a/test/compiler/projects/basic/tsconfig.outDir.json b/test/compiler/projects/basic/tsconfig.outDir.json old mode 100755 new mode 100644 diff --git a/test/compiler/projects/basic/tsconfig.rootDir.json b/test/compiler/projects/basic/tsconfig.rootDir.json old mode 100755 new mode 100644 diff --git a/test/compiler/projects/watchmode/tsconfig.json b/test/compiler/projects/watchmode/tsconfig.json index e5a835e99..40e0fb248 100644 --- a/test/compiler/projects/watchmode/tsconfig.json +++ b/test/compiler/projects/watchmode/tsconfig.json @@ -1,3 +1,6 @@ { - "luaTarget": "JIT" + "luaTarget": "JIT", + "compilerOptions": { + "types": [] + } } diff --git a/test/compiler/projects/watchmode/watch.ts b/test/compiler/projects/watchmode/watch.ts index 4e2a15260..fa2edc21a 100644 --- a/test/compiler/projects/watchmode/watch.ts +++ b/test/compiler/projects/watchmode/watch.ts @@ -1 +1 @@ -class MyTest {} \ No newline at end of file +class MyTest {} diff --git a/test/compiler/testfiles/out_file.ts b/test/compiler/testfiles/out_file.ts index 45842c5e2..ef22a69f1 100644 --- a/test/compiler/testfiles/out_file.ts +++ b/test/compiler/testfiles/out_file.ts @@ -1,3 +1 @@ -class Test { - -} +class Test {} diff --git a/test/compiler/testfiles/watch.ts b/test/compiler/testfiles/watch.ts index 4e2a15260..fa2edc21a 100644 --- a/test/compiler/testfiles/watch.ts +++ b/test/compiler/testfiles/watch.ts @@ -1 +1 @@ -class MyTest {} \ No newline at end of file +class MyTest {} diff --git a/test/compiler/watcher_proccess.js b/test/compiler/watcher_proccess.js new file mode 100644 index 000000000..1f1336618 --- /dev/null +++ b/test/compiler/watcher_proccess.js @@ -0,0 +1,6 @@ +require("ts-node/register/transpile-only"); +const { compile } = require("../../src/Compiler"); + +process.on("message", args => { + compile(args); +}); diff --git a/test/compiler/watcher_proccess.ts b/test/compiler/watcher_proccess.ts deleted file mode 100644 index 25b4bd344..000000000 --- a/test/compiler/watcher_proccess.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { compile } from "../../src/Compiler"; - -process.on("message", args => { - compile(args); -}); diff --git a/test/compiler/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index 7b838316b..899f2dcea 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -1,68 +1,65 @@ -import { AsyncTest, Expect, Setup, TestCase, Timeout } from "alsatian"; import { fork } from "child_process"; import * as fs from "fs"; import * as path from "path"; -export class CompilerWatchModeTest { +let testsCleanup: Array<() => void> = []; +afterEach(() => { + testsCleanup.forEach(x => x()); + testsCleanup = []; +}); - @TestCase(["-w", path.join(__dirname, "./testfiles/watch.ts")], - path.join(__dirname, "./testfiles/watch.ts")) - @TestCase(["-w", "-p", path.join(__dirname, "./projects/watchmode/")], - path.join(__dirname, "./projects/watchmode/watch.ts")) - @AsyncTest("Watch single File") - @Timeout(16000) - public async testSingle(args: string[], fileToChange: string): Promise { - fileToChange = fileToChange; - const fileToChangeOut = fileToChange.replace(".ts", ".lua"); - - const child = fork(path.join(__dirname, "watcher_proccess.js")); - child.send(args); - - await this.waitForFileExists(fileToChangeOut, 9000) - .catch(err => console.error(err)); +function waitForFileExists(filePath: string): Promise { + return new Promise(resolve => { + const intervalTimerId = setInterval(() => { + if (fs.existsSync(filePath)) { + clearInterval(intervalTimerId); + resolve(); + } + }, 100); - Expect(fs.existsSync(fileToChangeOut)).toBe(true); + testsCleanup.push(() => clearInterval(intervalTimerId)); + }); +} - const initialResultLua = fs.readFileSync(fileToChangeOut); +test.each([ + { + args: ["-w", "--types", "node", path.join(__dirname, "./testfiles/watch.ts")], + fileToChange: path.join(__dirname, "./testfiles/watch.ts"), + }, + { + args: ["-w", "-p", path.join(__dirname, "./projects/watchmode/")], + fileToChange: path.join(__dirname, "./projects/watchmode/watch.ts"), + }, +])( + "Watch single File (%p)", + async ({ args, fileToChange }) => { + const fileToChangeOut = fileToChange.replace(".ts", ".lua"); const originalTS = fs.readFileSync(fileToChange); - fs.unlinkSync(fileToChangeOut); - - fs.writeFileSync(fileToChange, "class MyTest2 {}"); - - await this.waitForFileExists(fileToChangeOut, 5000) - .catch(err => console.error(err)); + const child = fork(path.join(__dirname, "watcher_proccess.js"), [], { silent: true }); - const updatedResultLua = fs.readFileSync(fileToChangeOut).toString(); + testsCleanup.push(() => { + try { + fs.unlinkSync(fileToChangeOut); + } catch (err) { + if (err.code !== "ENOENT") throw err; + } + fs.writeFileSync(fileToChange, originalTS); + child.kill(); + }); - Expect(initialResultLua).not.toEqual(updatedResultLua); + child.send(args); - fs.writeFileSync(fileToChange, originalTS); + await waitForFileExists(fileToChangeOut); + const initialResultLua = fs.readFileSync(fileToChangeOut, "utf8"); fs.unlinkSync(fileToChangeOut); + fs.writeFileSync(fileToChange, "class MyTest2 {}"); - child.kill(); - } - - private waitForFileExists(filepath: string, timeout: number = 3000): Promise { - const interval = 200; - return new Promise((resolve, reject) => { - const intervalTimerId = setInterval( - () => { - if (fs.existsSync(filepath)) { - clearTimeout(timeoutId); - clearInterval(intervalTimerId); - resolve(); - } - }, - interval); + await waitForFileExists(fileToChangeOut); + const updatedResultLua = fs.readFileSync(fileToChangeOut, "utf8"); - const timeoutId = setTimeout( - () => { - clearInterval(intervalTimerId); - reject(new Error("Wating for file timed out!")); - }, - timeout); - }); - } -} + expect(initialResultLua).not.toEqual(updatedResultLua); + }, + 10000, +); diff --git a/test/src/json.lua b/test/json.lua similarity index 100% rename from test/src/json.lua rename to test/json.lua diff --git a/test/runner.ts b/test/runner.ts deleted file mode 100644 index b2dfbbf2b..000000000 --- a/test/runner.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { TestOutcome, TestRunner, TestSet } from "alsatian"; - -import * as fs from "fs"; -import * as path from "path"; - -// create test set -const testSet = TestSet.create(); - -// add your tests -testSet.addTestsFromFiles("./test/**/*.spec.js"); - -// create a test runner -const testRunner = new TestRunner(); - -// Copy lualib to project root -fs.copyFileSync( - path.resolve(__dirname, "../dist/lualib/lualib_bundle.lua"), - "lualib_bundle.lua" -); - -// setup the output -testRunner.outputStream - // pipe to the console - .pipe(process.stdout); - -let success = 0; -let ignored = 0; -let run = 0; -testRunner.onTestComplete(test => { - run++; - - if (test.outcome === TestOutcome.Pass) { - success++; - } else if (test.outcome === TestOutcome.Skip) { - ignored++; - } -}); - -// run the test set -testRunner.run(testSet) - // this will be called after all tests have been run - .then(result => { - // Remove lualib bundle again - fs.unlinkSync("lualib_bundle.lua"); - - const nonIgnoredTests = run - ignored; - const failedTests = nonIgnoredTests - success; - console.log(`Ignored ${ignored}/${run} tests.`); - console.log(`Failed ${failedTests}/${nonIgnoredTests} tests.`); - console.log(`Passed ${success}/${nonIgnoredTests} tests.`); - - if (failedTests > 0) { - process.exit(1); - } - }) - // this will be called if there was a problem - .catch(error => { - // Remove lualib bundle again - fs.unlinkSync("lualib_bundle.lua"); - - console.error(error); - process.exit(1); - }); diff --git a/test/test_thread.ts b/test/test_thread.ts deleted file mode 100644 index d9404d609..000000000 --- a/test/test_thread.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MatchError, TestRunner, TestSet, TestOutcome } from "alsatian"; -import * as flatted from "flatted"; - -module.exports = (input, done) => { - const testSet = TestSet.create(); - testSet.addTestsFromFiles(input.files); - const testRunner = new TestRunner(); - - let testCount = 0; - let failedTestCount = 0; - - testRunner.onTestComplete(result => { - if (result.outcome === TestOutcome.Fail) { - if (result.error instanceof MatchError) { - console.log(`Test ${result.testFixture.description}, ${result.test.key}(${flatted.stringify(result.testCase.caseArguments)}) Failed!`); - console.log(" ---\n" + - ' message: "' + - result.error.message + - '"\n' + - " severity: fail\n" + - " data:\n" + - " got: " + - result.error.actual + - "\n" + - " expect: " + - result.error.expected + - "\n"); - } - failedTestCount++; - } - testCount++; - }); - - testRunner.run(testSet) - .then(() => done(testCount, failedTestCount)); -}; diff --git a/test/threaded_runner.ts b/test/threaded_runner.ts deleted file mode 100644 index ba8f42000..000000000 --- a/test/threaded_runner.ts +++ /dev/null @@ -1,83 +0,0 @@ -import {MatchError} from "alsatian"; -import * as glob from "glob"; -import * as os from "os"; -import * as path from "path"; -import {config, Pool} from "threads"; - -function fileArrToString(fileArr: string[]): string { - return fileArr.map(val => path.basename(val).replace(".spec.js", "")).join(", "); -} - -function printTestStats(testCount: number, failedTestCount: number, header: string, footer: string): void { - console.log("-----------------"); - console.log(header); - console.log(`Total: ${testCount}`); - console.log(`Passed: ${testCount - failedTestCount}`); - console.log(`Failed: ${failedTestCount}`); - console.log(footer); - console.log("-----------------"); -} - -config.set({ - basepath: { - node: __dirname, - } -}); - -let cpuCount = os.cpus().length + 1; -if ("TRAVIS" in process.env && "CI" in process.env) { - // fixed thread count for CI - cpuCount = 8; -} -const testFiles: string[] = glob.sync("./test/**/*.spec.js"); -const pool = new Pool(cpuCount); -let jobCounter = 0; -const testStartTime = new Date(); -const fileCount = testFiles.length; -let exitWithError = false; -let totalTestCount = 0; -let totalFailedTestCount = 0; - -console.log( - `Running tests: ${fileArrToString(testFiles)} with ${cpuCount} threads`); - -testFiles.forEach(file => { - pool.run("./test_thread") - .send({files: [file]}) - .on("done", - (testCount, failedTestCount) => { - if (failedTestCount !== 0) { - exitWithError = true; - } - totalTestCount += testCount; - totalFailedTestCount += failedTestCount; - jobCounter++; - printTestStats( - testCount, - failedTestCount, - `Tests ${file} results:`, - `Thread: ${jobCounter}/${fileCount} done.`); - }) - .on("error", error => { - console.log("Fatal non test related Exception in test file:", file, error); - }); -}); - -pool.on("finished", () => { - let footer = "All tests passed!"; - if (exitWithError) { - footer = "Exiting with Error: One or more tests failed!"; - } - printTestStats(totalTestCount, totalFailedTestCount, "Final Results:", footer); - - console.log("Everything done, shutting down the thread pool."); - const timeInMs = (new Date().valueOf() - testStartTime.valueOf()); - console.log(`Tests took: ${Math.floor(timeInMs / 1000 / 60)}:${Math.floor(timeInMs / 1000) % 60}`); - - pool.killAll(); - - if (exitWithError) { - process.exit(1); - } -}); - diff --git a/test/translation/builder.spec.ts b/test/translation/builder.spec.ts index f667a6fd0..81a9fa3d1 100644 --- a/test/translation/builder.spec.ts +++ b/test/translation/builder.spec.ts @@ -1,12 +1,10 @@ -import { Expect, Test, TestCases } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; import * as fs from "fs"; import * as path from "path"; -const files: string[][] = []; -const fileContents: {[key: string]: Buffer} = {}; +const files: Array<{ ts: string; lua: string }> = []; +const fileContents: { [key: string]: Buffer } = {}; const tsPath = path.join(__dirname, "./ts/"); const luaPath = path.join(__dirname, "./lua/"); @@ -14,36 +12,33 @@ const luaPath = path.join(__dirname, "./lua/"); const tsFiles = fs.readdirSync(tsPath); const luaFiles = fs.readdirSync(luaPath); -tsFiles.forEach( - (tsFile, i) => { - // ignore non ts files - if (path.extname(tsFile) !== ".ts") { - return; - } - const luaPart = luaFiles.indexOf(tsFile.replace(".ts", ".lua")); - if (luaPart === -1) { - throw new Error("Missing lua counter part for test file: " + tsFile); - } - const luaFile = luaFiles[luaPart]; - const luaFileAbsolute = path.join(luaPath, luaFile); - const tsFileAbsolute = path.join(tsPath, tsFile); - files.push([tsFile, luaFile]); - fileContents[tsFile] = fs.readFileSync(tsFileAbsolute); - fileContents[luaFile] = fs.readFileSync(luaFileAbsolute); +tsFiles.forEach((tsFile, i) => { + // ignore non ts files + if (path.extname(tsFile) !== ".ts") { + return; + } + const luaPart = luaFiles.indexOf(tsFile.replace(".ts", ".lua")); + if (luaPart === -1) { + throw new Error("Missing lua counter part for test file: " + tsFile); } -); + const luaFile = luaFiles[luaPart]; + const luaFileAbsolute = path.join(luaPath, luaFile); + const tsFileAbsolute = path.join(tsPath, tsFile); + files.push({ ts: tsFile, lua: luaFile }); + fileContents[tsFile] = fs.readFileSync(tsFileAbsolute); + fileContents[luaFile] = fs.readFileSync(luaFileAbsolute); +}); function BufferToTestString(b: Buffer): string { - return b.toString().trim().split("\r\n").join("\n"); + return b + .toString() + .trim() + .split("\r\n") + .join("\n"); } -export class FileTests { - - @TestCases(files) - @Test("Transformation Tests") - public transformationTests(tsFile: string, luaFile: string) { - Expect(util.transpileString(BufferToTestString(fileContents[tsFile]))) - .toEqual(BufferToTestString(fileContents[luaFile])); - } - -} +test.each(files)("Transformation Tests (%p)", ({ ts, lua }) => { + expect(util.transpileString(BufferToTestString(fileContents[ts]))).toEqual( + BufferToTestString(fileContents[lua]), + ); +}); diff --git a/test/translation/lua/modulesChangedVariableExport.lua b/test/translation/lua/modulesChangedVariableExport.lua index aa02323b6..f55befe6d 100644 --- a/test/translation/lua/modulesChangedVariableExport.lua +++ b/test/translation/lua/modulesChangedVariableExport.lua @@ -1,3 +1,3 @@ local exports = exports or {}; -exports.test = 1; +exports.foo = 1; return exports; diff --git a/test/translation/lua/modulesVariableExport.lua b/test/translation/lua/modulesVariableExport.lua index 76c98810f..dd07ed7b8 100644 --- a/test/translation/lua/modulesVariableExport.lua +++ b/test/translation/lua/modulesVariableExport.lua @@ -1,3 +1,3 @@ local exports = exports or {}; -exports.test = "test"; +exports.foo = "bar"; return exports; diff --git a/test/translation/lua/modulesVariableNoExport.lua b/test/translation/lua/modulesVariableNoExport.lua index f20c4efeb..fe16f36dc 100644 --- a/test/translation/lua/modulesVariableNoExport.lua +++ b/test/translation/lua/modulesVariableNoExport.lua @@ -1 +1 @@ -local test = "test"; +local foo = "bar"; diff --git a/test/translation/ts/callNamespace.ts b/test/translation/ts/callNamespace.ts index e87b7b751..43ed32d6d 100644 --- a/test/translation/ts/callNamespace.ts +++ b/test/translation/ts/callNamespace.ts @@ -1,4 +1,4 @@ declare namespace Namespace { function myFunction(); } -Namespace.myFunction(); \ No newline at end of file +Namespace.myFunction(); diff --git a/test/translation/ts/characterEscapeSequence.ts b/test/translation/ts/characterEscapeSequence.ts index e3ec0b741..c5ac3a568 100644 --- a/test/translation/ts/characterEscapeSequence.ts +++ b/test/translation/ts/characterEscapeSequence.ts @@ -2,15 +2,15 @@ let quoteInDoubleQuotes = "' ' '"; let quoteInTemplateString = `' ' '`; let doubleQuoteInQuotes = '" " "'; -let doubleQuoteInDoubleQuotes = "\" \" \""; +let doubleQuoteInDoubleQuotes = '" " "'; let doubleQuoteInTemplateString = `" " "`; -let backQuoteInQuotes = '` ` `'; +let backQuoteInQuotes = "` ` `"; let backQuoteInDoubleQuotes = "` ` `"; let backQuoteInTemplateString = `\` \` \``; -let escapedCharsInQuotes = '\\ \0 \b \t \n \v \f \" \' \`'; -let escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" \'"; +let escapedCharsInQuotes = "\\ \0 \b \t \n \v \f \" ' `"; +let escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" '"; let escapedCharsInTemplateString = `\\ \0 \b \t \n \v \f \" \' \``; -let nonEmptyTemplateString = `Level 0: \n\t ${`Level 1: \n\t\t ${`Level 3: \n\t\t\t ${'Last level \n --'} \n --`} \n --`} \n --`; +let nonEmptyTemplateString = `Level 0: \n\t ${`Level 1: \n\t\t ${`Level 3: \n\t\t\t ${"Last level \n --"} \n --`} \n --`} \n --`; diff --git a/test/translation/ts/classExtension2.ts b/test/translation/ts/classExtension2.ts index 158f16422..11145e9d5 100644 --- a/test/translation/ts/classExtension2.ts +++ b/test/translation/ts/classExtension2.ts @@ -1,6 +1,5 @@ /** @extension */ -class TestClass { -} +class TestClass {} /** @extension */ class MyClass extends TestClass { diff --git a/test/translation/ts/classPureAbstract.ts b/test/translation/ts/classPureAbstract.ts index 178c23b59..d9a661160 100644 --- a/test/translation/ts/classPureAbstract.ts +++ b/test/translation/ts/classPureAbstract.ts @@ -1,3 +1,3 @@ /** @pureAbstract */ declare class ClassA {} -class ClassB extends ClassA {} \ No newline at end of file +class ClassB extends ClassA {} diff --git a/test/translation/ts/do.ts b/test/translation/ts/do.ts index 62b1c0a65..c17e3d1aa 100644 --- a/test/translation/ts/do.ts +++ b/test/translation/ts/do.ts @@ -1,4 +1,4 @@ -let e = 10 +let e = 10; do { - e--; -} while (e > 0) + e--; +} while (e > 0); diff --git a/test/translation/ts/enum.ts b/test/translation/ts/enum.ts index a59f7ac76..3d48fbcfb 100644 --- a/test/translation/ts/enum.ts +++ b/test/translation/ts/enum.ts @@ -1,5 +1,5 @@ enum TestEnum { val1 = 0, val2 = 2, - val3 -} \ No newline at end of file + val3, +} diff --git a/test/translation/ts/enumHeterogeneous.ts b/test/translation/ts/enumHeterogeneous.ts index a047d66fe..d4e69f10b 100644 --- a/test/translation/ts/enumHeterogeneous.ts +++ b/test/translation/ts/enumHeterogeneous.ts @@ -1,5 +1,5 @@ enum TestEnum { - val1, - val2 = 3, - val3 = "baz", + val1, + val2 = 3, + val3 = "baz", } diff --git a/test/translation/ts/enumString.ts b/test/translation/ts/enumString.ts index 8ab7e30d1..3d7d29747 100644 --- a/test/translation/ts/enumString.ts +++ b/test/translation/ts/enumString.ts @@ -1,5 +1,5 @@ enum TestEnum { - val1 = "foo", - val2 = "bar", - val3 = "baz", + val1 = "foo", + val2 = "bar", + val3 = "baz", } diff --git a/test/translation/ts/exportStatement.ts b/test/translation/ts/exportStatement.ts index 524be0bd9..7aa965422 100644 --- a/test/translation/ts/exportStatement.ts +++ b/test/translation/ts/exportStatement.ts @@ -1,6 +1,6 @@ const xyz = 4; -export {xyz}; -export {xyz as uwv}; +export { xyz }; +export { xyz as uwv }; export * from "xyz"; -export {abc, def} from "xyz"; -export {abc as def} from "xyz"; +export { abc, def } from "xyz"; +export { abc as def } from "xyz"; diff --git a/test/translation/ts/for.ts b/test/translation/ts/for.ts index 02d8156e2..a9dd48620 100644 --- a/test/translation/ts/for.ts +++ b/test/translation/ts/for.ts @@ -1,2 +1 @@ -for (let i = 1; i <= 100; i++) { -} +for (let i = 1; i <= 100; i++) {} diff --git a/test/translation/ts/forIn.ts b/test/translation/ts/forIn.ts index 55e50cce7..8d1bff356 100644 --- a/test/translation/ts/forIn.ts +++ b/test/translation/ts/forIn.ts @@ -1,7 +1,7 @@ for (let i in { - a: 1, - b: 2, - c: 3, - d: 4 + a: 1, + b: 2, + c: 3, + d: 4, }) { } diff --git a/test/translation/ts/getSetAccessors.ts b/test/translation/ts/getSetAccessors.ts index b721f0f0b..d61f592a2 100644 --- a/test/translation/ts/getSetAccessors.ts +++ b/test/translation/ts/getSetAccessors.ts @@ -4,11 +4,11 @@ class MyClass { return this._field + 4; } public set field(v: number) { - this._field = v*2; + this._field = v * 2; } } let instance = new MyClass(); instance.field = 4; const b = instance.field; -const c = (4 + instance.field)*3; +const c = (4 + instance.field) * 3; diff --git a/test/translation/ts/modulesChangedVariableExport.ts b/test/translation/ts/modulesChangedVariableExport.ts index 6386d1b78..009c4cd06 100644 --- a/test/translation/ts/modulesChangedVariableExport.ts +++ b/test/translation/ts/modulesChangedVariableExport.ts @@ -1,2 +1,2 @@ -export let test; -test = 1; +export let foo; +foo = 1; diff --git a/test/translation/ts/modulesImportAll.ts b/test/translation/ts/modulesImportAll.ts index 1ffb29e95..b452afb73 100644 --- a/test/translation/ts/modulesImportAll.ts +++ b/test/translation/ts/modulesImportAll.ts @@ -1 +1 @@ -import * as Test from "test" +import * as Test from "test"; diff --git a/test/translation/ts/modulesImportNamed.ts b/test/translation/ts/modulesImportNamed.ts index 14ba1ec8d..b4c16e54b 100644 --- a/test/translation/ts/modulesImportNamed.ts +++ b/test/translation/ts/modulesImportNamed.ts @@ -1 +1 @@ -import {TestClass} from "test" +import { TestClass } from "test"; diff --git a/test/translation/ts/modulesImportNamedSpecialChars.ts b/test/translation/ts/modulesImportNamedSpecialChars.ts index cff06e7c0..7237d70a2 100644 --- a/test/translation/ts/modulesImportNamedSpecialChars.ts +++ b/test/translation/ts/modulesImportNamedSpecialChars.ts @@ -1,5 +1,5 @@ -import {TestClass} from "kebab-module" -import {TestClass} from "dollar$module" -import {TestClass} from "singlequote'module" -import {TestClass} from "hash#module" -import {TestClass} from "space module" +import { TestClass } from "kebab-module"; +import { TestClass } from "dollar$module"; +import { TestClass } from "singlequote'module"; +import { TestClass } from "hash#module"; +import { TestClass } from "space module"; diff --git a/test/translation/ts/modulesImportRenamed.ts b/test/translation/ts/modulesImportRenamed.ts index bc19b6b8b..42129a291 100644 --- a/test/translation/ts/modulesImportRenamed.ts +++ b/test/translation/ts/modulesImportRenamed.ts @@ -1 +1 @@ -import {TestClass as RenamedClass} from "test" +import { TestClass as RenamedClass } from "test"; diff --git a/test/translation/ts/modulesImportRenamedSpecialChars.ts b/test/translation/ts/modulesImportRenamedSpecialChars.ts index 10cc4b0cc..59e7ed862 100644 --- a/test/translation/ts/modulesImportRenamedSpecialChars.ts +++ b/test/translation/ts/modulesImportRenamedSpecialChars.ts @@ -1,5 +1,5 @@ -import {TestClass as RenamedClass} from "kebab-module" -import {TestClass as RenamedClass} from "dollar$module" -import {TestClass as RenamedClass} from "singlequote'module" -import {TestClass as RenamedClass} from "hash#module" -import {TestClass as RenamedClass} from "space module" +import { TestClass as RenamedClass } from "kebab-module"; +import { TestClass as RenamedClass } from "dollar$module"; +import { TestClass as RenamedClass } from "singlequote'module"; +import { TestClass as RenamedClass } from "hash#module"; +import { TestClass as RenamedClass } from "space module"; diff --git a/test/translation/ts/modulesNamespaceExportEnum.ts b/test/translation/ts/modulesNamespaceExportEnum.ts index dd40d81cb..0c85b6872 100644 --- a/test/translation/ts/modulesNamespaceExportEnum.ts +++ b/test/translation/ts/modulesNamespaceExportEnum.ts @@ -1,6 +1,6 @@ export namespace test { - export enum TestEnum { - foo = "foo", - bar = "bar", - } + export enum TestEnum { + foo = "foo", + bar = "bar", + } } diff --git a/test/translation/ts/modulesVariableExport.ts b/test/translation/ts/modulesVariableExport.ts index 13f4d5b45..d407b0602 100644 --- a/test/translation/ts/modulesVariableExport.ts +++ b/test/translation/ts/modulesVariableExport.ts @@ -1 +1 @@ -export const test = "test" +export const foo = "bar"; diff --git a/test/translation/ts/modulesVariableNoExport.ts b/test/translation/ts/modulesVariableNoExport.ts index 858f3dd7c..4f4b4c843 100644 --- a/test/translation/ts/modulesVariableNoExport.ts +++ b/test/translation/ts/modulesVariableNoExport.ts @@ -1 +1 @@ -const test = "test" +const foo = "bar"; diff --git a/test/translation/ts/namespace.ts b/test/translation/ts/namespace.ts index d9ae73274..24f4a78e0 100644 --- a/test/translation/ts/namespace.ts +++ b/test/translation/ts/namespace.ts @@ -1,3 +1,3 @@ namespace myNamespace { function nsMember() {} -} \ No newline at end of file +} diff --git a/test/translation/ts/namespacePhantom.ts b/test/translation/ts/namespacePhantom.ts index c99b88e8d..2f003c28e 100644 --- a/test/translation/ts/namespacePhantom.ts +++ b/test/translation/ts/namespacePhantom.ts @@ -1,4 +1,4 @@ /** @phantom */ namespace myNamespace { function nsMember() {} -} \ No newline at end of file +} diff --git a/test/translation/ts/tupleReturn.ts b/test/translation/ts/tupleReturn.ts index 0d2936071..75b7fbf01 100644 --- a/test/translation/ts/tupleReturn.ts +++ b/test/translation/ts/tupleReturn.ts @@ -1,34 +1,34 @@ -/** @tupleReturn */ -function tupleReturn(): [number, string] { - return [0, "foobar"]; -} -declare function noTupleReturn(): [number, string]; -declare function foo(a: [number, string]): void; -tupleReturn(); -noTupleReturn(); -let [a, b] = tupleReturn(); -let [c, d] = noTupleReturn(); -[a, b] = tupleReturn(); -[c, d] = noTupleReturn(); -let e = tupleReturn(); -let f = noTupleReturn(); -e = tupleReturn(); -f = noTupleReturn(); -foo(tupleReturn()); -foo(noTupleReturn()); -/** @tupleReturn */ -function tupleReturnFromVar(): [number, string] { - const r: [number, string] = [1, "baz"]; - return r; -} -/** @tupleReturn */ -function tupleReturnForward(): [number, string] { - return tupleReturn(); -} -function tupleNoForward(): [number, string] { - return tupleReturn(); -} -/** @tupleReturn */ -function tupleReturnUnpack(): [number, string] { - return tupleNoForward(); -} +/** @tupleReturn */ +function tupleReturn(): [number, string] { + return [0, "foobar"]; +} +declare function noTupleReturn(): [number, string]; +declare function foo(a: [number, string]): void; +tupleReturn(); +noTupleReturn(); +let [a, b] = tupleReturn(); +let [c, d] = noTupleReturn(); +[a, b] = tupleReturn(); +[c, d] = noTupleReturn(); +let e = tupleReturn(); +let f = noTupleReturn(); +e = tupleReturn(); +f = noTupleReturn(); +foo(tupleReturn()); +foo(noTupleReturn()); +/** @tupleReturn */ +function tupleReturnFromVar(): [number, string] { + const r: [number, string] = [1, "baz"]; + return r; +} +/** @tupleReturn */ +function tupleReturnForward(): [number, string] { + return tupleReturn(); +} +function tupleNoForward(): [number, string] { + return tupleReturn(); +} +/** @tupleReturn */ +function tupleReturnUnpack(): [number, string] { + return tupleNoForward(); +} diff --git a/test/translation/ts/typeAssert.ts b/test/translation/ts/typeAssert.ts index 95c751a36..4b654d851 100644 --- a/test/translation/ts/typeAssert.ts +++ b/test/translation/ts/typeAssert.ts @@ -1,2 +1,2 @@ -const test1 = 10; +const test1 = 10; const test2 = 10 as number; diff --git a/test/translation/ts/while.ts b/test/translation/ts/while.ts index 6101bd4f2..4014a4add 100644 --- a/test/translation/ts/while.ts +++ b/test/translation/ts/while.ts @@ -1,4 +1,4 @@ let d = 10; while (d > 0) { - d--; + d--; } diff --git a/test/tsconfig.json b/test/tsconfig.json index 7eb5d7f53..0c62d9606 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,13 +1,10 @@ { "compilerOptions": { - "experimentalDecorators": true, - "sourceMap": true, "target": "es2017", + "types": ["node", "jest"], + + "noEmit": true, "module": "commonjs" }, - "exclude": [ - "translation/ts/*", - "compiler/projects/*", - "compiler/testfiles/*" - ] + "exclude": ["translation/ts", "compiler/projects", "compiler/testfiles"] } diff --git a/test/tslint.json b/test/tslint.json new file mode 100644 index 000000000..e8bb9a2cf --- /dev/null +++ b/test/tslint.json @@ -0,0 +1,59 @@ +{ + "rules": { + "array-type": [true, "array-simple"], + "arrow-return-shorthand": true, + "ban": [ + true, + { "name": "parseInt", "message": "tsstyle#type-coercion" }, + { "name": "parseFloat", "message": "tsstyle#type-coercion" }, + { "name": "Array", "message": "tsstyle#array-constructor" } + ], + "ban-types": [ + true, + ["Object", "Use {} instead."], + ["String", "Use 'string' instead."], + ["Number", "Use 'number' instead."], + ["Boolean", "Use 'boolean' instead."] + ], + "class-name": true, + "curly": [true, "ignore-same-line"], + "deprecation": true, + "forin": false, + "interface-name": [true, "never-prefix"], + "jsdoc-format": true, + "label-position": true, + "max-classes-per-file": [true, 1], + "member-access": true, + "no-angle-bracket-type-assertion": true, + "no-any": false, + "no-arg": true, + "no-conditional-assignment": true, + "no-construct": true, + "no-debugger": true, + "no-default-export": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": true, + "no-inferrable-types": true, + "no-namespace": [true, "allow-declarations"], + "no-null-keyword": true, + "no-reference": true, + "no-string-throw": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-shorthand": true, + "only-arrow-functions": [true, "allow-declarations", "allow-named-functions"], + "prefer-const": true, + "radix": true, + "switch-default": false, + "triple-equals": [true, "allow-null-check"], + "typedef": [true, "call-signature", "property-declaration"], + "use-isnan": true, + "variable-name": [ + true, + "check-format", + "ban-keywords", + "allow-leading-underscore", + "allow-pascal-case" + ] + } +} diff --git a/test/unit/accessors.spec.ts b/test/unit/accessors.spec.ts index 608d28851..a29505278 100644 --- a/test/unit/accessors.spec.ts +++ b/test/unit/accessors.spec.ts @@ -1,412 +1,353 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; -export class AccessorTests { - @Test("get accessor") - public getAccessor(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - } - const f = new Foo(); - return f.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("get accessor", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + } + const f = new Foo(); + return f.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("get accessor in base class") - public getAccessorInBaseClass(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - } - class Bar extends Foo {} - const b = new Bar(); - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("get accessor in base class", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + } + class Bar extends Foo {} + const b = new Bar(); + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("get accessor override") - public getAccessorOverride(): void { - const code = - `class Foo { - _foo = "foo"; - foo = "foo"; - } - class Bar extends Foo { - get foo() { return this._foo + "bar"; } - } - const b = new Bar(); - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("get accessor override", () => { + const code = `class Foo { + _foo = "foo"; + foo = "foo"; + } + class Bar extends Foo { + get foo() { return this._foo + "bar"; } + } + const b = new Bar(); + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("get accessor overridden") - public getAccessorOverridden(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - } - class Bar extends Foo { - foo = "bar"; - } - const b = new Bar(); - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("get accessor overridden", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + } + class Bar extends Foo { + foo = "bar"; + } + const b = new Bar(); + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("get accessor override accessor") - public getAccessorOverrideAccessor(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - } - class Bar extends Foo { - _bar = "bar"; - get foo() { return this._bar; } - } - const b = new Bar(); - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("get accessor override accessor", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + } + class Bar extends Foo { + _bar = "bar"; + get foo() { return this._bar; } + } + const b = new Bar(); + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("get accessor from interface") - public getAccessorFromINterface(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - } - interface Bar { - readonly foo: string; - } - const b: Bar = new Foo(); - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("get accessor from interface", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + } + interface Bar { + readonly foo: string; + } + const b: Bar = new Foo(); + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("set accessor") - public setAccessor(): void { - const code = - `class Foo { - _foo = "foo"; - set foo(val: string) { this._foo = val; } - } - const f = new Foo(); - f.foo = "bar" - return f._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("set accessor", () => { + const code = `class Foo { + _foo = "foo"; + set foo(val: string) { this._foo = val; } + } + const f = new Foo(); + f.foo = "bar" + return f._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("set accessor in base class") - public setAccessorInBaseClass(): void { - const code = - `class Foo { - _foo = "foo"; - set foo(val: string) { this._foo = val; } - } - class Bar extends Foo {} - const b = new Bar(); - b.foo = "bar" - return b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("set accessor in base class", () => { + const code = `class Foo { + _foo = "foo"; + set foo(val: string) { this._foo = val; } + } + class Bar extends Foo {} + const b = new Bar(); + b.foo = "bar" + return b._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("set accessor override") - public setAccessorOverride(): void { - const code = - `class Foo { - _foo = "foo"; - foo = "foo"; - } - class Bar extends Foo { - set foo(val: string) { this._foo = val; } - } - const b = new Bar(); - b.foo = "bar" - return b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("set accessor override", () => { + const code = `class Foo { + _foo = "foo"; + foo = "foo"; + } + class Bar extends Foo { + set foo(val: string) { this._foo = val; } + } + const b = new Bar(); + b.foo = "bar" + return b._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("set accessor overridden") - public setAccessorOverridden(): void { - const code = - `class Foo { - _foo = "baz"; - set foo(val: string) { this._foo = val; } - } - class Bar extends Foo { - foo = "foo"; // triggers base class setter - } - const b = new Bar(); - const fooOriginal = b._foo; - b.foo = "bar" - return fooOriginal + b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("set accessor overridden", () => { + const code = `class Foo { + _foo = "baz"; + set foo(val: string) { this._foo = val; } + } + class Bar extends Foo { + foo = "foo"; // triggers base class setter + } + const b = new Bar(); + const fooOriginal = b._foo; + b.foo = "bar" + return fooOriginal + b._foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("set accessor override accessor") - public setAccessorOverrideAccessor(): void { - const code = - `class Foo { - _foo = "foo"; - set foo(val: string) { this._foo = "foo"; } - } - class Bar extends Foo { - set foo(val: string) { this._foo = val; } - } - const b = new Bar(); - b.foo = "bar" - return b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("set accessor override accessor", () => { + const code = `class Foo { + _foo = "foo"; + set foo(val: string) { this._foo = "foo"; } + } + class Bar extends Foo { + set foo(val: string) { this._foo = val; } + } + const b = new Bar(); + b.foo = "bar" + return b._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("set accessor from interface") - public setAccessorFromInterface(): void { - const code = - `class Foo { - _foo = "foo"; - set foo(val: string) { this._foo = val; } - } - interface Bar { - _foo: string; - foo: string; - } - const b: Bar = new Foo(); - b.foo = "bar" - return b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("set accessor from interface", () => { + const code = `class Foo { + _foo = "foo"; + set foo(val: string) { this._foo = val; } + } + interface Bar { + _foo: string; + foo: string; + } + const b: Bar = new Foo(); + b.foo = "bar" + return b._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("get/set accessors") - public getSetAccessor(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - set foo(val: string) { this._foo = val; } - } - const f = new Foo(); - const fooOriginal = f.foo; - f.foo = "bar"; - return fooOriginal + f.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("get/set accessors", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + set foo(val: string) { this._foo = val; } + } + const f = new Foo(); + const fooOriginal = f.foo; + f.foo = "bar"; + return fooOriginal + f.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("get/set accessors in base class") - public getSetAccessorInBaseClass(): void { - const code = - `class Foo { - _foo = "foo"; - get foo() { return this._foo; } - set foo(val: string) { this._foo = val; } - } - class Bar extends Foo {} - const b = new Bar(); - const fooOriginal = b.foo; - b.foo = "bar" - return fooOriginal + b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("get/set accessors in base class", () => { + const code = `class Foo { + _foo = "foo"; + get foo() { return this._foo; } + set foo(val: string) { this._foo = val; } + } + class Bar extends Foo {} + const b = new Bar(); + const fooOriginal = b.foo; + b.foo = "bar" + return fooOriginal + b.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("static get accessor") - public staticGetAccessor(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - } - return Foo.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("static get accessor", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + } + return Foo.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("static get accessor in base class") - public staticGetAccessorInBaseClass(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - } - class Bar extends Foo {} - return Bar.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("static get accessor in base class", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + } + class Bar extends Foo {} + return Bar.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("static get accessor override") - public staticGetAccessorOverride(): void { - const code = - `class Foo { - static _foo = "foo"; - static foo = "foo"; - } - class Bar extends Foo { - static get foo() { return this._foo + "bar"; } - } - return Bar.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("static get accessor override", () => { + const code = `class Foo { + static _foo = "foo"; + static foo = "foo"; + } + class Bar extends Foo { + static get foo() { return this._foo + "bar"; } + } + return Bar.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("static get accessor overridden") - public staticGetAccessorOverridden(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - } - class Bar extends Foo { - static foo = "bar"; - } - return Bar.foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static get accessor overridden", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + } + class Bar extends Foo { + static foo = "bar"; + } + return Bar.foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static get accessor override accessor") - public staticGetAccessorOverrideAccessor(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - } - class Bar extends Foo { - static _bar = "bar"; - static get foo() { return this._bar; } - } - return Bar.foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static get accessor override accessor", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + } + class Bar extends Foo { + static _bar = "bar"; + static get foo() { return this._bar; } + } + return Bar.foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static get accessor from interface") - public staticGetAccessorFromINterface(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - } - interface Bar { - readonly foo: string; - } - const b: Bar = Foo; - return b.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } +test("static get accessor from interface", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + } + interface Bar { + readonly foo: string; + } + const b: Bar = Foo; + return b.foo;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); - @Test("static set accessor") - public staticSetAccessor(): void { - const code = - `class Foo { - static _foo = "foo"; - static set foo(val: string) { this._foo = val; } - } - Foo.foo = "bar" - return Foo._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static set accessor", () => { + const code = `class Foo { + static _foo = "foo"; + static set foo(val: string) { this._foo = val; } + } + Foo.foo = "bar" + return Foo._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static set accessor in base class") - public staticSetAccessorInBaseClass(): void { - const code = - `class Foo { - static _foo = "foo"; - static set foo(val: string) { this._foo = val; } - } - class Bar extends Foo {} - Bar.foo = "bar" - return Bar._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static set accessor in base class", () => { + const code = `class Foo { + static _foo = "foo"; + static set foo(val: string) { this._foo = val; } + } + class Bar extends Foo {} + Bar.foo = "bar" + return Bar._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static set accessor override") - public staticSetAccessorOverride(): void { - const code = - `class Foo { - static _foo = "foo"; - static foo = "foo"; - } - class Bar extends Foo { - static set foo(val: string) { this._foo = val; } - } - Bar.foo = "bar" - return Bar._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static set accessor override", () => { + const code = `class Foo { + static _foo = "foo"; + static foo = "foo"; + } + class Bar extends Foo { + static set foo(val: string) { this._foo = val; } + } + Bar.foo = "bar" + return Bar._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static set accessor overridden") - public staticSetAccessorOverridden(): void { - const code = - `class Foo { - static _foo = "baz"; - static set foo(val: string) { this._foo = val; } - } - class Bar extends Foo { - static foo = "foo"; // triggers base class setter - } - const fooOriginal = Bar._foo; - Bar.foo = "bar" - return fooOriginal + Bar._foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("static set accessor overridden", () => { + const code = `class Foo { + static _foo = "baz"; + static set foo(val: string) { this._foo = val; } + } + class Bar extends Foo { + static foo = "foo"; // triggers base class setter + } + const fooOriginal = Bar._foo; + Bar.foo = "bar" + return fooOriginal + Bar._foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("static set accessor override accessor") - public staticSetAccessorOverrideAccessor(): void { - const code = - `class Foo { - static _foo = "foo"; - static set foo(val: string) { this._foo = "foo"; } - } - class Bar extends Foo { - static set foo(val: string) { this._foo = val; } - } - Bar.foo = "bar" - return Bar._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static set accessor override accessor", () => { + const code = `class Foo { + static _foo = "foo"; + static set foo(val: string) { this._foo = "foo"; } + } + class Bar extends Foo { + static set foo(val: string) { this._foo = val; } + } + Bar.foo = "bar" + return Bar._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static set accessor from interface") - public staticSetAccessorFromInterface(): void { - const code = - `class Foo { - static _foo = "foo"; - static set foo(val: string) { this._foo = val; } - } - interface Bar { - _foo: string; - foo: string; - } - const b: Bar = Foo; - b.foo = "bar" - return b._foo;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } +test("static set accessor from interface", () => { + const code = `class Foo { + static _foo = "foo"; + static set foo(val: string) { this._foo = val; } + } + interface Bar { + _foo: string; + foo: string; + } + const b: Bar = Foo; + b.foo = "bar" + return b._foo;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); - @Test("static get/set accessors") - public staticGetSetAccessor(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - static set foo(val: string) { this._foo = val; } - } - const fooOriginal = Foo.foo; - Foo.foo = "bar"; - return fooOriginal + Foo.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } +test("static get/set accessors", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + static set foo(val: string) { this._foo = val; } + } + const fooOriginal = Foo.foo; + Foo.foo = "bar"; + return fooOriginal + Foo.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); - @Test("static get/set accessors in base class") - public staticGetSetAccessorInBaseClass(): void { - const code = - `class Foo { - static _foo = "foo"; - static get foo() { return this._foo; } - static set foo(val: string) { this._foo = val; } - } - class Bar extends Foo {} - const fooOriginal = Bar.foo; - Bar.foo = "bar" - return fooOriginal + Bar.foo;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } -} +test("static get/set accessors in base class", () => { + const code = `class Foo { + static _foo = "foo"; + static get foo() { return this._foo; } + static set foo(val: string) { this._foo = val; } + } + class Bar extends Foo {} + const fooOriginal = Bar.foo; + Bar.foo = "bar" + return fooOriginal + Bar.foo;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); diff --git a/test/unit/array.spec.ts b/test/unit/array.spec.ts index 4ddb7b8fd..98e98e730 100644 --- a/test/unit/array.spec.ts +++ b/test/unit/array.spec.ts @@ -1,150 +1,134 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; - -export class ArrayTests { - @Test("Array access") - public arrayAccess(): void { - const result = util.transpileAndExecute( - `const arr: number[] = [3,5,1]; - return arr[1];` - ); - Expect(result).toBe(5); - } - - @Test("Readonly Array access") - public readonlyArrayAccess(): void { - const result = util.transpileAndExecute( - `const arr: ReadonlyArray = [3,5,1]; - return arr[1];` - ); - Expect(result).toBe(5); - } - - @Test("Array union access") - public arrayUnionAccess(): void { - const result = util.transpileAndExecute( - `function makeArray(): number[] | string[] { return [3,5,1]; } - const arr = makeArray(); - return arr[1];` - ); - Expect(result).toBe(5); - } - - @Test("Array union access with empty tuple") - public arrayUnionAccessWithEmptyTuple(): void { - const result = util.transpileAndExecute( - `function makeArray(): number[] | [] { return [3,5,1]; } - const arr = makeArray(); - return arr[1];` - ); - Expect(result).toBe(5); - } - - @Test("Array union length") - public arrayUnionLength(): void { - const result = util.transpileAndExecute( - `function makeArray(): number[] | string[] { return [3,5,1]; } - const arr = makeArray(); - return arr.length;` - ); - Expect(result).toBe(3); - } - - @Test("Array intersection access") - public arrayIntersectionAccess(): void { - const result = util.transpileAndExecute( - `type I = number[] & {foo: string}; - function makeArray(): I { - let t = [3,5,1]; - (t as I).foo = "bar"; - return (t as I); - } - const arr = makeArray(); - return arr[1];` - ); - Expect(result).toBe(5); - } - - @Test("Array intersection length") - public arrayIntersectionLength(): void { - const result = util.transpileAndExecute( - `type I = number[] & {foo: string}; - function makeArray(): I { - let t = [3,5,1]; - (t as I).foo = "bar"; - return (t as I); - } - const arr = makeArray(); - return arr.length;` - ); - Expect(result).toBe(3); - } - - @TestCase("firstElement()", 3) - @TestCase("name", "array") - @TestCase("length", 1) - @Test("Derived array access") - public derivedArrayAccess(member: string, expected: any): void { - const luaHeader = `local arr = {name="array", firstElement=function(self) return self[1]; end};`; - const typeScriptHeader = - `interface CustomArray extends Array{ - name:string, - firstElement():number; - }; - declare const arr: CustomArray;`; - - const result = util.transpileAndExecute( - ` - arr[0] = 3; - return arr.${member};`, - undefined, - luaHeader, - typeScriptHeader - ); - - Expect(result).toBe(expected); - } - - @Test("Array delete") - public arrayDelete(): void { - const result = util.transpileAndExecute( - `const myarray = [1,2,3,4]; - delete myarray[2]; - return \`\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` - ); - - Expect(result).toBe("1,2,nil,4"); - } - - @Test("Array delete return true") - public arrayDeleteReturnTrue(): void { - const result = util.transpileAndExecute( - `const myarray = [1,2,3,4]; - const exists = delete myarray[2]; - return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` - ); - - Expect(result).toBe("true:1,2,nil,4"); - } - - @Test("Array delete return false") - public arrayDeleteReturnFalse(): void { - const result = util.transpileAndExecute( - `const myarray = [1,2,3,4]; - const exists = delete myarray[4]; - return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;` - ); - - Expect(result).toBe("true:1,2,3,4"); - } - - @Test("Array property access") - public arrayPropertyAccess(): void { - const code = - `type A = number[] & {foo?: string}; - const a: A = [1,2,3]; - a.foo = "bar"; - return \`\${a.foo}\${a[0]}\${a[1]}\${a[2]}\`;`; - Expect(util.transpileAndExecute(code)).toBe("bar123"); - } -} +import * as util from "../util"; + +test("Array access", () => { + const result = util.transpileAndExecute( + `const arr: number[] = [3,5,1]; + return arr[1];`, + ); + expect(result).toBe(5); +}); + +test("Readonly Array access", () => { + const result = util.transpileAndExecute( + `const arr: ReadonlyArray = [3,5,1]; + return arr[1];`, + ); + expect(result).toBe(5); +}); + +test("Array union access", () => { + const result = util.transpileAndExecute( + `function makeArray(): number[] | string[] { return [3,5,1]; } + const arr = makeArray(); + return arr[1];`, + ); + expect(result).toBe(5); +}); + +test("Array union access with empty tuple", () => { + const result = util.transpileAndExecute( + `function makeArray(): number[] | [] { return [3,5,1]; } + const arr = makeArray(); + return arr[1];`, + ); + expect(result).toBe(5); +}); + +test("Array union length", () => { + const result = util.transpileAndExecute( + `function makeArray(): number[] | string[] { return [3,5,1]; } + const arr = makeArray(); + return arr.length;`, + ); + expect(result).toBe(3); +}); + +test("Array intersection access", () => { + const result = util.transpileAndExecute( + `type I = number[] & {foo: string}; + function makeArray(): I { + let t = [3,5,1]; + (t as I).foo = "bar"; + return (t as I); + } + const arr = makeArray(); + return arr[1];`, + ); + expect(result).toBe(5); +}); + +test("Array intersection length", () => { + const result = util.transpileAndExecute( + `type I = number[] & {foo: string}; + function makeArray(): I { + let t = [3,5,1]; + (t as I).foo = "bar"; + return (t as I); + } + const arr = makeArray(); + return arr.length;`, + ); + expect(result).toBe(3); +}); + +test.each([ + { member: "firstElement()", expected: 3 }, + { member: "name", expected: "array" }, + { member: "length", expected: 1 }, +])("Derived array access (%p)", ({ member, expected }) => { + const luaHeader = `local arr = {name="array", firstElement=function(self) return self[1]; end};`; + const typeScriptHeader = `interface CustomArray extends Array{ + name:string, + firstElement():number; + }; + declare const arr: CustomArray;`; + + const result = util.transpileAndExecute( + ` + arr[0] = 3; + return arr.${member};`, + undefined, + luaHeader, + typeScriptHeader, + ); + + expect(result).toBe(expected); +}); + +test("Array delete", () => { + const result = util.transpileAndExecute( + `const myarray = [1,2,3,4]; + delete myarray[2]; + return \`\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;`, + ); + + expect(result).toBe("1,2,nil,4"); +}); + +test("Array delete return true", () => { + const result = util.transpileAndExecute( + `const myarray = [1,2,3,4]; + const exists = delete myarray[2]; + return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;`, + ); + + expect(result).toBe("true:1,2,nil,4"); +}); + +test("Array delete return false", () => { + const result = util.transpileAndExecute( + `const myarray = [1,2,3,4]; + const exists = delete myarray[4]; + return \`\${exists}:\${myarray[0]},\${myarray[1]},\${myarray[2]},\${myarray[3]}\`;`, + ); + + expect(result).toBe("true:1,2,3,4"); +}); + +test("Array property access", () => { + const code = `type A = number[] & {foo?: string}; + const a: A = [1,2,3]; + a.foo = "bar"; + return \`\${a.foo}\${a[0]}\${a[1]}\${a[2]}\`;`; + expect(util.transpileAndExecute(code)).toBe("bar123"); +}); diff --git a/test/unit/assignmentDestructuring.spec.ts b/test/unit/assignmentDestructuring.spec.ts index 985ee4472..2fa8fb07b 100644 --- a/test/unit/assignmentDestructuring.spec.ts +++ b/test/unit/assignmentDestructuring.spec.ts @@ -1,63 +1,51 @@ -import { Expect, Test, TestCase } from "alsatian"; import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; -import * as util from "../src/util"; +import * as util from "../util"; -export class AssignmentDestructuringTests { +const assignmentDestruturingTs = ` + declare function myFunc(this: void): [number, string]; + let [a, b] = myFunc();`; - private readonly assignmentDestruturingTs = ` - declare function myFunc(this: void): [number, string]; - let [a, b] = myFunc();`; +test("Assignment destructuring [5.1]", () => { + const lua = util.transpileString(assignmentDestruturingTs, { + luaTarget: LuaTarget.Lua51, + luaLibImport: LuaLibImportKind.None, + }); + expect(lua).toBe(`local a, b = unpack(myFunc());`); +}); - @Test("Assignment destructuring [5.1]") - public assignmentDestructuring51(): void { - // Transpile - const lua = util.transpileString( - this.assignmentDestruturingTs, {luaTarget: LuaTarget.Lua51, luaLibImport: LuaLibImportKind.None} - ); - // Assert - Expect(lua).toBe(`local a, b = unpack(myFunc());`); - } +test("Assignment destructuring [5.2]", () => { + const lua = util.transpileString(assignmentDestruturingTs, { + luaTarget: LuaTarget.Lua52, + luaLibImport: LuaLibImportKind.None, + }); + expect(lua).toBe(`local a, b = table.unpack(myFunc());`); +}); - @Test("Assignment destructuring [5.2]") - public tupleDestructing52(): void { - // Transpile - const lua = util.transpileString( - this.assignmentDestruturingTs, {luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None} - ); - // Assert - Expect(lua).toBe(`local a, b = table.unpack(myFunc());`); - } +test("Assignment destructuring [JIT]", () => { + const lua = util.transpileString(assignmentDestruturingTs, { + luaTarget: LuaTarget.LuaJIT, + luaLibImport: LuaLibImportKind.None, + }); + expect(lua).toBe(`local a, b = unpack(myFunc());`); +}); - @Test("Assignment destructuring [JIT]") - public assignmentDestructuringJIT(): void { - // Transpile - const lua = util.transpileString( - this.assignmentDestruturingTs, {luaTarget: LuaTarget.LuaJIT, luaLibImport: LuaLibImportKind.None} - ); - // Assert - Expect(lua).toBe(`local a, b = unpack(myFunc());`); - } +test.each([ + "function foo(): [] { return []; }; let [] = foo();", + "let [] = ['a', 'b', 'c'];", + "let [] = [];", + "let [] = [] = [];", + "function foo(): [] { return []; }; [] = foo();", + "[] = ['a', 'b', 'c'];", + "[] = [];", + "[] = [] = [];", +])("Empty destructuring (%p)", code => { + expect(() => util.transpileAndExecute(code)).not.toThrow(); +}); - @TestCase("function foo(): [] { return []; }; let [] = foo();") - @TestCase("let [] = ['a', 'b', 'c'];") - @TestCase("let [] = [];") - @TestCase("let [] = [] = [];") - @TestCase("function foo(): [] { return []; }; [] = foo();") - @TestCase("[] = ['a', 'b', 'c'];") - @TestCase("[] = [];") - @TestCase("[] = [] = [];") - @Test("Empty destructuring") - public emptyDestructuring(code: string): void { - Expect(() => util.transpileAndExecute(code)).not.toThrow(); - } - - @Test("Union destructuring") - public unionDestructuring(): void { - const code = - `function foo(): [string] | [] { return ["bar"]; } - let x: string; - [x] = foo(); - return x;`; - Expect(util.transpileAndExecute(code)).toBe("bar"); - } -} +test("Union destructuring", () => { + const code = `function foo(): [string] | [] { return ["bar"]; } + let x: string; + [x] = foo(); + return x;`; + expect(util.transpileAndExecute(code)).toBe("bar"); +}); diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index f5d5e0ddb..ed3c49daf 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -1,9 +1,6 @@ -import { Expect, Test, TestCase, TestCases } from "alsatian"; import { TranspileError } from "../../src/TranspileError"; - -import * as util from "../src/util"; import { TSTLErrors } from "../../src/TSTLErrors"; -const fs = require("fs"); +import * as util from "../util"; interface TestFunction { value: string; @@ -303,20 +300,20 @@ const noSelfInFileTestFunctions: TestFunction[] = [ ]; const anonTestFunctionExpressions: TestFunction[] = [ - {value: `s => s`}, - {value: `(s => s)`}, - {value: `function(s) { return s; }`}, - {value: `(function(s) { return s; })`}, + { value: `s => s` }, + { value: `(s => s)` }, + { value: `function(s) { return s; }` }, + { value: `(function(s) { return s; })` }, ]; const selfTestFunctionExpressions: TestFunction[] = [ - {value: `function(this: any, s) { return s; }`}, - {value: `(function(this: any, s) { return s; })`}, + { value: `function(this: any, s) { return s; }` }, + { value: `(function(this: any, s) { return s; })` }, ]; const noSelfTestFunctionExpressions: TestFunction[] = [ - {value: `function(this: void, s) { return s; }`}, - {value: `(function(this: void, s) { return s; })`}, + { value: `function(this: void, s) { return s; }` }, + { value: `(function(this: void, s) { return s; })` }, ]; const anonTestFunctionType = "(s: string) => string"; @@ -324,9 +321,9 @@ const selfTestFunctionType = "(this: any, s: string) => string"; const noSelfTestFunctionType = "(this: void, s: string) => string"; type TestFunctionCast = [ - /*testFunction: */TestFunction, - /*castedFunction: */string, - /*isSelfConversion?: */boolean? + /*testFunction: */ TestFunction, + /*castedFunction: */ string, + /*isSelfConversion?: */ boolean? ]; const validTestFunctionCasts: TestFunctionCast[] = [ [selfTestFunctions[0], `<${anonTestFunctionType}>(${selfTestFunctions[0].value})`], @@ -335,26 +332,54 @@ const validTestFunctionCasts: TestFunctionCast[] = [ [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})`], + [ + 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})`, + ], ]; const invalidTestFunctionCasts: TestFunctionCast[] = [ [noSelfTestFunctions[0], `<${anonTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], - [noSelfTestFunctions[0], `(${noSelfTestFunctions[0].value}) as (${anonTestFunctionType})`, false], + [ + noSelfTestFunctions[0], + `(${noSelfTestFunctions[0].value}) as (${anonTestFunctionType})`, + false, + ], [noSelfTestFunctions[0], `<${selfTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], - [noSelfTestFunctions[0], `(${noSelfTestFunctions[0].value}) as (${selfTestFunctionType})`, false], - [noSelfInFileTestFunctions[0], `<${selfTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`, false], - [noSelfInFileTestFunctions[0], `(${noSelfInFileTestFunctions[0].value}) as (${selfTestFunctionType})`, false], + [ + noSelfTestFunctions[0], + `(${noSelfTestFunctions[0].value}) as (${selfTestFunctionType})`, + false, + ], + [ + noSelfInFileTestFunctions[0], + `<${selfTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`, + false, + ], + [ + noSelfInFileTestFunctions[0], + `(${noSelfInFileTestFunctions[0].value}) as (${selfTestFunctionType})`, + false, + ], [selfTestFunctions[0], `<${noSelfTestFunctionType}>(${selfTestFunctions[0].value})`, true], [selfTestFunctions[0], `(${selfTestFunctions[0].value}) as (${noSelfTestFunctionType})`, true], ]; type TestFunctionAssignment = [ - /*testFunction: */TestFunction, - /*functionType: */string, - /*isSelfConversion?: */boolean? + /*testFunction: */ TestFunction, + /*functionType: */ string, + /*isSelfConversion?: */ boolean? ]; const validTestFunctionAssignments: TestFunctionAssignment[] = [ ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), @@ -367,830 +392,883 @@ const validTestFunctionAssignments: TestFunctionAssignment[] = [ ...anonTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), - ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType], + ), ]; const invalidTestFunctionAssignments: TestFunctionAssignment[] = [ ...selfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType, false]), ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), - ...noSelfInFileTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), - ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType, false]), - ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), - ...noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), + ...noSelfInFileTestFunctions.map( + (f): TestFunctionAssignment => [f, selfTestFunctionType, true], + ), + ...selfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType, false], + ), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, anonTestFunctionType, true], + ), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, selfTestFunctionType, true], + ), ]; -export class AssignmentTests { - - @TestCase(`"abc"`, `"abc"`) - @TestCase("3", "3") - @TestCase("[1,2,3]", "{1, 2, 3}") - @TestCase("true", "true") - @TestCase("false", "false") - @TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"}`) - @Test("Const assignment") - public constAssignment(inp: string, out: string): void { - const lua = util.transpileString(`const myvar = ${inp};`); - Expect(lua).toBe(`local myvar = ${out};`); - } - - @TestCase(`"abc"`, `"abc"`) - @TestCase("3", "3") - @TestCase("[1,2,3]", "{1, 2, 3}") - @TestCase("true", "true") - @TestCase("false", "false") - @TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"}`) - @Test("Let assignment") - public letAssignment(inp: string, out: string): void { - const lua = util.transpileString(`let myvar = ${inp};`); - Expect(lua).toBe(`local myvar = ${out};`); - } - - @TestCase(`"abc"`, `"abc"`) - @TestCase("3", "3") - @TestCase("[1,2,3]", "{1, 2, 3}") - @TestCase("true", "true") - @TestCase("false", "false") - @TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"}`) - @Test("Var assignment") - public varAssignment(inp: string, out: string): void { - const lua = util.transpileString(`var myvar = ${inp};`); - Expect(lua).toBe(`myvar = ${out};`); - } - - @TestCase("var myvar;") - @TestCase("let myvar;") - @TestCase("const myvar = null;") - @TestCase("const myvar = undefined;") - @Test("Null assignments") - public nullAssignment(declaration: string): void { +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Const assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`const myvar = ${inp};`); + expect(lua).toBe(`local myvar = ${out};`); +}); + +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Let assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`let myvar = ${inp};`); + expect(lua).toBe(`local myvar = ${out};`); +}); + +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Var assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`var myvar = ${inp};`); + expect(lua).toBe(`myvar = ${out};`); +}); + +test.each(["var myvar;", "let myvar;", "const myvar = null;", "const myvar = undefined;"])( + "Null assignments (%p)", + declaration => { const result = util.transpileAndExecute(declaration + " return myvar;"); - Expect(result).toBe(undefined); - } - - @TestCase(["a", "b"], ["e", "f"]) - @TestCase(["a", "b"], ["e", "f", "g"]) - @TestCase(["a", "b", "c"], ["e", "f", "g"]) - @Test("Binding pattern assignment") - public bindingPattern(input: string[], values: string[]): void { - const pattern = input.join(","); - const initializer = values.map(v => `"${v}"`).join(","); - - const tsCode = `const [${pattern}] = [${initializer}]; return [${pattern}].join("-");`; - const result = util.transpileAndExecute(tsCode); - - Expect(result).toBe(values.slice(0, input.length).join("-")); - } - - @Test("Ellipsis binding pattern") - public ellipsisBindingPattern(): void { - Expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")) - .toThrowError(Error, "Ellipsis destruction is not allowed."); - } - - @Test("Tuple Assignment") - public tupleAssignment(): void { - const code = `function abc(): [number, number] { return [1, 2]; }; - let t: [number, number] = abc(); - return t[0] + t[1];`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(3); - } - - @Test("TupleReturn assignment") - public tupleReturnFunction(): void { - const code = `/** @tupleReturn */\n` - + `declare function abc(this: void): number[]\n` - + `let [a,b] = abc();`; - - const lua = util.transpileString(code); - Expect(lua).toBe("local a, b = abc();"); - } - - @Test("TupleReturn Single assignment") - public tupleReturnSingleAssignment(): void { - const code = `/** @tupleReturn */\n` - + `declare function abc(this: void): [number, string];\n` - + `let a = abc();` - + `a = abc();`; - - const lua = util.transpileString(code); - Expect(lua).toBe("local a = ({abc()});\na = ({abc()});"); - } - - @Test("TupleReturn interface assignment") - public tupleReturnInterface(): void { - const code = `interface def {\n` - + `/** @tupleReturn */\n` - + `abc();\n` - + `} declare const jkl : def;\n` - + `let [a,b] = jkl.abc();`; - - const lua = util.transpileString(code); - Expect(lua).toBe("local a, b = jkl:abc();"); - } - - @Test("TupleReturn namespace assignment") - public tupleReturnNameSpace(): void { - const code = `declare namespace def {\n` - + `/** @tupleReturn */\n` - + `function abc(this: void) {}\n` - + `}\n` - + `let [a,b] = def.abc();`; - - const lua = util.transpileString(code); - Expect(lua).toBe("local a, b = def.abc();"); - } - - @Test("TupleReturn method assignment") - public tupleReturnMethod(): void { - const code = `declare class def {\n` - + `/** @tupleReturn */\n` - + `abc() { return [1,2,3]; }\n` - + `} const jkl = new def();\n` - + `let [a,b] = jkl.abc();`; - - const lua = util.transpileString(code); - Expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); - } - - @Test("TupleReturn functional") - public tupleReturnFunctional(): void { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a;`; - - const result = util.transpileAndExecute(code); - - Expect(result).toBe("a3"); - } - - @Test("TupleReturn single") - public tupleReturnSingle(): void { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length`; - - const result = util.transpileAndExecute(code); - - Expect(result).toBe(2); - } - - @Test("TupleReturn in expression") - public tupleReturnInExpression(): void { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0];`; - - const result = util.transpileAndExecute(code); - - Expect(result).toBe("a3"); - } - - @TestCase("and") - @TestCase("local") - @TestCase("nil") - @TestCase("not") - @TestCase("or") - @TestCase("repeat") - @TestCase("then") - @TestCase("until") - @Test("Keyword identifier error") - public keywordIdentifierError(identifier: string): void { - Expect(() => util.transpileString(`const ${identifier} = 3;`)) - .toThrowError(TranspileError, `Cannot use Lua keyword ${identifier} as identifier.`); - } - - @TestCases(validTestFunctionAssignments) - @Test("Valid function variable declaration") - public validFunctionDeclaration(testFunction: TestFunction, functionType: string): void { - const code = - `const fn: ${functionType} = ${testFunction.value}; - return fn("foobar");`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } - - @TestCases(validTestFunctionAssignments) - @Test("Valid function assignment") - public validFunctionAssignment(testFunction: TestFunction, functionType: string): void { - const code = - `let fn: ${functionType}; - fn = ${testFunction.value}; - return fn("foobar");`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } + expect(result).toBe(undefined); + }, +); + +test.each([ + { input: ["a", "b"], values: ["e", "f"] }, + { input: ["a", "b"], values: ["e", "f", "g"] }, + { input: ["a", "b", "c"], values: ["e", "f", "g"] }, +])("Binding pattern assignment (%p)", ({ input, values }) => { + const pattern = input.join(","); + const initializer = values.map(v => `"${v}"`).join(","); + + const tsCode = `const [${pattern}] = [${initializer}]; return [${pattern}].join("-");`; + const result = util.transpileAndExecute(tsCode); + + expect(result).toBe(values.slice(0, input.length).join("-")); +}); + +test("Ellipsis binding pattern", () => { + expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrowExactError( + new Error("Ellipsis destruction is not allowed."), + ); +}); + +test("Tuple Assignment", () => { + const code = `function abc(): [number, number] { return [1, 2]; }; + let t: [number, number] = abc(); + return t[0] + t[1];`; + const result = util.transpileAndExecute(code); + expect(result).toBe(3); +}); + +test("TupleReturn assignment", () => { + const code = + `/** @tupleReturn */\n` + + `declare function abc(this: void): number[]\n` + + `let [a,b] = abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = abc();"); +}); + +test("TupleReturn Single assignment", () => { + const code = + `/** @tupleReturn */\n` + + `declare function abc(this: void): [number, string];\n` + + `let a = abc();` + + `a = abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a = ({abc()});\na = ({abc()});"); +}); + +test("TupleReturn interface assignment", () => { + const code = + `interface def {\n` + + `/** @tupleReturn */\n` + + `abc();\n` + + `} declare const jkl : def;\n` + + `let [a,b] = jkl.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = jkl:abc();"); +}); + +test("TupleReturn namespace assignment", () => { + const code = + `declare namespace def {\n` + + `/** @tupleReturn */\n` + + `function abc(this: void) {}\n` + + `}\n` + + `let [a,b] = def.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = def.abc();"); +}); + +test("TupleReturn method assignment", () => { + const code = + `declare class def {\n` + + `/** @tupleReturn */\n` + + `abc() { return [1,2,3]; }\n` + + `} const jkl = new def();\n` + + `let [a,b] = jkl.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); +}); + +test("TupleReturn functional", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const [a, b] = abc(); + return b + a;`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe("a3"); +}); + +test("TupleReturn single", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const res = abc(); + return res.length`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe(2); +}); + +test("TupleReturn in expression", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + return abc()[1] + abc()[0];`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe("a3"); +}); + +test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( + "Keyword identifier error (%p)", + identifier => { + expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowExactError( + new TranspileError(`Cannot use Lua keyword ${identifier} as identifier.`), + ); + }, +); + +test.each(validTestFunctionAssignments)( + "Valid function variable declaration (%p)", + (testFunction, functionType) => { + const code = `const fn: ${functionType} = ${testFunction.value}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(validTestFunctionAssignments)( + "Valid function assignment (%p)", + (testFunction, functionType) => { + const code = `let fn: ${functionType}; + fn = ${testFunction.value}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); - @TestCases(invalidTestFunctionAssignments) - @Test("Invalid function variable declaration") - public invalidFunctionDeclaration(testFunction: TestFunction, functionType: string, isSelfConversion: boolean) - : void - { - const code = - `${testFunction.definition || ""} - const fn: ${functionType} = ${testFunction.value};`; +test.each(invalidTestFunctionAssignments)( + "Invalid function variable declaration (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + const fn: ${functionType} = ${testFunction.value};`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @TestCases(invalidTestFunctionAssignments) - @Test("Invalid function assignment") - public invalidFunctionAssignment(testFunction: TestFunction, functionType: string, isSelfConversion: boolean) - : void - { - const code = - `${testFunction.definition || ""} - let fn: ${functionType}; - fn = ${testFunction.value};`; + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function assignment (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + let fn: ${functionType}; + fn = ${testFunction.value};`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @TestCases(validTestFunctionCasts) - @Test("Valid function assignment with cast") - public validFunctionAssignmentWithCast(testFunction: TestFunction, castedFunction: string): void { - const code = - `let fn: typeof ${testFunction.value}; - fn = ${castedFunction}; - return fn("foobar");`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } - - @TestCases(invalidTestFunctionCasts) - @Test("Invalid function assignment with cast") - public invalidFunctionAssignmentWithCast( - testFunction: TestFunction, - castedFunction: string, - isSelfConversion: boolean - ): void { - const code = - `${testFunction.definition || ""} - let fn: typeof ${testFunction.value}; - fn = ${castedFunction};`; + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(validTestFunctionCasts)( + "Valid function assignment with cast (%p)", + (testFunction, castedFunction) => { + const code = `let fn: typeof ${testFunction.value}; + fn = ${castedFunction}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(invalidTestFunctionCasts)( + "Invalid function assignment with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + let fn: typeof ${testFunction.value}; + fn = ${castedFunction};`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @TestCases(validTestFunctionAssignments) - @Test("Valid function argument") - public validFunctionArgument(testFunction: TestFunction, functionType: string): void { - const code = - `function takesFunction(fn: ${functionType}) { - return fn("foobar"); - } - return takesFunction(${testFunction.value});`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); - @TestCases(invalidTestFunctionAssignments) - @Test("Invalid function argument") - public invalidFunctionArgument(testFunction: TestFunction, functionType: string, isSelfConversion: boolean) - : void - { - const code = - `${testFunction.definition || ""} - declare function takesFunction(fn: ${functionType}); - takesFunction(${testFunction.value});`; +test.each(validTestFunctionAssignments)( + "Valid function argument (%p)", + (testFunction, functionType) => { + const code = `function takesFunction(fn: ${functionType}) { + return fn("foobar"); + } + return takesFunction(${testFunction.value});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function argument (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: ${functionType}); + takesFunction(${testFunction.value});`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @Test("Valid lua lib function argument") - public validLuaLibFunctionArgument(): void { - const code = - `let result = ""; - function foo(this: any, value: string) { result += value; } - const a = ['foo', 'bar']; - a.forEach(foo); - return result;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } - - @Test("Invalid lua lib function argument") - public invalidLuaLibFunctionArgument(testFunction: TestFunction, functionType: string, isSelfConversion: boolean) - : void - { - const code = - `declare function foo(this: void, value: string): void; - declare const a: string[]; - a.forEach(foo);`; - const err = TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "callbackfn"); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @TestCases(validTestFunctionCasts) - @Test("Valid function argument with cast") - public validFunctionArgumentWithCast(testFunction: TestFunction, castedFunction: string): void { - const code = - `function takesFunction(fn: typeof ${testFunction.value}) { - return fn("foobar"); - } - return takesFunction(${castedFunction});`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test("Valid lua lib function argument", () => { + const code = `let result = ""; + function foo(this: any, value: string) { result += value; } + const a = ['foo', 'bar']; + a.forEach(foo); + return result;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test("Invalid lua lib function argument", () => { + const code = `declare function foo(this: void, value: string): void; + declare const a: string[]; + a.forEach(foo);`; + const err = TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "callbackfn"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); +}); + +test.each(validTestFunctionCasts)( + "Valid function argument with cast (%p)", + (testFunction, castedFunction) => { + const code = `function takesFunction(fn: typeof ${testFunction.value}) { + return fn("foobar"); } - - @TestCases(invalidTestFunctionCasts) - @Test("Invalid function argument with cast") - public invalidFunctionArgumentWithCast( - testFunction: TestFunction, - castedFunction: string, - isSelfConversion: boolean - ): void - { - const code = - `${testFunction.definition || ""} - declare function takesFunction(fn: typeof ${testFunction.value}); - takesFunction(${castedFunction});`; + return takesFunction(${castedFunction});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(invalidTestFunctionCasts)( + "Invalid function argument with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: typeof ${testFunction.value}); + takesFunction(${castedFunction});`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - // TODO: Fix function expression inference with generic types. The following should work, but doesn't: - // function takesFunction string>(fn: T) { ... } - // takesFunction(s => s); // Error: cannot convert method to function - // @TestCases(validTestFunctionAssignments) // Use this instead of other TestCases when fixed - @TestCases(selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType])) - @TestCases(selfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType])) - @TestCases(noSelfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType])) - @TestCases(selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType])) - @TestCases(selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType])) - @TestCases(noSelfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType])) - @Test("Valid function generic argument") - public validFunctionGenericArgument(testFunction: TestFunction, functionType: string): void { - const code = - `function takesFunction(fn: T) { - return fn("foobar"); - } - return takesFunction(${testFunction.value});`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); - @TestCases(invalidTestFunctionAssignments) - @Test("Invalid function generic argument") - public invalidFunctionGenericArgument(testFunction: TestFunction, functionType: string, isSelfConversion: boolean) - : void - { - const code = - `${testFunction.definition || ""} - declare function takesFunction(fn: T); - takesFunction(${testFunction.value});`; +// TODO: Fix function expression inference with generic types. The following should work, but doesn't: +// function takesFunction string>(fn: T) { ... } +// takesFunction(s => s); // Error: cannot convert method to function +// @TestCases(validTestFunctionAssignments) // Use this instead of other TestCases when fixed +test.each([ + ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), + ...selfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), + ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType], + ), +])("Valid function generic argument (%p)", (testFunction, functionType) => { + const code = `function takesFunction(fn: T) { + return fn("foobar"); + } + return takesFunction(${testFunction.value});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); +}); + +test.each(invalidTestFunctionAssignments)( + "Invalid function generic argument (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: T); + takesFunction(${testFunction.value});`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @TestCases(anonTestFunctionExpressions.map(f => [f, "0", "'foobar'"])) - @TestCases(selfTestFunctionExpressions.map(f => [f, "0", "'foobar'"])) - @TestCases(noSelfTestFunctionExpressions.map(f => [f, "'foobar'"])) - @Test("Valid function expression argument with no signature") - public validFunctionExpressionArgumentNoSignature(testFunction: TestFunction, ...args: string[]): void { - const code = - `const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { - return fn(...args); - } - return takesFunction(${testFunction.value}, ${args.join(", ")});`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } - - @TestCases(validTestFunctionAssignments) - @Test("Valid function return") - public validFunctionReturn(testFunction: TestFunction, functionType: string): void { - const code = - `function returnsFunction(): ${functionType} { - return ${testFunction.value}; - } - const fn = returnsFunction(); - return fn("foobar");`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); - } - - @TestCases(invalidTestFunctionAssignments) - @Test("Invalid function return") - public invalidFunctionReturn(testFunction: TestFunction, functionType: string, isSelfConversion: boolean): void { - const code = - `${testFunction.definition || ""} - function returnsFunction(): ${functionType} { - return ${testFunction.value}; - }`; + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each([ + ...anonTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), + ...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), + ...noSelfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]]), +])("Valid function expression argument with no signature (%p)", (testFunction, args) => { + const code = `const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { + return fn(...args); + } + return takesFunction(${testFunction.value}, ${args.join(", ")});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); +}); + +test.each(validTestFunctionAssignments)( + "Valid function return (%p)", + (testFunction, functionType) => { + const code = `function returnsFunction(): ${functionType} { + return ${testFunction.value}; + } + const fn = returnsFunction(); + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function return (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + function returnsFunction(): ${functionType} { + return ${testFunction.value}; + }`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); - @TestCases(validTestFunctionCasts) - @Test("Valid function return with cast") - public validFunctionReturnWithCast(testFunction: TestFunction, castedFunction: string): void { - const code = - `function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - } - const fn = returnsFunction(); - return fn("foobar");`; - Expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe("foobar"); +test.each(validTestFunctionCasts)( + "Valid function return with cast (%p)", + (testFunction, castedFunction) => { + const code = `function returnsFunction(): typeof ${testFunction.value} { + return ${castedFunction}; } - - @TestCases(invalidTestFunctionCasts) - @Test("Invalid function return with cast") - public invalidFunctionReturnWithCast( - testFunction: TestFunction, - castedFunction: string, - isSelfConversion: boolean - ): void - { - const code = - `${testFunction.definition || ""} - function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - }`; + const fn = returnsFunction(); + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(invalidTestFunctionCasts)( + "Invalid function return with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + function returnsFunction(): typeof ${testFunction.value} { + return ${castedFunction}; + }`; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @Test("Interface method assignment") - public interfaceMethodAssignment(): void { - const code = `class Foo { - method(s: string): string { return s + "+method"; } - lambdaProp: (s: string) => string = s => s + "+lambdaProp"; - } - interface IFoo { - method: (s: string) => string; - lambdaProp(s: string): string; - } - const foo: IFoo = new Foo(); - return foo.method("foo") + "|" + foo.lambdaProp("bar");`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo+method|bar+lambdaProp"); - } - - @Test("Valid function tuple assignment") - public validFunctionTupleAssignment(): void { - const code = `interface Func { (this: void, s: string): string; } - function getTuple(): [number, Func] { return [1, s => s]; } - let [i, f]: [number, Func] = getTuple(); - return f("foo");`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Invalid function tuple assignment") - public invalidFunctionTupleAssignment(): void { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Meth]; - let [i, f]: [number, Func] = getTuple();`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined).message - ); - } - - @Test("Valid method tuple assignment") - public validMethodTupleAssignment(): void { - const code = `interface Foo { method(s: string): string; } - interface Meth { (this: Foo, s: string): string; } - let meth: Meth = s => s; - function getTuple(): [number, Meth] { return [1, meth]; } - let [i, f]: [number, Meth] = getTuple(); - let foo: Foo = {method: f}; - return foo.method("foo");`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Invalid method tuple assignment") - public invalidMethodTupleAssignment(): void { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Func]; - let [i, f]: [number, Meth] = getTuple();`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - TSTLErrors.UnsupportedSelfFunctionConversion(undefined).message - ); - } - - @Test("Valid interface method assignment") - public validInterfaceMethodAssignment(): void { - const code = `interface A { fn(this: void, s: string): string; } - interface B { fn(this: void, s: string): string; } - const a: A = { fn(this: void, s) { return s; } }; - const b: B = a; - return b.fn("foo");`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Invalid interface method assignment") - public invalidInterfaceMethodAssignment(): void { - const code = `interface A { fn(s: string): string; } - interface B { fn(this: void, s: string): string; } - declare const a: A; - const b: B = a;`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn").message - ); - } - - @TestCase("(this: any, s: string) => string", ["foo"], "foobar") - @TestCase("{(this: any, s: string): string}", ["foo"], "foobar") - @TestCase("(this: any, s1: string, s2: string) => string", ["foo", "baz"], "foobaz") - @TestCase("{(this: any, s1: string, s2: string): string}", ["foo", "baz"], "foobaz") - @Test("Valid function overload assignment") - public validFunctionOverloadAssignment(assignType: string, args: string[], expectResult: string): void { - const code = `interface O { - (s1: string, s2: string): string; - (s: string): string; - } - const o: O = (s1: string, s2?: string) => s1 + (s2 || "bar"); - let f: ${assignType} = o; - return f(${args.map(a => "\"" + a + "\"").join(", ")});`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(expectResult); - } - - @TestCase("(this: void, s: string) => string") - @TestCase("(this: void, s1: string, s2: string) => string") - @TestCase("{(this: void, s: string): string}") - @TestCase("{(this: any, s1: string, s2: string): string}") - @Test("Invalid function overload assignment") - public invalidFunctionOverloadAssignment(assignType: string): void { - const code = `interface O { - (this: any, s1: string, s2: string): string; - (this: void, s: string): string; - } - declare const o: O; - let f: ${assignType} = o;`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - TSTLErrors.UnsupportedOverloadAssignment(undefined).message - ); - } - - @TestCase("noSelf") - @TestCase("noSelfInFile") - @Test("noSelf function method argument") - public noSelfFunctionMethodArgument(noSelfTag: string): void { - const header = - `/** @${noSelfTag} */ namespace NS { - export class C { - method(fn: (s: string) => string) { return fn("foo"); } - } - } - function foo(this: void, s: string) { return s; }`; - const code = - `const c = new NS.C(); - return c.method(foo);`; - Expect(util.transpileAndExecute(code, undefined, undefined, header, false)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string") - @TestCase("(this: any, s: string) => string") - @TestCase("(s: string) => string") - @Test("Function expression type inference in binary operator") - public functionExpressionTypeInferenceInBinaryOp(funcType: string): void { - const header = `declare const undefinedFunc: ${funcType};`; - const code = - `let func: ${funcType} = s => s; - func = undefinedFunc || (s => s); - return func("foo");`; - Expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); - } - - @TestCase("s => s") - @TestCase("(s => s)") - @TestCase("function(s) { return s; }") - @TestCase("(function(s) { return s; })") - @Test("Function expression type inference in class") - public functionExpressionTypeInferenceInClass(funcExp: string): void { - const code = - `class Foo { - func: (this: void, s: string) => string = ${funcExp}; - method: (s: string) => string = ${funcExp}; - static staticFunc: (this: void, s: string) => string = ${funcExp}; - static staticMethod: (s: string) => string = ${funcExp}; - } - const foo = new Foo(); - return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d");`; - Expect(util.transpileAndExecute(code)).toBe("abcd"); - } - - @TestCase("const foo: Foo", "s => s") - @TestCase("const foo: Foo", "(s => s)") - @TestCase("const foo: Foo", "function(s) { return s; }") - @TestCase("const foo: Foo", "(function(s) { return s; })") - @TestCase("let foo: Foo; foo", "s => s") - @TestCase("let foo: Foo; foo", "(s => s)") - @TestCase("let foo: Foo; foo", "function(s) { return s; }") - @TestCase("let foo: Foo; foo", "(function(s) { return s; })") - @Test("Function expression type inference in object literal") - public functionExpressionTypeInferenceInObjectLiteral(assignTo: string, funcExp: string): void { - const code = - `interface Foo { - func(this: void, s: string): string; - method(this: this, s: string): string; - } - ${assignTo} = {func: ${funcExp}, method: ${funcExp}}; - return foo.method("foo") + foo.func("bar");`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } - - @Test("Function expression type inference in object literal assigned to narrower type") - public functionEXpressionTypeInferenceInObjectLiteralAssignedToNarrowerType(): void { - const code = - `let foo: {} = {bar: s => s}; - return (foo as {bar: (a: any) => any}).bar("foobar");`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } - - @TestCase("const foo: Foo", "s => s") - @TestCase("const foo: Foo", "(s => s)") - @TestCase("const foo: Foo", "function(s) { return s; }") - @TestCase("const foo: Foo", "(function(s) { return s; })") - @TestCase("let foo: Foo; foo", "s => s") - @TestCase("let foo: Foo; foo", "(s => s)") - @TestCase("let foo: Foo; foo", "function(s) { return s; }") - @TestCase("let foo: Foo; foo", "(function(s) { return s; })") - @Test("Function expression type inference in object literal (generic key)") - public functionExpressionTypeInferenceInObjectLiteralGenericKey(assignTo: string, funcExp: string): void { - const code = - `interface Foo { - [f: string]: (this: void, s: string) => string; - } - ${assignTo} = {func: ${funcExp}}; - return foo.func("foo");`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("const funcs: [Func, Method]", "funcs[0]", "funcs[1]", "s => s") - @TestCase("const funcs: [Func, Method]", "funcs[0]", "funcs[1]", "(s => s)") - @TestCase("const funcs: [Func, Method]", "funcs[0]", "funcs[1]", "function(s) { return s; }") - @TestCase("const funcs: [Func, Method]", "funcs[0]", "funcs[1]", "(function(s) { return s; })") - @TestCase("let funcs: [Func, Method]; funcs", "funcs[0]", "funcs[1]", "s => s") - @TestCase("let funcs: [Func, Method]; funcs", "funcs[0]", "funcs[1]", "(s => s)") - @TestCase("let funcs: [Func, Method]; funcs", "funcs[0]", "funcs[1]", "function(s) { return s; }") - @TestCase("let funcs: [Func, Method]; funcs", "funcs[0]", "funcs[1]", "(function(s) { return s; })") - @TestCase("const [func, meth]: [Func, Method]", "func", "meth", "s => s") - @TestCase("const [func, meth]: [Func, Method]", "func", "meth", "(s => s)") - @TestCase("const [func, meth]: [Func, Method]", "func", "meth", "function(s) { return s; }") - @TestCase("const [func, meth]: [Func, Method]", "func", "meth", "(function(s) { return s; })") - @TestCase("let func: Func; let meth: Method; [func, meth]", "func", "meth", "s => s") - @TestCase("let func: Func; let meth: Method; [func, meth]", "func", "meth", "(s => s)") - @TestCase("let func: Func; let meth: Method; [func, meth]", "func", "meth", "function(s) { return s; }") - @TestCase("let func: Func; let meth: Method; [func, meth]", "func", "meth", "(function(s) { return s; })") - @Test("Function expression type inference in tuple") - public functionExpressionTypeInferenceInTuple( - assignTo: string, - func: string, - method: string, - funcExp: string - ): void - { - const code = - `interface Foo { - method(s: string): string; - } - interface Func { - (this: void, s: string): string; - } - interface Method { - (this: Foo, s: string): string; - } - ${assignTo} = [${funcExp}, ${funcExp}]; - const foo: Foo = {method: ${method}}; - return foo.method("foo") + ${func}("bar");`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } - - @TestCase("const meths: Method[]", "meths[0]", "s => s") - @TestCase("const meths: Method[]", "meths[0]", "(s => s)") - @TestCase("const meths: Method[]", "meths[0]", "function(s) { return s; }") - @TestCase("const meths: Method[]", "meths[0]", "(function(s) { return s; })") - @TestCase("let meths: Method[]; meths", "meths[0]", "s => s") - @TestCase("let meths: Method[]; meths", "meths[0]", "(s => s)") - @TestCase("let meths: Method[]; meths", "meths[0]", "function(s) { return s; }") - @TestCase("let meths: Method[]; meths", "meths[0]", "(function(s) { return s; })") - @TestCase("const [meth]: Method[]", "meth", "s => s") - @TestCase("const [meth]: Method[]", "meth", "(s => s)") - @TestCase("const [meth]: Method[]", "meth", "function(s) { return s; }") - @TestCase("const [meth]: Method[]", "meth", "(function(s) { return s; })") - @TestCase("let meth: Method; [meth]", "meth", "s => s") - @TestCase("let meth: Method; [meth]", "meth", "(s => s)") - @TestCase("let meth: Method; [meth]", "meth", "function(s) { return s; }") - @TestCase("let meth: Method; [meth]", "meth", "(function(s) { return s; })") - @Test("Function expression type inference in array") - public functionExpressionTypeInferenceInArray(assignTo: string, method: string, funcExp: string): void { - const code = - `interface Foo { - method(s: string): string; - } - interface Method { - (this: Foo, s: string): string; - } - ${assignTo} = [${funcExp}]; - const foo: Foo = {method: ${method}}; - return foo.method("foo");`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string", "s => s") - @TestCase("(this: any, s: string) => string", "s => s") - @TestCase("(s: string) => string", "s => s") - @TestCase("(this: void, s: string) => string", "function(s) { return s; }") - @TestCase("(this: any, s: string) => string", "function(s) { return s; }") - @TestCase("(s: string) => string", "function(s) { return s; }") - @Test("Function expression type inference in union") - public functionExpressionTypeInferenceInUnion(funcType: string, funcExp: string): void { - const code = - `type U = string | number | (${funcType}); - const u: U = ${funcExp}; - return (u as ${funcType})("foo");`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string", "s => s") - @TestCase("(this: any, s: string) => string", "s => s") - @TestCase("(s: string) => string", "s => s") - @TestCase("(this: void, s: string) => string", "function(s) { return s; }") - @TestCase("(this: any, s: string) => string", "function(s) { return s; }") - @TestCase("(s: string) => string", "function(s) { return s; }") - @Test("Function expression type inference in union tuple") - public functionExpressionTypeInferenceInUnionTuple(funcType: string, funcExp: string): void { - const code = - `interface I { callback: ${funcType}; } - let a: I[] | number = [{ callback: ${funcExp} }]; - return a[0].callback("foo");`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string", "s => s") - @TestCase("(this: any, s: string) => string", "s => s") - @TestCase("(s: string) => string", "s => s") - @TestCase("(this: void, s: string) => string", "function(s) { return s; }") - @TestCase("(this: any, s: string) => string", "function(s) { return s; }") - @TestCase("(s: string) => string", "function(s) { return s; }") - @Test("Function expression type inference in as cast") - public functionExpressionTypeInferenceInAsCast(funcType: string, funcExp: string): void { - const code = - `const fn: ${funcType} = (${funcExp}) as (${funcType}); - return fn("foo");`; - console.log(code); - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string", "s => s") - @TestCase("(this: any, s: string) => string", "s => s") - @TestCase("(s: string) => string", "s => s") - @TestCase("(this: void, s: string) => string", "function(s) { return s; }") - @TestCase("(this: any, s: string) => string", "function(s) { return s; }") - @TestCase("(s: string) => string", "function(s) { return s; }") - @Test("Function expression type inference in type assertion") - public functionExpressionTypeInferenceInTypeAssert(funcType: string, funcExp: string): void { - const code = - `const fn: ${funcType} = <${funcType}>(${funcExp}); - return fn("foo");`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @TestCase("(this: void, s: string) => string", "s => s") - @TestCase("(this: any, s: string) => string", "s => s") - @TestCase("(s: string) => string", "s => s") - @TestCase("(this: void, s: string) => string", "function(s) { return s; }") - @TestCase("(this: any, s: string) => string", "function(s) { return s; }") - @TestCase("(s: string) => string", "function(s) { return s; }") - @Test("Function expression type inference in constructor") - public functionExpresssionTypeInferenceInConstructor(funcType: string, funcExp: string): void { - const code = - `class C { - result: string; - constructor(fn: (s: string) => string) { this.result = fn("foo"); } + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test("Interface method assignment", () => { + const code = `class Foo { + method(s: string): string { return s + "+method"; } + lambdaProp: (s: string) => string = s => s + "+lambdaProp"; + } + interface IFoo { + method: (s: string) => string; + lambdaProp(s: string): string; + } + const foo: IFoo = new Foo(); + return foo.method("foo") + "|" + foo.lambdaProp("bar");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo+method|bar+lambdaProp"); +}); + +test("Valid function tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + function getTuple(): [number, Func] { return [1, s => s]; } + let [i, f]: [number, Func] = getTuple(); + return f("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Invalid function tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Meth]; + let [i, f]: [number, Func] = getTuple();`; + expect(() => util.transpileString(code)).toThrowExactError( + new TranspileError(TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined).message), + ); +}); + +test("Valid method tuple assignment", () => { + const code = `interface Foo { method(s: string): string; } + interface Meth { (this: Foo, s: string): string; } + let meth: Meth = s => s; + function getTuple(): [number, Meth] { return [1, meth]; } + let [i, f]: [number, Meth] = getTuple(); + let foo: Foo = {method: f}; + return foo.method("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Invalid method tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Func]; + let [i, f]: [number, Meth] = getTuple();`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedSelfFunctionConversion(undefined), + ); +}); + +test("Valid interface method assignment", () => { + const code = `interface A { fn(this: void, s: string): string; } + interface B { fn(this: void, s: string): string; } + const a: A = { fn(this: void, s) { return s; } }; + const b: B = a; + return b.fn("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Invalid interface method assignment", () => { + const code = `interface A { fn(s: string): string; } + interface B { fn(this: void, s: string): string; } + declare const a: A; + const b: B = a;`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"), + ); +}); + +test.each([ + { assignType: "(this: any, s: string) => string", args: ["foo"], expectResult: "foobar" }, + { assignType: "{(this: any, s: string): string}", args: ["foo"], expectResult: "foobar" }, + { + assignType: "(this: any, s1: string, s2: string) => string", + args: ["foo", "baz"], + expectResult: "foobaz", + }, + { + assignType: "{(this: any, s1: string, s2: string): string}", + args: ["foo", "baz"], + expectResult: "foobaz", + }, +])("Valid function overload assignment (%p)", ({ assignType, args, expectResult }) => { + const code = `interface O { + (s1: string, s2: string): string; + (s: string): string; + } + const o: O = (s1: string, s2?: string) => s1 + (s2 || "bar"); + let f: ${assignType} = o; + return f(${args.map(a => '"' + a + '"').join(", ")});`; + const result = util.transpileAndExecute(code); + expect(result).toBe(expectResult); +}); + +test.each([ + "(this: void, s: string) => string", + "(this: void, s1: string, s2: string) => string", + "{(this: void, s: string): string}", + "{(this: any, s1: string, s2: string): string}", +])("Invalid function overload assignment (%p)", assignType => { + const code = `interface O { + (this: any, s1: string, s2: string): string; + (this: void, s: string): string; + } + declare const o: O; + let f: ${assignType} = o;`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedOverloadAssignment(undefined), + ); +}); + +test.each(["noSelf", "noSelfInFile"])("noSelf function method argument (%p)", noSelfTag => { + const header = `/** @${noSelfTag} */ namespace NS { + export class C { + method(fn: (s: string) => string) { return fn("foo"); } } - const c = new C(s => s); - return c.result;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } - - @Test("String table access") - public stringTableAccess(assignType: string): void { - const code = `const dict : {[key:string]:any} = {}; - dict["a b"] = 3; - return dict["a b"];`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(3); + } + function foo(this: void, s: string) { return s; }`; + const code = `const c = new NS.C(); + return c.method(foo);`; + expect(util.transpileAndExecute(code, undefined, undefined, header, false)).toBe("foo"); +}); + +test.each([ + "(this: void, s: string) => string", + "(this: any, s: string) => string", + "(s: string) => string", +])("Function expression type inference in binary operator (%p)", funcType => { + const header = `declare const undefinedFunc: ${funcType};`; + const code = `let func: ${funcType} = s => s; + func = undefinedFunc || (s => s); + return func("foo");`; + expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); +}); + +test.each(["s => s", "(s => s)", "function(s) { return s; }", "(function(s) { return s; })"])( + "Function expression type inference in class (%p)", + funcExp => { + const code = `class Foo { + func: (this: void, s: string) => string = ${funcExp}; + method: (s: string) => string = ${funcExp}; + static staticFunc: (this: void, s: string) => string = ${funcExp}; + static staticMethod: (s: string) => string = ${funcExp}; } + const foo = new Foo(); + return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d");`; + expect(util.transpileAndExecute(code)).toBe("abcd"); + }, +); + +test.each([ + { assignTo: "const foo: Foo", funcExp: "s => s" }, + { assignTo: "const foo: Foo", funcExp: "(s => s)" }, + { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, + { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, + { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, + { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, + { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, + { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, +])("Function expression type inference in object literal (%p)", ({ assignTo, funcExp }) => { + const code = `interface Foo { + func(this: void, s: string): string; + method(this: this, s: string): string; + } + ${assignTo} = {func: ${funcExp}, method: ${funcExp}}; + return foo.method("foo") + foo.func("bar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test("Function expression type inference in object literal assigned to narrower type", () => { + const code = `let foo: {} = {bar: s => s}; + return (foo as {bar: (a: any) => any}).bar("foobar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test.each([ + { assignTo: "const foo: Foo", funcExp: "s => s" }, + { assignTo: "const foo: Foo", funcExp: "(s => s)" }, + { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, + { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, + { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, + { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, + { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, + { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, +])( + "Function expression type inference in object literal (generic key) (%p)", + ({ assignTo, funcExp }) => { + const code = `interface Foo { + [f: string]: (this: void, s: string) => string; + } + ${assignTo} = {func: ${funcExp}}; + return foo.func("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); + }, +); -} +test.each([ + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "s => s", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(s => s)", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "s => s", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(s => s)", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "s => s", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "(s => s)", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "s => s", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "(s => s)", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "(function(s) { return s; })", + }, +])("Function expression type inference in tuple (%p)", ({ assignTo, func, method, funcExp }) => { + const code = `interface Foo { + method(s: string): string; + } + interface Func { + (this: void, s: string): string; + } + interface Method { + (this: Foo, s: string): string; + } + ${assignTo} = [${funcExp}, ${funcExp}]; + const foo: Foo = {method: ${method}}; + return foo.method("foo") + ${func}("bar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test.each([ + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "s => s" }, + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "(s => s)" }, + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "function(s) { return s; }" }, + { + assignTo: "const meths: Method[]", + method: "meths[0]", + funcExp: "(function(s) { return s; })", + }, + { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "s => s" }, + { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "(s => s)" }, + { + assignTo: "let meths: Method[]; meths", + method: "meths[0]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let meths: Method[]; meths", + method: "meths[0]", + funcExp: "(function(s) { return s; })", + }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "s => s" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(s => s)" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "function(s) { return s; }" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(function(s) { return s; })" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "s => s" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "(s => s)" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "function(s) { return s; }" }, + { + assignTo: "let meth: Method; [meth]", + method: "meth", + funcExp: "(function(s) { return s; })", + }, +])("Function expression type inference in array (%p)", ({ assignTo, method, funcExp }) => { + const code = `interface Foo { + method(s: string): string; + } + interface Method { + (this: Foo, s: string): string; + } + ${assignTo} = [${funcExp}]; + const foo: Foo = {method: ${method}}; + return foo.method("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in union (%p)", ({ funcType, funcExp }) => { + const code = `type U = string | number | (${funcType}); + const u: U = ${funcExp}; + return (u as ${funcType})("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in union tuple (%p)", ({ funcType, funcExp }) => { + const code = `interface I { callback: ${funcType}; } + let a: I[] | number = [{ callback: ${funcExp} }]; + return a[0].callback("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in as cast (%p)", ({ funcType, funcExp }) => { + const code = `const fn: ${funcType} = (${funcExp}) as (${funcType}); + return fn("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in type assertion (%p)", ({ funcType, funcExp }) => { + const code = `const fn: ${funcType} = <${funcType}>(${funcExp}); + return fn("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in constructor (%p)", ({ funcType, funcExp }) => { + const code = `class C { + result: string; + constructor(fn: (s: string) => string) { this.result = fn("foo"); } + } + const c = new C(s => s); + return c.result;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test("String table access", () => { + const code = `const dict : {[key:string]:any} = {}; + dict["a b"] = 3; + return dict["a b"];`; + const result = util.transpileAndExecute(code); + expect(result).toBe(3); +}); diff --git a/test/unit/bindingpatterns.spec.ts b/test/unit/bindingpatterns.spec.ts index ad0e18638..e17d5de92 100644 --- a/test/unit/bindingpatterns.spec.ts +++ b/test/unit/bindingpatterns.spec.ts @@ -1,91 +1,92 @@ -import { Expect, Test, TestCase, TestCases } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; const testCases = [ - ["{x}", "{x: true}", "x"], - ["[x, y]", "[false, true]", "y"], - ["{x: [y, z]}", "{x: [false, true]}", "z"], - ["{x: [, z]}", "{x: [false, true]}", "z"], - ["{x: [{y}]}", "{x: [{y: true}]}", "y"], - ["[[y, z]]", "[[false, true]]", "z"], - ["{x, y}", "{x: false, y: true}", "y"], - ["{x: foo, y}", "{x: true, y: false}", "foo"], - ["{x: foo, y: bar}", "{x: false, y: true}", "bar"], - ["{x: {x, y}, z}", "{x: {x: true, y: false}, z: false}", "x"], - ["{x: {x, y}, z}", "{x: {x: false, y: true}, z: false}", "y"], - ["{x: {x, y}, z}", "{x: {x: false, y: false}, z: true}", "z"], + { bindingString: "{x}", objectString: "{x: true}", returnVariable: "x" }, + { bindingString: "[x, y]", objectString: "[false, true]", returnVariable: "y" }, + { bindingString: "{x: [y, z]}", objectString: "{x: [false, true]}", returnVariable: "z" }, + { bindingString: "{x: [, z]}", objectString: "{x: [false, true]}", returnVariable: "z" }, + { bindingString: "{x: [{y}]}", objectString: "{x: [{y: true}]}", returnVariable: "y" }, + { bindingString: "[[y, z]]", objectString: "[[false, true]]", returnVariable: "z" }, + { bindingString: "{x, y}", objectString: "{x: false, y: true}", returnVariable: "y" }, + { bindingString: "{x: foo, y}", objectString: "{x: true, y: false}", returnVariable: "foo" }, + { + bindingString: "{x: foo, y: bar}", + objectString: "{x: false, y: true}", + returnVariable: "bar", + }, + { + bindingString: "{x: {x, y}, z}", + objectString: "{x: {x: true, y: false}, z: false}", + returnVariable: "x", + }, + { + bindingString: "{x: {x, y}, z}", + objectString: "{x: {x: false, y: true}, z: false}", + returnVariable: "y", + }, + { + bindingString: "{x: {x, y}, z}", + objectString: "{x: {x: false, y: false}, z: true}", + returnVariable: "z", + }, ]; const testCasesDefault = [ - ["{x = true}", "{}", "x"], - ["{x, y = true}", "{x: false}", "y"], + { bindingString: "{x = true}", objectString: "{}", returnVariable: "x" }, + { bindingString: "{x, y = true}", objectString: "{x: false}", returnVariable: "y" }, ]; -export class BindingPatternTests { - - @TestCase("{x, y}, z", "{x: false, y: false}, true", "z") - @TestCase("{x, y}, {z}", "{x: false, y: false}, {z: true}", "z") - @TestCases(testCases) - @TestCases(testCasesDefault) - @Test("Object bindings in functions") - public tesBindingPatternParameters( - bindingString: string, - objectString: string, - returnVariable: string - ): void { - const result = util.transpileAndExecute(` - function test(${bindingString}) { - return ${returnVariable}; - } - return test(${objectString}); - `); - Expect(result).toBe(true); - } +test.each([ + { bindingString: "{x, y}, z", objectString: "{x: false, y: false}, true", returnVariable: "z" }, + { + bindingString: "{x, y}, {z}", + objectString: "{x: false, y: false}, {z: true}", + returnVariable: "z", + }, + ...testCases, + ...testCasesDefault, +])("Object bindings in functions (%p)", ({ bindingString, objectString, returnVariable }) => { + const result = util.transpileAndExecute(` + function test(${bindingString}) { + return ${returnVariable}; + } + return test(${objectString}); + `); + expect(result).toBe(true); +}); - @TestCases(testCases) - @TestCases(testCasesDefault) - public testBindingPatternDeclarations( - bindingString: string, - objectString: string, - returnVariable: string - ): void { +test.each([...testCases, ...testCasesDefault])( + "testBindingPatternDeclarations (%p)", + ({ bindingString, objectString, returnVariable }) => { const result = util.transpileAndExecute(` - let ${bindingString} = ${objectString}; - return ${returnVariable}; - `); - Expect(result).toBe(true); - } + let ${bindingString} = ${objectString}; + return ${returnVariable}; +`); + expect(result).toBe(true); + }, +); - @TestCases(testCases) - @TestCases(testCasesDefault) - public testBindingPatternExportDeclarations( - bindingString: string, - objectString: string, - returnVariable: string - ): void { +test.each([...testCases, ...testCasesDefault])( + "testBindingPatternExportDeclarations (%p)", + ({ bindingString, objectString, returnVariable }) => { const result = util.transpileExecuteAndReturnExport( `export const ${bindingString} = ${objectString};`, - returnVariable + returnVariable, ); - Expect(result).toBe(true); - } + expect(result).toBe(true); + }, +); - @TestCases(testCases) - @Test("Object bindings with call expressions") - public testBindingPatternCallExpressions( - bindingString: string, - objectString: string, - returnVariable: string - ): void { +test.each(testCases)( + "Object bindings with call expressions (%p)", + ({ bindingString, objectString, returnVariable }) => { const result = util.transpileAndExecute(` - function call() { - return ${objectString}; - } - let ${bindingString} = call(); - return ${returnVariable}; - `); - Expect(result).toBe(true); + function call() { + return ${objectString}; } - -} + let ${bindingString} = call(); + return ${returnVariable}; +`); + expect(result).toBe(true); + }, +); diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index 314e91853..b9c23546d 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -1,835 +1,742 @@ -import { Expect, Test, TestCase } from "alsatian"; - import * as ts from "typescript"; -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; -export class ClassTests { - - @Test("ClassFieldInitializer") - public classFieldInitializer(): void { - const result = util.transpileAndExecute( - `class a { - field: number = 4; - } - return new a().field;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassNumericLiteralFieldInitializer") - public classNumericLiteralFieldInitializer(): void { - const result = util.transpileAndExecute( - `class a { - 1: number = 4; - } - return new a()[1];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStringLiteralFieldInitializer") - public classStringLiteralFieldInitializer(): void { - const result = util.transpileAndExecute( - `class a { - "field": number = 4; - } - return new a()["field"];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassComputedFieldInitializer") - public classComputedFieldInitializer(): void { - const result = util.transpileAndExecute( - `const field: "field" = "field"; - class a { - [field]: number = 4; - } - return new a()[field];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassConstructor") - public classConstructor(): void { - const result = util.transpileAndExecute( - `class a { - field: number = 3; - constructor(n: number) { - this.field = n * 2; - } - } - return new a(4).field;` - ); - - // Assert - Expect(result).toBe(8); - } - - @Test("ClassConstructorAssignment") - public classConstructorAssignment(): void { - const result = util.transpileAndExecute( - `class a { constructor(public field: number) {} } - return new a(4).field;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassConstructorDefaultParameter") - public classConstructorDefaultParameter(): void { - const result = util.transpileAndExecute( - `class a { public field: number; constructor(f: number = 3) { this.field = f; } } - return new a().field;` - ); - - Expect(result).toBe(3); - } - - @Test("ClassConstructorAssignmentDefault") - public classConstructorAssignmentParameterDefault(): void { - const result = util.transpileAndExecute( - `class a { constructor(public field: number = 3) { } } - return new a().field;` - ); - - Expect(result).toBe(3); - } - - @Test("ClassNewNoBrackets") - public classNewNoBrackets(): void { - const result = util.transpileAndExecute( - `class a { - public field: number = 4; +test("ClassFieldInitializer", () => { + const result = util.transpileAndExecute( + `class a { + field: number = 4; + } + return new a().field;`, + ); + + expect(result).toBe(4); +}); + +test("ClassNumericLiteralFieldInitializer", () => { + const result = util.transpileAndExecute( + `class a { + 1: number = 4; + } + return new a()[1];`, + ); + + expect(result).toBe(4); +}); + +test("ClassStringLiteralFieldInitializer", () => { + const result = util.transpileAndExecute( + `class a { + "field": number = 4; + } + return new a()["field"];`, + ); + + expect(result).toBe(4); +}); + +test("ClassComputedFieldInitializer", () => { + const result = util.transpileAndExecute( + `const field: "field" = "field"; + class a { + [field]: number = 4; + } + return new a()[field];`, + ); + + expect(result).toBe(4); +}); + +test("ClassConstructor", () => { + const result = util.transpileAndExecute( + `class a { + field: number = 3; + constructor(n: number) { + this.field = n * 2; + } + } + return new a(4).field;`, + ); + + expect(result).toBe(8); +}); + +test("ClassConstructorAssignment", () => { + const result = util.transpileAndExecute( + `class a { constructor(public field: number) {} } + return new a(4).field;`, + ); + + expect(result).toBe(4); +}); + +test("ClassConstructorDefaultParameter", () => { + const result = util.transpileAndExecute( + `class a { public field: number; constructor(f: number = 3) { this.field = f; } } + return new a().field;`, + ); + + expect(result).toBe(3); +}); + +test("ClassConstructorAssignmentDefault", () => { + const result = util.transpileAndExecute( + `class a { constructor(public field: number = 3) { } } + return new a().field;`, + ); + + expect(result).toBe(3); +}); + +test("ClassNewNoBrackets", () => { + const result = util.transpileAndExecute( + `class a { + public field: number = 4; + constructor() {} + } + let inst = new a; + return inst.field;`, + ); + + expect(result).toBe(4); +}); + +test("ClassStaticFields", () => { + const result = util.transpileAndExecute( + `class a { static field: number = 4; } + return a.field;`, + ); + + expect(result).toBe(4); +}); + +test("ClassStaticNumericLiteralFields", () => { + const result = util.transpileAndExecute( + `class a { static 1: number = 4; } + return a[1];`, + ); + + expect(result).toBe(4); +}); + +test("ClassStaticStringLiteralFields", () => { + const result = util.transpileAndExecute( + `class a { static "field": number = 4; } + return a["field"];`, + ); + + expect(result).toBe(4); +}); + +test("ClassStaticComputedFields", () => { + const result = util.transpileAndExecute( + `const field: "field" = "field"; + class a { static [field]: number = 4; } + return a[field];`, + ); + + expect(result).toBe(4); +}); + +test("classExtends", () => { + const result = util.transpileAndExecute( + `class a { field: number = 4; } + class b extends a {} + return new b().field;`, + ); + + expect(result).toBe(4); +}); + +test("SubclassDefaultConstructor", () => { + const result = util.transpileAndExecute( + `class a { + field: number; + constructor(field: number) { + this.field = field; + } + } + class b extends a {} + return new b(10).field;`, + ); + + expect(result).toBe(10); +}); + +test("SubsubclassDefaultConstructor", () => { + const result = util.transpileAndExecute( + `class a { + field: number; + constructor(field: number) { + this.field = field; + } + } + class b extends a {} + class c extends b {} + return new c(10).field;`, + ); + + expect(result).toBe(10); +}); + +test("SubclassConstructor", () => { + const result = util.transpileAndExecute( + `class a { + field: number; + constructor(field: number) { + this.field = field; + } + } + class b extends a { + constructor(field: number) { + super(field + 1); + } + } + return new b(10).field;`, + ); + + expect(result).toBe(11); +}); + +test("classSuper", () => { + const result = util.transpileAndExecute( + `class a { + public field: number = 4; + constructor(n: number) { + this.field = n; + } + } + class b extends a { + constructor() { + super(5); + } + } + return new b().field;`, + ); + + expect(result).toBe(5); +}); + +test("classSuperSuper", () => { + const result = util.transpileAndExecute( + `class a { + public field: number = 4; + constructor(n: number) { + this.field = n; + } + } + class b extends a { + constructor(n: number) { + super(n * 2); + } + } + class c extends b { + constructor() { + super(5); + } + } + return new c().field;`, + ); + + expect(result).toBe(10); +}); + +test("classSuperSkip", () => { + const result = util.transpileAndExecute( + `class a { + public field: number = 4; + constructor(n: number) { + this.field = n; + } + } + class b extends a { + } + class c extends b { + constructor() { + super(5); + } + } + return new c().field;`, + ); + + expect(result).toBe(5); +}); + +test("renamedClassExtends", () => { + const result = util.transpileAndExecute( + `const b = new B(); + return b.value;`, + undefined, + undefined, + `namespace Classes { + export class Base { + public value: number; + constructor(){ this.value = 3; } + } + } + + const A = Classes.Base; + class B extends A { + constructor(){ super(); } + };`, + ); + + expect(result).toBe(3); +}); + +test("ClassMethodCall", () => { + const result = util.transpileAndExecute( + `class a { + public method(): number { + return 4; + } + } + let inst = new a(); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("ClassNumericLiteralMethodCall", () => { + const result = util.transpileAndExecute( + `class a { + public 1(): number { + return 4; + } + } + let inst = new a(); + return inst[1]();`, + ); + + expect(result).toBe(4); +}); + +test("ClassStringLiteralMethodCall", () => { + const result = util.transpileAndExecute( + `class a { + public "method"(): number { + return 4; + } + } + let inst = new a(); + return inst["method"]();`, + ); + + expect(result).toBe(4); +}); + +test("ClassComputedMethodCall", () => { + const result = util.transpileAndExecute( + `const method: "method" = "method"; + class a { + public [method](): number { + return 4; + } + } + let inst = new a(); + return inst[method]();`, + ); + + expect(result).toBe(4); +}); + +test("ClassToString", () => { + const result = util.transpileAndExecute( + `class a { + public toString(): string { + return "instance of a"; + } + } + let inst = new a(); + return inst.toString();`, + ); + + expect(result).toBe("instance of a"); +}); + +test("HasOwnProperty true", () => { + const result = util.transpileAndExecute( + `class a { + public test(): void { + } + } + let inst = new a(); + inst["prop"] = 17; + return inst.hasOwnProperty("prop");`, + ); + + expect(result).toBe(true); +}); + +test("HasOwnProperty false", () => { + const result = util.transpileAndExecute( + `class a { + public test(): void { + } + } + let inst = new a(); + inst["prop"] = 17; + return inst.hasOwnProperty("test");`, + ); + + expect(result).toBe(false); +}); + +test("CastClassMethodCall", () => { + const result = util.transpileAndExecute( + `interface result + { + val : number; + } + class a { + public method(out: result) { + out.val += 2; + } + } + let inst:any = new a(); + let result = {val : 0}; + (inst as a).method(result); + (inst as a).method(result); + return result.val;`, + ); + + expect(result).toBe(4); +}); + +test("ClassPropertyFunctionThis", () => { + const result = util.transpileAndExecute( + `class a { + constructor(private n: number) {} + public method: () => number = () => this.n; + } + let inst = new a(4); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("ClassInheritedMethodCall", () => { + const result = util.transpileAndExecute( + `class a { + public method(): number { + return 4; + } + } + class b extends a {} + let inst = new b(); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("ClassDoubleInheritedMethodCall", () => { + const result = util.transpileAndExecute( + `class a { + public method(): number { + return 4; + } + } + class b extends a {} + class c extends b {} + let inst = new c(); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("ClassInheritedMethodCall2", () => { + const result = util.transpileAndExecute( + `class a {} + class b extends a { + public method(): number { + return 4; + } + } + class c extends b {} + let inst = new c(); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("ClassMethodOverride", () => { + const result = util.transpileAndExecute( + `class a { + public method(): number { + return 2; + } + } + class b extends a { + public method(): number { + return 4; + } + } + let inst = new b(); + return inst.method();`, + ); + + expect(result).toBe(4); +}); + +test("methodDefaultParameters", () => { + const result = util.transpileAndExecute( + `class a { + public method(b: number, c: number = 5): number { + return b + c; + } + } + let inst = new a(); + return inst.method(4);`, + ); + + expect(result).toBe(9); +}); + +test("Class without name error", () => { + const transformer = util.makeTestTransformer(); + + expect(() => + transformer.transformClassDeclaration({} as ts.ClassDeclaration), + ).toThrowExactError(new Error("Class declarations must have a name.")); +}); + +test("CallSuperMethodNoArgs", () => { + const result = util.transpileAndExecute( + `class a { + a: number + constructor(n: number) { + this.a = n; + } + public method() { + return this.a; + } + } + class b extends a { + constructor(n: number) { + super(n); + } + public method() { + return super.method(); + } + } + let inst = new b(6); + return inst.method();`, + ); + + expect(result).toBe(6); +}); + +test("CallSuperMethodArgs", () => { + const result = util.transpileAndExecute( + `class a { + a: number + constructor(n: number) { + this.a = n; + } + public method(n: number) { + return this.a + n; + } + } + class b extends a { + constructor(n: number) { + super(n); + } + public method(n: number) { + return super.method(n); + } + } + let inst = new b(6); + return inst.method(4);`, + ); + + expect(result).toBe(10); +}); + +test("CallSuperExpressionMethod", () => { + const result = util.transpileAndExecute( + `let i = 0; + function make() { + const j = i++; + return class { constructor() {} - } - let inst = new a; - return inst.field;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStaticFields") - public classStaticFields(): void { - const result = util.transpileAndExecute( - `class a { static field: number = 4; } - return a.field;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStaticNumericLiteralFields") - public classStaticNumericLiteralFields(): void { - const result = util.transpileAndExecute( - `class a { static 1: number = 4; } - return a[1];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStaticStringLiteralFields") - public classStaticStringLiteralFields(): void { - const result = util.transpileAndExecute( - `class a { static "field": number = 4; } - return a["field"];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStaticComputedFields") - public classStaticComputedFields(): void { - const result = util.transpileAndExecute( - `const field: "field" = "field"; - class a { static [field]: number = 4; } - return a[field];` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("classExtends") - public classExtends(): void { - const result = util.transpileAndExecute( - `class a { field: number = 4; } - class b extends a {} - return new b().field;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("SubclassDefaultConstructor") - public subclassDefaultConstructor(): void { - const result = util.transpileAndExecute( - `class a { - field: number; - constructor(field: number) { - this.field = field; - } - } - class b extends a {} - return new b(10).field;` - ); - - Expect(result).toBe(10); - } - - @Test("SubsubclassDefaultConstructor") - public subsubclassDefaultConstructor(): void { - const result = util.transpileAndExecute( - `class a { - field: number; - constructor(field: number) { - this.field = field; - } - } - class b extends a {} - class c extends b {} - return new c(10).field;` - ); - - Expect(result).toBe(10); - } - - @Test("SubclassConstructor") - public subclassConstructor(): void { - const result = util.transpileAndExecute( - `class a { - field: number; - constructor(field: number) { - this.field = field; - } - } - class b extends a { - constructor(field: number) { - super(field + 1); - } - } - return new b(10).field;` - ); - - Expect(result).toBe(11); - } - - @Test("classSuper") - public classSuper(): void { - const result = util.transpileAndExecute( - `class a { - public field: number = 4; - constructor(n: number) { - this.field = n; - } - } - class b extends a { - constructor() { - super(5); - } - } - return new b().field;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("classSuperSuper") - public classSuperSuper(): void { - const result = util.transpileAndExecute( - `class a { - public field: number = 4; - constructor(n: number) { - this.field = n; - } - } - class b extends a { - constructor(n: number) { - super(n * 2); - } - } - class c extends b { - constructor() { - super(5); - } - } - return new c().field;` - ); - - // Assert - Expect(result).toBe(10); - } - - @Test("classSuperSkip") - public classSuperSkip(): void { - const result = util.transpileAndExecute( - `class a { - public field: number = 4; - constructor(n: number) { - this.field = n; - } - } - class b extends a { - } - class c extends b { - constructor() { - super(5); - } - } - return new c().field;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("renamedClassExtends") - public renamedClassExtends(): void - { - const result = util.transpileAndExecute( - `const b = new B(); - return b.value;`, - undefined, undefined, - `namespace Classes { - export class Base { - public value: number; - constructor(){ this.value = 3; } - } - } - - const A = Classes.Base; - class B extends A { - constructor(){ super(); } - };` - ); - - // Assert - Expect(result).toBe(3); - } - - @Test("ClassMethodCall") - public classMethodCall(): void { - const result = util.transpileAndExecute( - `class a { - public method(): number { - return 4; - } - } - let inst = new a(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassNumericLiteralMethodCall") - public classNumericLiteralMethodCall(): void { - const result = util.transpileAndExecute( - `class a { - public 1(): number { - return 4; - } - } - let inst = new a(); - return inst[1]();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassStringLiteralMethodCall") - public classStringLiteralMethodCall(): void { - const result = util.transpileAndExecute( - `class a { - public "method"(): number { - return 4; - } - } - let inst = new a(); - return inst["method"]();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassComputedMethodCall") - public classComputedMethodCall(): void { - const result = util.transpileAndExecute( - `const method: "method" = "method"; - class a { - public [method](): number { - return 4; - } - } - let inst = new a(); - return inst[method]();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassToString") - public classToString(): void { - const result = util.transpileAndExecute( - `class a { - public toString(): string { - return "instance of a"; - } - } - let inst = new a(); - return inst.toString();` - ); - - // Assert - Expect(result).toBe("instance of a"); - } - @Test("HasOwnProperty true") - public hasOwnProperty1(): void { - const result = util.transpileAndExecute( - `class a { - public test(): void { - } - } - let inst = new a(); - inst["prop"] = 17; - return inst.hasOwnProperty("prop");` - ); - - // Assert - Expect(result).toBe(true); - } - @Test("HasOwnProperty false") - public hasOwnProperty2(): void { - const result = util.transpileAndExecute( - `class a { - public test(): void { - } - } - let inst = new a(); - inst["prop"] = 17; - return inst.hasOwnProperty("test");` - ); - - // Assert - Expect(result).toBe(false); - } - @Test("CastClassMethodCall") - public extraParenthesisAssignment(): void { - const result = util.transpileAndExecute( - `interface result - { - val : number; - } - class a { - public method(out: result) { - out.val += 2; - } - } - let inst:any = new a(); - let result = {val : 0}; - (inst as a).method(result); - (inst as a).method(result); - return result.val;` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassPropertyFunctionThis") - public classPropertyFunctionThis(): void { - const result = util.transpileAndExecute( - `class a { - constructor(private n: number) {} - public method: () => number = () => this.n; - } - let inst = new a(4); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassInheritedMethodCall") - public classInheritedMethodCall(): void { - const result = util.transpileAndExecute( - `class a { - public method(): number { - return 4; - } - } - class b extends a {} - let inst = new b(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassDoubleInheritedMethodCall") - public classDoubleInheritedMethodCall(): void { - const result = util.transpileAndExecute( - `class a { - public method(): number { - return 4; - } - } - class b extends a {} - class c extends b {} - let inst = new c(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassInheritedMethodCall2") - public classInheritedMethodCall2(): void { - const result = util.transpileAndExecute( - `class a {} - class b extends a { - public method(): number { - return 4; - } - } - class c extends b {} - let inst = new c(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("ClassMethodOverride") - public classMethodOverride(): void { - const result = util.transpileAndExecute( - `class a { - public method(): number { - return 2; - } - } - class b extends a { - public method(): number { - return 4; - } - } - let inst = new b(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(4); - } - - @Test("methodDefaultParameters") - public methodInheritedParameters(): void { - const result = util.transpileAndExecute( - `class a { - public method(b: number, c: number = 5): number { - return b + c; - } - } - let inst = new a(); - return inst.method(4);` - ); - - // Assert - Expect(result).toBe(9); - } - - @Test("Class without name error") - public classWithoutNameError(): void { - const transformer = util.makeTestTransformer(); - - Expect(() => transformer.transformClassDeclaration({} as ts.ClassDeclaration)) - .toThrowError(Error, "Class declarations must have a name."); - } - - @Test("CallSuperMethodNoArgs") - public callSuperMethodNoArgs(): void { - const result = util.transpileAndExecute( - `class a { - a: number - constructor(n: number) { - this.a = n; - } - public method() { - return this.a; - } - } - class b extends a { - constructor(n: number) { - super(n); - } - public method() { - return super.method(); - } - } - let inst = new b(6); - return inst.method();` - ); - - // Assert - Expect(result).toBe(6); - } - - @Test("CallSuperMethodArgs") - public callSuperMethodArgs(): void { - const result = util.transpileAndExecute( - `class a { - a: number - constructor(n: number) { - this.a = n; - } - public method(n: number) { - return this.a + n; - } - } - class b extends a { - constructor(n: number) { - super(n); - } - public method(n: number) { - return super.method(n); - } - } - let inst = new b(6); - return inst.method(4);` - ); - - // Assert - Expect(result).toBe(10); - } - - @Test("CallSuperExpressionMethod") - public callSuperExpressionMethod(): void { - const result = util.transpileAndExecute( - `let i = 0; - function make() { - const j = i++; - return class { - constructor() {} - method() {} - }; - } - class B extends make() { - constructor() { super(); } - method() { super.method(); } - } - const inst = new B(); - inst.method(); - inst.method(); - inst.method(); - return i;` - ); - - // Assert - Expect(result).toBe(1); - } - - @Test("CallSuperSuperMethod") - public callSuperSuperMethod(): void { - const result = util.transpileAndExecute( - `class a { - a: number - constructor(n: number) { - this.a = n; - } - public method() { - return this.a; - } - } - class b extends a { - constructor(n: number) { - super(n); - } - public method() { - return super.method(); - } - } - class c extends b { - constructor(n: number) { - super(n); - } - public method() { - return super.method(); - } - } - let inst = new c(6); - return inst.method();` - ); - - // Assert - Expect(result).toBe(6); - } - - @Test("classExpression") - public classExpression(): void { - const result = util.transpileAndExecute( - `class a { - public method() { - return "instance of a"; - } - } - const b = class extends a { - public method() { - return "instance of b"; - } - } - let inst = new b(); - return inst.method();` - ); - - // Assert - Expect(result).toBe("instance of b"); - } - - @Test("Named Class Expression") - public namedClassExpression(): void { - const result = util.transpileAndExecute( - `const a = class MyClass { - public method() { - return "foo"; - } - } - let inst = new a(); - return inst.method();` - ); - - // Assert - Expect(result).toBe("foo"); - } - - @Test("classExpressionBaseClassMethod") - public classExpressionBaseClassMethod(): void { - const result = util.transpileAndExecute( - `class a { - public method() { - return 42; - } - } - const b = class extends a { - } - let inst = new b(); - return inst.method();` - ); - - // Assert - Expect(result).toBe(42); - } - - @Test("Class Method Runtime Override") - public classMethodRuntimeOverride(): void { - const result = util.transpileAndExecute( - `class MyClass { - method(): number { - return 4; - } - } - - let inst = new MyClass(); - inst.method = () => { - return 8; - } - return inst.method();` - ); - - Expect(result).toBe(8); - } - - @Test("Exported class super call") - public exportedClassSuperCall(): void { - const code = - `export class Foo { - prop: string; - constructor(prop: string) { this.prop = prop; } - } - export class Bar extends Foo { - constructor() { - super("bar"); - } - } - export const baz = (new Bar()).prop;`; - Expect(util.transpileExecuteAndReturnExport(code, "baz")).toBe("bar"); - } - - @TestCase("(new Foo())", "foo") - @TestCase("Foo", "bar") - @Test("Class method name collision") - public classMethodNameCollisiom(input: string, expectResult: string): void { - const code = - `class Foo { - public method() { return "foo"; } - public static method() { return "bar"; } - } - return ${input}.method();`; - Expect(util.transpileAndExecute(code)).toBe(expectResult); - } - - @TestCase("extension") - @TestCase("metaExtension") - @Test("Class extends extension") - public classExtendsExtension(extensionType: string): void { - const code = - `declare class A {} - /** @${extensionType} **/ - class B extends A {} - class C extends B {}`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - "Cannot extend classes with decorator '@extension' or '@metaExtension'." - ); - } - - @TestCase("extension") - @TestCase("metaExtension") - @Test("Class construct extension") - public classConstructExtension(extensionType: string): void { - const code = - `declare class A {} - /** @${extensionType} **/ - class B extends A {} - const b = new B();`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - "Cannot construct classes with decorator '@extension' or '@metaExtension'." - ); - } - - @Test("Class static instance of self") - public classStaticInstanceOfSelf(): void { - const code = - `class Foo { - bar = "foobar"; - static instance = new Foo(); - } - return Foo.instance.bar;`; - Expect(util.transpileAndExecute(code)).toBe("foobar"); - } -} + method() {} + }; + } + class B extends make() { + constructor() { super(); } + method() { super.method(); } + } + const inst = new B(); + inst.method(); + inst.method(); + inst.method(); + return i;`, + ); + + expect(result).toBe(1); +}); + +test("CallSuperSuperMethod", () => { + const result = util.transpileAndExecute( + `class a { + a: number + constructor(n: number) { + this.a = n; + } + public method() { + return this.a; + } + } + class b extends a { + constructor(n: number) { + super(n); + } + public method() { + return super.method(); + } + } + class c extends b { + constructor(n: number) { + super(n); + } + public method() { + return super.method(); + } + } + let inst = new c(6); + return inst.method();`, + ); + + expect(result).toBe(6); +}); + +test("classExpression", () => { + const result = util.transpileAndExecute( + `class a { + public method() { + return "instance of a"; + } + } + const b = class extends a { + public method() { + return "instance of b"; + } + } + let inst = new b(); + return inst.method();`, + ); + + expect(result).toBe("instance of b"); +}); + +test("Named Class Expression", () => { + const result = util.transpileAndExecute( + `const a = class MyClass { + public method() { + return "foo"; + } + } + let inst = new a(); + return inst.method();`, + ); + + expect(result).toBe("foo"); +}); + +test("classExpressionBaseClassMethod", () => { + const result = util.transpileAndExecute( + `class a { + public method() { + return 42; + } + } + const b = class extends a { + } + let inst = new b(); + return inst.method();`, + ); + + expect(result).toBe(42); +}); + +test("Class Method Runtime Override", () => { + const result = util.transpileAndExecute( + `class MyClass { + method(): number { + return 4; + } + } + + let inst = new MyClass(); + inst.method = () => { + return 8; + } + return inst.method();`, + ); + + expect(result).toBe(8); +}); + +test("Exported class super call", () => { + const code = `export class Foo { + prop: string; + constructor(prop: string) { this.prop = prop; } + } + export class Bar extends Foo { + constructor() { + super("bar"); + } + } + export const baz = (new Bar()).prop;`; + expect(util.transpileExecuteAndReturnExport(code, "baz")).toBe("bar"); +}); + +test.each([{ input: "(new Foo())", expectResult: "foo" }, { input: "Foo", expectResult: "bar" }])( + "Class method name collision (%p)", + ({ input, expectResult }) => { + const code = `class Foo { + public method() { return "foo"; } + public static method() { return "bar"; } + } + return ${input}.method();`; + expect(util.transpileAndExecute(code)).toBe(expectResult); + }, +); + +test.each(["extension", "metaExtension"])("Class extends extension (%p)", extensionType => { + const code = `declare class A {} + /** @${extensionType} **/ + class B extends A {} + class C extends B {}`; + expect(() => util.transpileString(code)).toThrowExactError( + new TranspileError( + "Cannot extend classes with decorator '@extension' or '@metaExtension'.", + ), + ); +}); + +test.each(["extension", "metaExtension"])("Class construct extension (%p)", extensionType => { + const code = `declare class A {} + /** @${extensionType} **/ + class B extends A {} + const b = new B();`; + expect(() => util.transpileString(code)).toThrowExactError( + new TranspileError( + "Cannot construct classes with decorator '@extension' or '@metaExtension'.", + ), + ); +}); + +test("Class static instance of self", () => { + const code = `class Foo { + bar = "foobar"; + static instance = new Foo(); + } + return Foo.instance.bar;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); diff --git a/test/unit/commandLineParser.spec.ts b/test/unit/commandLineParser.spec.ts index 000cdd4b3..8ec339310 100644 --- a/test/unit/commandLineParser.spec.ts +++ b/test/unit/commandLineParser.spec.ts @@ -1,245 +1,235 @@ -import { Expect, Test, TestCase } from "alsatian"; - import { findConfigFile, parseCommandLine, parseTsConfigString } from "../../src/CommandLineParser"; import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; -export class CommandLineParserTests -{ - @TestCase([""], LuaLibImportKind.Inline) - @TestCase(["--luaLibImport", "none"], LuaLibImportKind.None) - @TestCase(["--luaLibImport", "always"], LuaLibImportKind.Always) - @TestCase(["--luaLibImport", "inline"], LuaLibImportKind.Inline) - @TestCase(["--luaLibImport", "require"], LuaLibImportKind.Require) - @Test("CLI parser luaLibImportKind") - public cliParserLuaLibImportKind(args: string[], expected: LuaLibImportKind): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.luaLibImport).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @Test("CLI parser invalid luaLibImportKind") - public cliParserInvalidLuaLibImportKind(): void { - const result = parseCommandLine(["--luaLibImport", "invalid"]); - Expect(result.isValid).toBe(false); - } - - @TestCase([""], LuaTarget.LuaJIT) - @TestCase(["--luaTarget", "5.1"], LuaTarget.Lua51) - @TestCase(["--luaTarget", "5.2"], LuaTarget.Lua52) - @TestCase(["--luaTarget", "jit"], LuaTarget.LuaJIT) - @TestCase(["--luaTarget", "JIT"], LuaTarget.LuaJIT) - @TestCase(["--luaTarget", "5.3"], LuaTarget.Lua53) - @Test("CLI parser luaTarget") - public cliParserLuaTarget(args: string[], expected: LuaTarget): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.luaTarget).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @TestCase(["-lt", "5.1"], LuaTarget.Lua51) - @TestCase(["-lt", "5.2"], LuaTarget.Lua52) - @TestCase(["-lt", "jit"], LuaTarget.LuaJIT) - @TestCase(["-lt", "JIT"], LuaTarget.LuaJIT) - @TestCase(["-lt", "5.3"], LuaTarget.Lua53) - @Test("CLI parser luaTarget") - public cliParserLuaTargetAlias(args: string[], expected: LuaTarget): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.luaTarget).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @Test("CLI parser invalid luaTarget") - public cliParserInvalidLuaTarget(): void { - const result = parseCommandLine(["--luatTarget", "invalid"]); - Expect(result.isValid).toBe(false); - } - - @TestCase([""], false) - @TestCase(["--noHeader", "true"], true) - @TestCase(["--noHeader", "false"], false) - @TestCase(["--noHeader"], true) - @TestCase(["--noHeader", "--noHoisting"], true) - @Test("CLI parser noHeader") - public cliParserNoHeader(args: string[], expected: boolean): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.noHeader).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @TestCase([""], false) - @TestCase(["--noHoisting", "true"], true) - @TestCase(["--noHoisting", "false"], false) - @TestCase(["--noHoisting"], true) - @TestCase(["--noHoisting", "--noHeader"], true) - @Test("CLI parser noHoisting") - public cliParserNoHoisting(args: string[], expected: boolean): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.noHoisting).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @TestCase([""], false) - @TestCase(["--project", "tsconfig.json"], true) - @TestCase(["-p", "tsconfig.json"], true) - @Test("CLI parser project") - public cliParserProject(args: string[], expected: boolean): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.project !== undefined).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @Test("CLI Parser Multiple Options") - public cliParserMultipleOptions(): void { - const commandLine = "--project tsconfig.json --noHeader --noHoisting -lt 5.3"; - const result = parseCommandLine(commandLine.split(" ")); - - if (result.isValid === true) { - Expect(result.result.options.project).toBeDefined(); - Expect(result.result.options.noHeader).toBe(true); - Expect(result.result.options.noHoisting).toBe(true); - Expect(result.result.options.luaTarget).toBe(LuaTarget.Lua53); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @TestCase([""], false) - @TestCase(["--help"], true) - @TestCase(["-h"], true) - @Test("CLI parser project") - public cliParserHelp(args: string[], expected: boolean): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.help === true).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @TestCase([""], false) - @TestCase(["--version"], true) - @TestCase(["-v"], true) - @Test("CLI parser project") - public cliParserVersion(args: string[], expected: boolean): void { - const result = parseCommandLine(args); - if (result.isValid === true) { - Expect(result.result.options.version === true).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } - - @Test("defaultOption") - @TestCase("luaTarget", LuaTarget.LuaJIT) - @TestCase("noHeader", false) - @TestCase("luaLibImport", "inline") - @TestCase("rootDir", process.cwd()) - @TestCase("outDir", process.cwd()) - public defaultOptions(option: any, expected: any): void { - const parsedCommandLine = parseCommandLine([]); - if (parsedCommandLine.isValid) { - Expect(expected).toBe(parsedCommandLine.result.options[option]); - } else { - Expect(parsedCommandLine.isValid).toBeTruthy(); - } - } - - @Test("ValidLuaTarget") - public validLuaTarget(): void { - const parsedCommandLine = parseCommandLine(['--luaTarget', '5.3']); - if (parsedCommandLine.isValid) { - Expect(parsedCommandLine.result.options["luaTarget"]).toBe("5.3"); - } else { - Expect(parsedCommandLine.isValid).toBeTruthy(); - } - } - - @Test("InvalidLuaTarget") - public invalidLuaTarget(): void { - // Don't check error message because the yargs library messes the message up. - const result = parseCommandLine(['--luaTarget', '42']); - Expect(result.isValid).toBe(false); - } - - @Test("InvalidArgumentTSTL") - public invalidArgument(): void { - // Don't check error message because the yargs library messes the message up. - const result = parseCommandLine(['--invalidTarget', 'test']); - Expect(result.isValid).toBe(false); - } - - @Test("outDir") - public outDir(): void { - const parsedCommandLine = parseCommandLine(['--outDir', './test']); - - if (parsedCommandLine.isValid) { - Expect(parsedCommandLine.result.options['outDir']).toBe('./test'); - } else { - Expect(parsedCommandLine.isValid).toBeTruthy(); - } - } - - @Test("rootDir") - public rootDir(): void { - const parsedCommandLine = parseCommandLine(['--rootDir', './test']); - - if (parsedCommandLine.isValid) { - Expect(parsedCommandLine.result.options['rootDir']).toBe('./test'); - Expect(parsedCommandLine.result.options['outDir']).toBe('./test'); - } else { - Expect(parsedCommandLine.isValid).toBeTruthy(); - } - } - - @Test("outDirAndRooDir") - public outDirAndRooDir(): void { - const parsedCommandLine = parseCommandLine(['--outDir', './testOut', '--rootDir', './testRoot']); - - if (parsedCommandLine.isValid) { - Expect(parsedCommandLine.result.options['outDir']).toBe('./testOut'); - Expect(parsedCommandLine.result.options['rootDir']).toBe('./testRoot'); - } else { - Expect(parsedCommandLine.isValid).toBeTruthy(); - } - } - - @Test("Find config no path") - public findConfigNoPath(): void { - const result = findConfigFile({ options: {}, fileNames: [], errors: [] }); - Expect(result.isValid).toBe(false); - } - - @TestCase("{}", undefined) - @TestCase(`{ noHeader: true }`, true) - @TestCase(`{ noHeader: "true" }`, true) - @TestCase(`{ tstl: { noHeader: true } }`, true) - @TestCase(`{ tstl: { noHeader: "true" } }`, true) - @Test("TsConfig noHeader") - public tsConfigNoHeader(tsConfig: string, expected: boolean): void { - const result = parseTsConfigString(tsConfig, ""); - - if (result.isValid) { - Expect(result.result.options.noHeader).toBe(expected); - } else { - Expect(result.isValid).toBeTruthy(); - } - } -} +test.each([ + { args: [""], expected: LuaLibImportKind.Inline }, + { args: ["--luaLibImport", "none"], expected: LuaLibImportKind.None }, + { args: ["--luaLibImport", "always"], expected: LuaLibImportKind.Always }, + { args: ["--luaLibImport", "inline"], expected: LuaLibImportKind.Inline }, + { args: ["--luaLibImport", "require"], expected: LuaLibImportKind.Require }, +])("CLI parser luaLibImportKind (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.luaLibImport).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test("CLI parser invalid luaLibImportKind", () => { + const result = parseCommandLine(["--luaLibImport", "invalid"]); + expect(result.isValid).toBe(false); +}); + +test.each([ + { args: [""], expected: LuaTarget.LuaJIT }, + { args: ["--luaTarget", "5.1"], expected: LuaTarget.Lua51 }, + { args: ["--luaTarget", "5.2"], expected: LuaTarget.Lua52 }, + { args: ["--luaTarget", "jit"], expected: LuaTarget.LuaJIT }, + { args: ["--luaTarget", "JIT"], expected: LuaTarget.LuaJIT }, + { args: ["--luaTarget", "5.3"], expected: LuaTarget.Lua53 }, +])("CLI parser luaTarget (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.luaTarget).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { args: ["-lt", "5.1"], expected: LuaTarget.Lua51 }, + { args: ["-lt", "5.2"], expected: LuaTarget.Lua52 }, + { args: ["-lt", "jit"], expected: LuaTarget.LuaJIT }, + { args: ["-lt", "JIT"], expected: LuaTarget.LuaJIT }, + { args: ["-lt", "5.3"], expected: LuaTarget.Lua53 }, +])("CLI parser luaTarget (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.luaTarget).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test("CLI parser invalid luaTarget", () => { + const result = parseCommandLine(["--luatTarget", "invalid"]); + expect(result.isValid).toBe(false); +}); + +test.each([ + { args: [""], expected: false }, + { args: ["--noHeader", "true"], expected: true }, + { args: ["--noHeader", "false"], expected: false }, + { args: ["--noHeader"], expected: true }, + { args: ["--noHeader", "--noHoisting"], expected: true }, +])("CLI parser noHeader (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.noHeader).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { args: [""], expected: false }, + { args: ["--noHoisting", "true"], expected: true }, + { args: ["--noHoisting", "false"], expected: false }, + { args: ["--noHoisting"], expected: true }, + { args: ["--noHoisting", "--noHeader"], expected: true }, +])("CLI parser noHoisting (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.noHoisting).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { args: [""], expected: false }, + { args: ["--project", "tsconfig.json"], expected: true }, + { args: ["-p", "tsconfig.json"], expected: true }, +])("CLI parser project (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.project !== undefined).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test("CLI Parser Multiple Options", () => { + const commandLine = "--project tsconfig.json --noHeader --noHoisting -lt 5.3"; + const result = parseCommandLine(commandLine.split(" ")); + + if (result.isValid === true) { + expect(result.result.options.project).toBeDefined(); + expect(result.result.options.noHeader).toBe(true); + expect(result.result.options.noHoisting).toBe(true); + expect(result.result.options.luaTarget).toBe(LuaTarget.Lua53); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { args: [""], expected: false }, + { args: ["--help"], expected: true }, + { args: ["-h"], expected: true }, +])("CLI parser project (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.help === true).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { args: [""], expected: false }, + { args: ["--version"], expected: true }, + { args: ["-v"], expected: true }, +])("CLI parser project (%p)", ({ args, expected }) => { + const result = parseCommandLine(args); + if (result.isValid === true) { + expect(result.result.options.version === true).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); + +test.each([ + { option: "luaTarget", expected: LuaTarget.LuaJIT }, + { option: "noHeader", expected: false }, + { option: "luaLibImport", expected: "inline" }, + { option: "rootDir", expected: process.cwd() }, + { option: "outDir", expected: process.cwd() }, +])("defaultOption (%p)", ({ option, expected }) => { + const parsedCommandLine = parseCommandLine([]); + if (parsedCommandLine.isValid) { + expect(expected).toBe(parsedCommandLine.result.options[option]); + } else { + expect(parsedCommandLine.isValid).toBeTruthy(); + } +}); + +test("ValidLuaTarget", () => { + const parsedCommandLine = parseCommandLine(["--luaTarget", "5.3"]); + if (parsedCommandLine.isValid) { + expect(parsedCommandLine.result.options["luaTarget"]).toBe("5.3"); + } else { + expect(parsedCommandLine.isValid).toBeTruthy(); + } +}); + +test("InvalidLuaTarget", () => { + // Don't check error message because the yargs library messes the message up. + const result = parseCommandLine(["--luaTarget", "42"]); + expect(result.isValid).toBe(false); +}); + +test("InvalidArgumentTSTL", () => { + // Don't check error message because the yargs library messes the message up. + const result = parseCommandLine(["--invalidTarget", "test"]); + expect(result.isValid).toBe(false); +}); + +test("outDir", () => { + const parsedCommandLine = parseCommandLine(["--outDir", "./test"]); + + if (parsedCommandLine.isValid) { + expect(parsedCommandLine.result.options["outDir"]).toBe("./test"); + } else { + expect(parsedCommandLine.isValid).toBeTruthy(); + } +}); + +test("rootDir", () => { + const parsedCommandLine = parseCommandLine(["--rootDir", "./test"]); + + if (parsedCommandLine.isValid) { + expect(parsedCommandLine.result.options["rootDir"]).toBe("./test"); + expect(parsedCommandLine.result.options["outDir"]).toBe("./test"); + } else { + expect(parsedCommandLine.isValid).toBeTruthy(); + } +}); + +test("outDirAndRooDir", () => { + const parsedCommandLine = parseCommandLine([ + "--outDir", + "./testOut", + "--rootDir", + "./testRoot", + ]); + + if (parsedCommandLine.isValid) { + expect(parsedCommandLine.result.options["outDir"]).toBe("./testOut"); + expect(parsedCommandLine.result.options["rootDir"]).toBe("./testRoot"); + } else { + expect(parsedCommandLine.isValid).toBeTruthy(); + } +}); + +test("Find config no path", () => { + const result = findConfigFile({ options: {}, fileNames: [], errors: [] }); + expect(result.isValid).toBe(false); +}); + +test.each([ + { tsConfig: "{}" }, + { tsConfig: `{ noHeader: true }`, expected: true }, + { tsConfig: `{ noHeader: "true" }`, expected: true }, + { tsConfig: `{ tstl: { noHeader: true } }`, expected: true }, + { tsConfig: `{ tstl: { noHeader: "true" } }`, expected: true }, +])("TsConfig noHeader (%p)", ({ tsConfig, expected }) => { + const result = parseTsConfigString(tsConfig, ""); + + if (result.isValid) { + expect(result.result.options.noHeader).toBe(expected); + } else { + expect(result.isValid).toBeTruthy(); + } +}); diff --git a/test/unit/compiler/configuration/mixed/index.spec.ts b/test/unit/compiler/configuration/mixed/index.spec.ts index 179a8ac77..0ff2cec88 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -1,4 +1,3 @@ -import { Expect, Test } from "alsatian"; import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; @@ -6,41 +5,36 @@ import * as ts from "typescript"; import { CompilerOptions, LuaLibImportKind } from "../../../../../src/CompilerOptions"; import { parseCommandLine } from "../../../../../src/CommandLineParser"; -export class MixedConfigurationTests -{ - @Test("tsconfig.json mixed with cmd line args") - public tsconfigMixedWithCmdLineArgs(): void { - const rootPath = __dirname; - const tsConfigPath = path.join(rootPath, "project-tsconfig.json"); - const expectedTsConfig = ts.parseJsonConfigFileContent( - ts.parseConfigFileTextToJson(tsConfigPath, fs.readFileSync(tsConfigPath).toString()).config, - ts.sys, - path.dirname(tsConfigPath) - ); +test("tsconfig.json mixed with cmd line args", () => { + const rootPath = __dirname; + const tsConfigPath = path.join(rootPath, "project-tsconfig.json"); + const expectedTsConfig = ts.parseJsonConfigFileContent( + ts.parseConfigFileTextToJson(tsConfigPath, fs.readFileSync(tsConfigPath).toString()).config, + ts.sys, + path.dirname(tsConfigPath), + ); - const parsedArgs = parseCommandLine([ - "-p", - `"${tsConfigPath}"`, - "--luaLibImport", - LuaLibImportKind.Inline, - `${path.join(rootPath, "test.ts")}`, - ]); + const parsedArgs = parseCommandLine([ + "-p", + `"${tsConfigPath}"`, + "--luaLibImport", + LuaLibImportKind.Inline, + `${path.join(rootPath, "test.ts")}`, + ]); - if (parsedArgs.isValid === true) - { - Expect(parsedArgs.result.options).toEqual({ - ...expectedTsConfig.options, - // Overridden by cmd args (set to "none" in project-tsconfig.json) - luaLibImport: LuaLibImportKind.Inline, - // Only set in tsconfig, TSTL default is "JIT" - luaTarget: "5.1", - // Only present in TSTL dfaults - noHeader: false, - project: tsConfigPath, - noHoisting: false, - } as CompilerOptions); - } else { - Expect(parsedArgs.isValid).toBeTruthy(); - } + if (parsedArgs.isValid === true) { + expect(parsedArgs.result.options).toEqual({ + ...expectedTsConfig.options, + // Overridden by cmd args (set to "none" in project-tsconfig.json) + luaLibImport: LuaLibImportKind.Inline, + // Only set in tsconfig, TSTL default is "JIT" + luaTarget: "5.1", + // Only present in TSTL dfaults + noHeader: false, + project: tsConfigPath, + noHoisting: false, + } as CompilerOptions); + } else { + expect(parsedArgs.isValid).toBeTruthy(); } -} +}); diff --git a/test/unit/compiler/configuration/options.spec.ts b/test/unit/compiler/configuration/options.spec.ts index 28324c10a..9c6ba7306 100644 --- a/test/unit/compiler/configuration/options.spec.ts +++ b/test/unit/compiler/configuration/options.spec.ts @@ -1,29 +1,19 @@ -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../../../src/util"; +import * as util from "../../../util"; import { LuaTarget, LuaLibImportKind } from "../../../../src/CompilerOptions"; -export class ObjectLiteralTests -{ - @TestCase(LuaTarget.LuaJIT) - @TestCase("jit") - @TestCase("JiT") - @Test("Options LuaTarget case-insensitive") - public luaTargetCaseInsensitive(target: string): void { - const options = {LuaTarget: target}; - const result = util.transpileString("~a", options); +test.each([LuaTarget.LuaJIT, "jit", "JiT"])("Options luaTarget case-insensitive (%p)", target => { + const options = { luaTarget: target as LuaTarget }; + const result = util.transpileString("~a", options); - Expect(result).toBe("bit.bnot(a);"); - } + expect(result).toBe("bit.bnot(a);"); +}); - @TestCase(LuaLibImportKind.None) - @TestCase("none") - @TestCase("NoNe") - @Test("Options LuaLibImport case-insensitive") - public luaLibImportCaseInsensitive(importKind: string): void { - const options = {LuaLibImportKind: importKind}; +test.each([LuaLibImportKind.None, "none", "NoNe"])( + "Options luaLibImport case-insensitive (%p)", + importKind => { + const options = { luaLibImport: importKind as LuaLibImportKind }; const result = util.transpileString("const a = new Map();", options); - Expect(result).toBe("local a = Map.new();"); - } -} + expect(result).toBe("local a = Map.new();"); + }, +); diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index 6d330100b..cb0c2f446 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,402 +1,380 @@ -import { Expect, Test, TestCase } from "alsatian"; import { TranspileError } from "../../src/TranspileError"; import { LuaTarget } from "../../src/CompilerOptions"; -import * as util from "../src/util"; - -export class LuaConditionalsTests { - - @TestCase(0, 0) - @TestCase(1, 1) - @Test("if") - public if(inp: number, expected: number): void { +import * as util from "../util"; + +test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 1 }])("if (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let input: number = ${inp}; + if (input === 0) { + return 0; + } + return 1;`, + ); + + expect(result).toBe(expected); +}); + +test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 1 }])( + "ifelse (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let input: number = ${inp}; - if (input === 0) { - return 0; - } - return 1;` + if (input === 0) { + return 0; + } else { + return 1; + }`, ); - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @Test("ifelse") - public ifelse(inp: number, expected: number): void { + expect(result).toBe(expected); + }, +); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: 3 }, +])("ifelseif (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let input: number = ${inp}; + if (input === 0) { + return 0; + } else if (input === 1){ + return 1; + } else if (input === 2){ + return 2; + } + return 3;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: 3 }, +])("ifelseifelse (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let input: number = ${inp}; + if (input === 0) { + return 0; + } else if (input === 1){ + return 1; + } else if (input === 2){ + return 2; + } else { + return 3; + }`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -1 }, +])("switch (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: + result = 0; + break; + case 1: + result = 1; + break; + case 2: + result = 2; + break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -2 }, +])("switchdefault (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: + result = 0; + break; + case 1: + result = 1; + break; + case 2: + result = 2; + break; + default: + result = -2; + break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 1 }, + { inp: 0, expected: 1 }, + { inp: 2, expected: 4 }, + { inp: 3, expected: 4 }, + { inp: 4, expected: 4 }, + { inp: 5, expected: 15 }, + { inp: 7, expected: -2 }, +])("switchfallthrough (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: + result = 0; + case 1: + result = 1; + break; + case 2: + result = 2; + case 3: + case 4: + result = 4; + break; + case 5: + result = 5; + case 6: + result += 10; + break; + case 7: + result = 7; + default: + result = -2; + break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -2 }, +])("nestedSwitch (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: + result = 0; + break; + case 1: + switch(${inp}) { + case 0: + result = 0; + break; + case 1: + result = 1; + break; + default: + result = -3; + break; + } + break; + case 2: + result = 2; + break; + default: + result = -2; + break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 2 }, { inp: 2, expected: 2 }])( + "switchLocalScope (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( - `let input: number = ${inp}; - if (input === 0) { - return 0; - } else { - return 1; - }` - ); + `let result: number = -1; - // Assert - Expect(result).toBe(expected); + switch (${inp}) { + case 0: { + let x = 0; + result = 0; + break; + } + case 1: { + let x = 1; + result = x; + } + case 2: { + let x = 2; + result = x; + break; + } } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, 3) - @Test("ifelseif") - public ifelseif(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let input: number = ${inp}; - if (input === 0) { - return 0; - } else if (input === 1){ - return 1; - } else if (input === 2){ - return 2; - } - return 3;` + return result;`, ); - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, 3) - @Test("ifelseifelse") - public ifelseifelse(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let input: number = ${inp}; - if (input === 0) { + expect(result).toBe(expected); + }, +); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -1 }, +])("switchReturn (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `const result: number = -1; + + switch (${inp}) { + case 0: return 0; - } else if (input === 1){ + break; + case 1: return 1; - } else if (input === 2){ + case 2: return 2; - } else { - return 3; - }` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -1) - @Test("switch") - public switch(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: - result = 0; - break; - case 1: - result = 1; - break; - case 2: - result = 2; - break; + break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -1 }, +])("switchWithBrackets (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: { + result = 0; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -2) - @Test("switchdefault") - public switchdefault(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: - result = 0; - break; - case 1: - result = 1; - break; - case 2: - result = 2; - break; - default: - result = -2; - break; + case 1: { + result = 1; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 1) - @TestCase(0, 1) - @TestCase(2, 4) - @TestCase(3, 4) - @TestCase(4, 4) - @TestCase(5, 15) - @TestCase(7, -2) - @Test("switchfallthrough") - public switchfallthrough(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: - result = 0; - case 1: - result = 1; - break; - case 2: - result = 2; - case 3: - case 4: - result = 4; - break; - case 5: - result = 5; - case 6: - result += 10; - break; - case 7: - result = 7; - default: - result = -2; - break; + case 2: { + result = 2; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -2) - @Test("nestedSwitch") - public nestedSwitch(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: - result = 0; - break; - case 1: - switch(${inp}) { - case 0: - result = 0; - break; - case 1: - result = 1; - break; - default: - result = -3; - break; - } - break; - case 2: - result = 2; - break; - default: - result = -2; - break; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 0 }, + { inp: 1, expected: 1 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -1 }, +])("switchWithBracketsBreakInConditional (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: { + result = 0; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 2) - @TestCase(2, 2) - @Test("switchLocalScope") - public switchLocalScope(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; + case 1: { + result = 1; - switch (${inp}) { - case 0: { - let x = 0; - result = 0; - break; - } - case 1: { - let x = 1; - result = x; - } - case 2: { - let x = 2; - result = x; - break; - } + if (result == 1) break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -1) - @Test("switchReturn") - public switchReturn(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `const result: number = -1; - - switch (${inp}) { - case 0: - return 0; - break; - case 1: - return 1; - case 2: - return 2; - break; + case 2: { + result = 2; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -1) - @Test("switchWithBrackets") - public switchWithBrackets(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: 0, expected: 4 }, + { inp: 1, expected: 0 }, + { inp: 2, expected: 2 }, + { inp: 3, expected: -1 }, +])("switchWithBracketsBreakInInternalLoop (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let result: number = -1; + + switch (${inp}) { + case 0: { + result = 0; + + for (let i = 0; i < 5; i++) { + result++; - switch (${inp}) { - case 0: { - result = 0; - break; - } - case 1: { - result = 1; - break; - } - case 2: { - result = 2; - break; + if (i >= 2) { + break; + } } } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - - @TestCase(0, 0) - @TestCase(1, 1) - @TestCase(2, 2) - @TestCase(3, -1) - @Test("switchWithBracketsBreakInConditional") - public switchWithBracketsBreakInConditional(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: { - result = 0; - break; - } - case 1: { - result = 1; - - if (result == 1) break; - } - case 2: { - result = 2; - break; - } + case 1: { + result++; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 4) - @TestCase(1, 0) - @TestCase(2, 2) - @TestCase(3, -1) - @Test("switchWithBracketsBreakInInternalLoop") - public switchWithBracketsBreakInInternalLoop(inp: number, expected: number): void { - const result = util.transpileAndExecute( - `let result: number = -1; - - switch (${inp}) { - case 0: { - result = 0; - - for (let i = 0; i < 5; i++) { - result++; - - if (i >= 2) { - break; - } - } - } - case 1: { - result++; - break; - } - case 2: { - result = 2; - break; - } + case 2: { + result = 2; + break; } - return result;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @Test("If dead code after return") - public ifDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `if (true) { return 3; const b = 8; }`); - - Expect(result).toBe(3); - } - - @Test("switch dead code after return") - public whileDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `switch ("abc") { case "def": return 4; let abc = 4; case "abc": return 5; let def = 6; }`); - - Expect(result).toBe(5); - } - - @Test("switch not allowed in 5.1") - public switchThrow51(): void { - Expect( () => util.transpileString(`switch ("abc") {}`, {luaTarget: LuaTarget.Lua51})) - .toThrowError(TranspileError, "Switch statements is/are not supported for target Lua 5.1."); - } -} + } + return result;`, + ); + + expect(result).toBe(expected); +}); + +test("If dead code after return", () => { + const result = util.transpileAndExecute(`if (true) { return 3; const b = 8; }`); + + expect(result).toBe(3); +}); + +test("switch dead code after return", () => { + const result = util.transpileAndExecute( + `switch ("abc") { case "def": return 4; let abc = 4; case "abc": return 5; let def = 6; }`, + ); + + expect(result).toBe(5); +}); + +test("switch not allowed in 5.1", () => { + expect(() => + util.transpileString(`switch ("abc") {}`, { luaTarget: LuaTarget.Lua51 }), + ).toThrowExactError( + new TranspileError("Switch statements is/are not supported for target Lua 5.1."), + ); +}); diff --git a/test/unit/console.spec.ts b/test/unit/console.spec.ts index 2bd1e5fab..5c9319045 100644 --- a/test/unit/console.spec.ts +++ b/test/unit/console.spec.ts @@ -1,67 +1,77 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; -export class ConsoleTests { +const compilerOptions = { lib: ["lib.es2015.d.ts", "lib.dom.d.ts"] }; - @TestCase("console.log()", "print();") - @TestCase('console.log("Hello")', 'print("Hello");') - @TestCase('console.log("Hello %s", "there")', 'print(string.format("Hello %s", "there"));') - @TestCase('console.log("Hello %%s", "there")', 'print(string.format("Hello %%s", "there"));') - @TestCase('console.log("Hello", "There")', 'print("Hello", "There");') - @Test("console.log") - public testConsoleLog(inp: string, expected: string): void { - // Transpile - const lua = util.transpileString(inp); +test.each([ + { inp: "console.log()", expected: "print();" }, + { inp: 'console.log("Hello")', expected: 'print("Hello");' }, + { + inp: 'console.log("Hello %s", "there")', + expected: 'print(string.format("Hello %s", "there"));', + }, + { + inp: 'console.log("Hello %%s", "there")', + expected: 'print(string.format("Hello %%s", "there"));', + }, + { inp: 'console.log("Hello", "There")', expected: 'print("Hello", "There");' }, +])("console.log (%p)", ({ inp, expected }) => { + expect(util.transpileString(inp, compilerOptions)).toBe(expected); +}); - // Assert - Expect(lua).toBe(expected); - } +test.each([ + { inp: "console.trace()", expected: "print(debug.traceback());" }, + { inp: 'console.trace("message")', expected: 'print(debug.traceback("message"));' }, + { + inp: 'console.trace("Hello %s", "there")', + expected: 'print(debug.traceback(string.format("Hello %s", "there")));', + }, + { + inp: 'console.trace("Hello %%s", "there")', + expected: 'print(debug.traceback(string.format("Hello %%s", "there")));', + }, + { + inp: 'console.trace("Hello", "there")', + expected: 'print(debug.traceback("Hello", "there"));', + }, +])("console.trace (%p)", ({ inp, expected }) => { + expect(util.transpileString(inp, compilerOptions)).toBe(expected); +}); - @TestCase("console.trace()", "print(debug.traceback());") - @TestCase('console.trace("message")', 'print(debug.traceback("message"));') - @TestCase('console.trace("Hello %s", "there")', 'print(debug.traceback(string.format("Hello %s", "there")));') - @TestCase('console.trace("Hello %%s", "there")', 'print(debug.traceback(string.format("Hello %%s", "there")));') - @TestCase('console.trace("Hello", "there")', 'print(debug.traceback("Hello", "there"));') - @Test("console.trace") - public testConsoleTrace(inp: string, expected: string): void { - // Transpile - const lua = util.transpileString(inp); +test.each([ + { inp: "console.assert(false)", expected: "assert(false);" }, + { inp: 'console.assert(false, "message")', expected: 'assert(false, "message");' }, + { + inp: 'console.assert(false, "message %s", "info")', + expected: 'assert(false, string.format("message %s", "info"));', + }, + { + inp: 'console.assert(false, "message %%s", "info")', + expected: 'assert(false, string.format("message %%s", "info"));', + }, + { + inp: 'console.assert(false, "message", "more")', + expected: 'assert(false, "message", "more");', + }, +])("console.assert (%p)", ({ inp, expected }) => { + expect(util.transpileString(inp, compilerOptions)).toBe(expected); +}); - // Assert - Expect(lua).toBe(expected); - } +test("console.differentiation", () => { + const result = util.transpileExecuteAndReturnExport( + ` + export class Console { + test() { return 42; } + } - @TestCase("console.assert(false)", "assert(false);") - @TestCase('console.assert(false, "message")', 'assert(false, "message");') - @TestCase('console.assert(false, "message %s", "info")', 'assert(false, string.format("message %s", "info"));') - @TestCase('console.assert(false, "message %%s", "info")', 'assert(false, string.format("message %%s", "info"));') - @TestCase('console.assert(false, "message", "more")', 'assert(false, "message", "more");') - @Test("console.assert") - public testConsoleAssert(inp: string, expected: string): void { - // Transpile - const lua = util.transpileString(inp); + function test() { + const console = new Console(); + return console.test(); + } - // Assert - Expect(lua).toBe(expected); - } - - @Test("console.differentiation") - public testConsoleDifferentiation(): void { - // Transpile - const result = util.transpileExecuteAndReturnExport(` - export class Console { - test() { return 42; } - } - - function test() { - const console = new Console(); - return console.test(); - } - - export const result = test(); - `, "result"); - Expect(result).toBe(42); - } - - -} \ No newline at end of file + export const result = test(); + `, + "result", + compilerOptions, + ); + expect(result).toBe(42); +}); diff --git a/test/unit/curry.spec.ts b/test/unit/curry.spec.ts index 03bf99000..639336a47 100644 --- a/test/unit/curry.spec.ts +++ b/test/unit/curry.spec.ts @@ -1,19 +1,10 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; -export class LuaCurryTests { +test.each([{ x: 2, y: 3 }, { x: 5, y: 4 }])("curryingAdd (%p)", ({ x, y }) => { + const result = util.transpileAndExecute( + `let add = (x: number) => (y: number) => x + y; + return add(${x})(${y})`, + ); - @Test("curryingAdd") - @TestCase(2, 3) - @TestCase(5, 4) - public curryingAdd(x: number, y: number): void - { - const result = util.transpileAndExecute( - `let add = (x: number) => (y: number) => x + y; - return add(${x})(${y})` - ); - - // Assert - Expect(result).toBe(x + y); - } -} + expect(result).toBe(x + y); +}); diff --git a/test/unit/declarations.spec.ts b/test/unit/declarations.spec.ts index 12bb8d8d6..1751d621c 100644 --- a/test/unit/declarations.spec.ts +++ b/test/unit/declarations.spec.ts @@ -1,124 +1,88 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; -export class DeclarationTests -{ - @Test("Declaration function call") - public declarationFunctionCall(): void { - // Arrange - const libLua = `function declaredFunction(x) return 3*x end`; - - const tsHeader = `declare function declaredFunction(this: void, x: number): number;`; - - const source = `return declaredFunction(2) + 4;`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe(10); - } - - @Test("Declaration function call tupleReturn") - public declarationFunctionCallTupleReturn(): void { - // Arrange - const libLua = `function declaredFunction(x) return x, 2*x + 1 end`; - - const tsHeader = ` - /** @tupleReturn */ - declare function declaredFunction(this: void, x: number): [number, number];`; - - const source = ` - const tuple = declaredFunction(3); - const [destructedLeft, destructedRight] = declaredFunction(2); - return \`\${tuple[0] + destructedLeft},\${tuple[1] + destructedRight}\`;`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe("5,12"); - } - - @Test("Declaration namespace function call") - public declarationNamespaceFunctionCall(): void { - // Arrange - const libLua = ` - myNameSpace = {} - function myNameSpace.declaredFunction(x) return 3*x end - `; - - const tsHeader = `declare namespace myNameSpace { function declaredFunction(this: void, x: number): number; }`; - - const source = `return myNameSpace.declaredFunction(2) + 4;`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe(10); - } - - @Test("Declaration interface function call") - public declarationInterfaceFunctionCall(): void { - // Arrange - const libLua = ` - myInterfaceInstance = {} - myInterfaceInstance.x = 10 - function myInterfaceInstance:declaredFunction(x) return self.x + 3*x end - `; - - const tsHeader = ` - declare interface MyInterface { - declaredFunction(x: number): number; - } - declare var myInterfaceInstance: MyInterface;`; - - const source = `return myInterfaceInstance.declaredFunction(3);`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe(19); - } - - @Test("Declaration function callback") - public declarationFunctionCallback(): void { - // Arrange - const libLua = `function declaredFunction(callback) return callback(4) end`; - const tsHeader = - `declare function declaredFunction(this: void, callback: (this: void, x: number) => number): number;`; - - const source = `return declaredFunction(x => 2 * x);`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe(8); - } - - @Test("Declaration instance function callback") - public declarationInstanceFunctionCallback(): void { - // Arrange - const libLua = ` - myInstance = {} - myInstance.x = 10 - function myInstance:declaredFunction(callback) return callback(self.x) end`; - - const tsHeader = - `declare interface MyInterface { - declaredFunction(callback: (this: void, x: number) => number): number; - } - declare var myInstance: MyInterface;`; - - const source = `return myInstance.declaredFunction(x => 2 * x);`; - - // Act - const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); - - // Assert - Expect(result).toBe(20); - } -} +test("Declaration function call", () => { + const libLua = `function declaredFunction(x) return 3*x end`; + + const tsHeader = `declare function declaredFunction(this: void, x: number): number;`; + + const source = `return declaredFunction(2) + 4;`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe(10); +}); + +test("Declaration function call tupleReturn", () => { + const libLua = `function declaredFunction(x) return x, 2*x + 1 end`; + + const tsHeader = ` + /** @tupleReturn */ + declare function declaredFunction(this: void, x: number): [number, number];`; + + const source = ` + const tuple = declaredFunction(3); + const [destructedLeft, destructedRight] = declaredFunction(2); + return \`\${tuple[0] + destructedLeft},\${tuple[1] + destructedRight}\`;`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe("5,12"); +}); + +test("Declaration namespace function call", () => { + const libLua = ` + myNameSpace = {} + function myNameSpace.declaredFunction(x) return 3*x end + `; + + const tsHeader = `declare namespace myNameSpace { function declaredFunction(this: void, x: number): number; }`; + + const source = `return myNameSpace.declaredFunction(2) + 4;`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe(10); +}); + +test("Declaration interface function call", () => { + const libLua = ` + myInterfaceInstance = {} + myInterfaceInstance.x = 10 + function myInterfaceInstance:declaredFunction(x) return self.x + 3*x end + `; + + const tsHeader = ` + declare interface MyInterface { + declaredFunction(x: number): number; + } + declare var myInterfaceInstance: MyInterface;`; + + const source = `return myInterfaceInstance.declaredFunction(3);`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe(19); +}); + +test("Declaration function callback", () => { + const libLua = `function declaredFunction(callback) return callback(4) end`; + const tsHeader = `declare function declaredFunction(this: void, callback: (this: void, x: number) => number): number;`; + + const source = `return declaredFunction(x => 2 * x);`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe(8); +}); + +test("Declaration instance function callback", () => { + const libLua = ` + myInstance = {} + myInstance.x = 10 + function myInstance:declaredFunction(callback) return callback(self.x) end`; + + const tsHeader = `declare interface MyInterface { + declaredFunction(callback: (this: void, x: number) => number): number; + } + declare var myInstance: MyInterface;`; + + const source = `return myInstance.declaredFunction(x => 2 * x);`; + + const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); + expect(result).toBe(20); +}); diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index 69fb6bd2a..87620b101 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -1,52 +1,43 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; -export class DecoratorCustomConstructor -{ - @Test("CustomCreate") - public customCreate(): void { - const luaHeader = - `function Point2DCreate(x, y) - return {x = x, y = y} - end`; +test("CustomCreate", () => { + const luaHeader = `function Point2DCreate(x, y) + return {x = x, y = y} + end`; - const tsHeader = - `/** @customConstructor Point2DCreate */ - class Point2D { - public x: number; - public y: number; - constructor(x: number, y: number) { - // No values assigned - } - }`; + const tsHeader = `/** @customConstructor Point2DCreate */ + class Point2D { + public x: number; + public y: number; + constructor(x: number, y: number) { + // No values assigned + } + }`; - const result = util.transpileAndExecute( - `return new Point2D(1, 2).x;`, - undefined, - luaHeader, - tsHeader - ); + const result = util.transpileAndExecute( + `return new Point2D(1, 2).x;`, + undefined, + luaHeader, + tsHeader, + ); - // Assert - Expect(result).toBe(1); - } + expect(result).toBe(1); +}); - @Test("IncorrectUsage") - public incorrectUsage(): void { - Expect(() => { - util.transpileString( - `/** @customConstructor */ - class Point2D { - constructor( - public x: number, - public y: number - ) {} - } - return new Point2D(1, 2).x; - ` - ); - }).toThrowError(TranspileError, "!CustomConstructor expects 1 argument(s) but got 0."); - } -} +test("IncorrectUsage", () => { + expect(() => { + util.transpileString( + `/** @customConstructor */ + class Point2D { + constructor( + public x: number, + public y: number + ) {} + } + return new Point2D(1, 2).x; + `, + ); + }).toThrowExactError(new TranspileError("!CustomConstructor expects 1 argument(s) but got 0.")); +}); diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index 6fdedf191..abac8f233 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -1,63 +1,61 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; -export class DecoratorMetaExtension { - - @Test("MetaExtension") - public metaExtension(): void { - const tsHeader = ` - declare class _LOADED {} - declare namespace debug { - function getregistry(): any; +test("MetaExtension", () => { + const tsHeader = ` + declare class _LOADED {} + declare namespace debug { + function getregistry(): any; + } + /** @metaExtension */ + class LoadedExt extends _LOADED { + public static test() { + return 5; } - /** @metaExtension */ - class LoadedExt extends _LOADED { - public static test() { - return 5; - } - }`; + }`; - const result = util.transpileAndExecute( - `return debug.getregistry()["_LOADED"].test();`, - undefined, undefined, tsHeader); + const result = util.transpileAndExecute( + `return debug.getregistry()["_LOADED"].test();`, + undefined, + undefined, + tsHeader, + ); - // Assert - Expect(result).toBe(5); - } + expect(result).toBe(5); +}); - @Test("IncorrectUsage") - public incorrectUsage(): void { - const expectedMessage = TSTLErrors.MissingMetaExtension(undefined).message; - Expect(() => { - util.transpileString( - ` - /** @metaExtension */ - class LoadedExt { - public static test() { - return 5; - } +test("IncorrectUsage", () => { + const expectedMessage = TSTLErrors.MissingMetaExtension(undefined).message; + expect(() => { + util.transpileString( + ` + /** @metaExtension */ + class LoadedExt { + public static test() { + return 5; } - ` - ); - }).toThrowError(TranspileError, expectedMessage); - } + } + `, + ); + }).toThrowExactError(new TranspileError(expectedMessage)); +}); - @Test("DontAllowInstantiation") - public dontAllowInstantiation(): void { - Expect(() => { - util.transpileString( - ` - declare class _LOADED {} - /** @metaExtension */ - class Ext extends _LOADED { - } - const e = new Ext(); - ` - ); - }).toThrowError(TranspileError, - "Cannot construct classes with decorator '@extension' or '@metaExtension'."); - } -} +test("DontAllowInstantiation", () => { + expect(() => { + util.transpileString( + ` + declare class _LOADED {} + /** @metaExtension */ + class Ext extends _LOADED { + } + const e = new Ext(); + `, + ); + }).toThrowExactError( + new TranspileError( + "Cannot construct classes with decorator '@extension' or '@metaExtension'.", + ), + ); +}); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index d21b695c4..7a2b07b66 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -1,191 +1,178 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; -export class EnumTests { - @Test("Declare const enum") - public declareConstEnum(): void { - const testCode = ` - declare const enum TestEnum { - MEMBER_ONE = "test", - MEMBER_TWO = "test2" - } - - const valueOne = TestEnum.MEMBER_ONE; - `; - - Expect(util.transpileString(testCode)).toBe(`local valueOne = "test";`); - } - - @Test("Const enum") - public constEnum(): void { - const testCode = ` - const enum TestEnum { - MEMBER_ONE = "test", - MEMBER_TWO = "test2" - } - - const valueOne = TestEnum.MEMBER_TWO; - `; - - Expect(util.transpileString(testCode)).toBe(`local valueOne = "test2";`); - } - - @Test("Const enum without initializer") - public constEnumNoInitializer(): void { - const testCode = ` - const enum TestEnum { - MEMBER_ONE, - MEMBER_TWO - } - - const valueOne = TestEnum.MEMBER_TWO; - `; - - Expect(util.transpileString(testCode)).toBe(`local valueOne = 1;`); - } - - @Test("Const enum without initializer in some values") - public constEnumNoInitializerInSomeValues(): void { - const testCode = ` - const enum TestEnum { - MEMBER_ONE = 3, - MEMBER_TWO, - MEMBER_THREE = 5 - } - - const valueOne = TestEnum.MEMBER_TWO; - `; - - Expect(util.transpileString(testCode)).toBe(`local valueOne = 4;`); - } - - @Test("Invalid heterogeneous enum") - public invalidHeterogeneousEnum(): void { - // Transpile & Assert - Expect(() => { - const lua = util.transpileString( - `enum TestEnum { - a, - b = "ok", - c, - }` - ); - }).toThrowError(TranspileError, "Invalid heterogeneous enum. Enums should either specify no " - + "member values, or specify values (of the same type) for all members."); - } - - @Test("String literal name in enum") - public stringLiteralNameEnum(): void { - const code = `enum TestEnum { - ["name"] = "foo" - } - return TestEnum["name"];`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Enum identifier value internal") - public enumIdentifierValueInternal(): void { - const result = util.transpileAndExecute( - `enum testEnum { - abc, - def, - ghi = def, - jkl, - } - return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi},\${testEnum.jkl}\`;` +test("Declare const enum", () => { + const testCode = ` + declare const enum TestEnum { + MEMBER_ONE = "test", + MEMBER_TWO = "test2" + } + + const valueOne = TestEnum.MEMBER_ONE; + `; + + expect(util.transpileString(testCode)).toBe(`local valueOne = "test";`); +}); + +test("Const enum", () => { + const testCode = ` + const enum TestEnum { + MEMBER_ONE = "test", + MEMBER_TWO = "test2" + } + + const valueOne = TestEnum.MEMBER_TWO; + `; + + expect(util.transpileString(testCode)).toBe(`local valueOne = "test2";`); +}); + +test("Const enum without initializer", () => { + const testCode = ` + const enum TestEnum { + MEMBER_ONE, + MEMBER_TWO + } + + const valueOne = TestEnum.MEMBER_TWO; + `; + + expect(util.transpileString(testCode)).toBe(`local valueOne = 1;`); +}); + +test("Const enum without initializer in some values", () => { + const testCode = ` + const enum TestEnum { + MEMBER_ONE = 3, + MEMBER_TWO, + MEMBER_THREE = 5 + } + + const valueOne = TestEnum.MEMBER_TWO; + `; + + expect(util.transpileString(testCode)).toBe(`local valueOne = 4;`); +}); + +test("Invalid heterogeneous enum", () => { + expect(() => { + const lua = util.transpileString( + `enum TestEnum { + a, + b = "ok", + c, + }`, ); - - Expect(result).toBe("0,1,1,2"); - } - - @Test("Enum identifier value internal recursive") - public enumIdentifierValueInternalRecursive(): void { - const result = util.transpileAndExecute( - `enum testEnum { - abc, - def, - ghi = def, - jkl = ghi, - } - return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi},\${testEnum.jkl}\`;` - ); - - Expect(result).toBe("0,1,1,1"); - } - - @Test("Enum identifier value external") - public enumIdentifierValueExternal(): void { - const result = util.transpileAndExecute( - `const ext = 6; - enum testEnum { - abc, - def, - ghi = ext, - } - return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi}\`;` - ); - - Expect(result).toBe("0,1,6"); - } - - @Test("Enum reverse mapping") - public enumReverseMapping(): void { - const result = util.transpileAndExecute( - `enum testEnum { - abc, - def, - ghi - } - return testEnum[testEnum.abc] + testEnum[testEnum.ghi]` - ); - - Expect(result).toBe("abcghi"); - } - - @Test("Const enum index") - public constEnumIndex(): void { - const result = util.transpileAndExecute( - `const enum testEnum { - abc, - def, - ghi - } - return testEnum["def"];` - ); - - Expect(result).toBe(1); - } - - @Test("Const enum index identifier value") - public constEnumIndexIdnetifierValue(): void { - const result = util.transpileAndExecute( - `const enum testEnum { - abc, - def = 4, - ghi, - jkl = ghi - } - return testEnum["jkl"];` - ); - - Expect(result).toBe(5); - } - - @Test("Const enum index identifier chain") - public constEnumIndexIdnetifierChain(): void { - const result = util.transpileAndExecute( - `const enum testEnum { - abc = 3, - def, - ghi = def, - jkl = ghi, - } - return testEnum["ghi"];` - ); - - Expect(result).toBe(4); - } -} + }).toThrowExactError( + new TranspileError( + "Invalid heterogeneous enum. Enums should either specify no " + + "member values, or specify values (of the same type) for all members.", + ), + ); +}); + +test("String literal name in enum", () => { + const code = `enum TestEnum { + ["name"] = "foo" + } + return TestEnum["name"];`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Enum identifier value internal", () => { + const result = util.transpileAndExecute( + `enum testEnum { + abc, + def, + ghi = def, + jkl, + } + return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi},\${testEnum.jkl}\`;`, + ); + + expect(result).toBe("0,1,1,2"); +}); + +test("Enum identifier value internal recursive", () => { + const result = util.transpileAndExecute( + `enum testEnum { + abc, + def, + ghi = def, + jkl = ghi, + } + return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi},\${testEnum.jkl}\`;`, + ); + + expect(result).toBe("0,1,1,1"); +}); + +test("Enum identifier value external", () => { + const result = util.transpileAndExecute( + `const ext = 6; + enum testEnum { + abc, + def, + ghi = ext, + } + return \`\${testEnum.abc},\${testEnum.def},\${testEnum.ghi}\`;`, + ); + + expect(result).toBe("0,1,6"); +}); + +test("Enum reverse mapping", () => { + const result = util.transpileAndExecute( + `enum testEnum { + abc, + def, + ghi + } + return testEnum[testEnum.abc] + testEnum[testEnum.ghi]`, + ); + + expect(result).toBe("abcghi"); +}); + +test("Const enum index", () => { + const result = util.transpileAndExecute( + `const enum testEnum { + abc, + def, + ghi + } + return testEnum["def"];`, + ); + + expect(result).toBe(1); +}); + +test("Const enum index identifier value", () => { + const result = util.transpileAndExecute( + `const enum testEnum { + abc, + def = 4, + ghi, + jkl = ghi + } + return testEnum["jkl"];`, + ); + + expect(result).toBe(5); +}); + +test("Const enum index identifier chain", () => { + const result = util.transpileAndExecute( + `const enum testEnum { + abc = 3, + def, + ghi = def, + jkl = ghi, + } + return testEnum["ghi"];`, + ); + + expect(result).toBe(4); +}); diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index a7058bc03..60a0adf10 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,78 +1,63 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; -export class LuaErrorTests { +test("throwString", () => { + const lua = util.transpileString(`throw "Some Error"`); + expect(lua).toBe(`error("Some Error");`); +}); - @Test("throwString") - public trowString(): void { - // Transpile - const lua = util.transpileString( - `throw "Some Error"` - ); - // Assert - Expect(lua).toBe(`error("Some Error");`); - } - - @Test("throwError") - public throwError(): void { - // Transpile & Asser - Expect(() => { - const lua = util.transpileString( - `throw Error("Some Error")` - ); - }).toThrowError(TranspileError, "Invalid throw expression, only strings can be thrown."); - } +test("throwError", () => { + expect(() => { + const lua = util.transpileString(`throw Error("Some Error")`); + }).toThrowExactError( + new TranspileError("Invalid throw expression, only strings can be thrown."), + ); +}); - @TestCase(0, "A") - @TestCase(1, "B") - @TestCase(2, "C") - @Test("re-throw") - public reThrow(i: number, expected: any): void { - const source = - `const i: number = ${i}; - 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"; - } - } - let result: string = "x"; +test.each([{ i: 0, expected: "A" }, { i: 1, expected: "B" }, { i: 2, expected: "C" }])( + "re-throw (%p)", + ({ i, expected }) => { + const source = `const i: number = ${i}; + function foo() { + try { try { - foo(); + if (i === 0) { throw "z"; } } catch (e) { - result = (e as string)[(e as string).length - 1]; + throw "a"; + } finally { + if (i === 1) { throw "b"; } } - return result;`; - const result = util.transpileAndExecute(source); - Expect(result).toBe(expected); + } catch (e) { + throw (e as string).toUpperCase(); + } finally { + throw "C"; + } } + let result: string = "x"; + try { + foo(); + } catch (e) { + result = (e as string)[(e as string).length - 1]; + } + return result;`; + const result = util.transpileAndExecute(source); + expect(result).toBe(expected); + }, +); - @Test("re-throw (no catch var)") - public reThrowWithoutCatchVar(): void { - const source = - `let result = "x"; +test("re-throw (no catch var)", () => { + const source = `let result = "x"; + try { try { - try { - throw "y"; - } catch { - throw "z"; - } - } catch (e) { - result = (e as string)[(e as string).length - 1]; + throw "y"; + } catch { + throw "z"; } - return result;`; - const result = util.transpileAndExecute(source); - Expect(result).toBe("z"); - } -} + } catch (e) { + result = (e as string)[(e as string).length - 1]; + } + return result;`; + const result = util.transpileAndExecute(source); + expect(result).toBe("z"); +}); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index aa14e0404..2cf2e6cb3 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,528 +1,543 @@ -import { Expect, Test, TestCase } from "alsatian"; import { TranspileError } from "../../src/TranspileError"; import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; import * as ts from "typescript"; -import * as util from "../src/util"; +import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; -export class ExpressionTests { - - @TestCase("i++", "i = i + 1;") - @TestCase("++i", "i = i + 1;") - @TestCase("i--", "i = i - 1;") - @TestCase("--i", "i = i - 1;") - @TestCase("!a", "not a;") - @TestCase("-a", "-a;") - @TestCase("+a", "a;") - @TestCase("let a = delete tbl['test']", "local a = (function()\n tbl.test = nil;\n return true;\nend)();") - @TestCase("delete tbl['test']", "tbl.test = nil;") - @TestCase("let a = delete tbl.test", "local a = (function()\n tbl.test = nil;\n return true;\nend)();") - @TestCase("delete tbl.test", "tbl.test = nil;") - @Test("Unary expressions basic") - public unaryBasic(input: string, lua: string): void { - Expect(util.transpileString(input)).toBe(lua); - } - - @TestCase("3+4", 3 + 4) - @TestCase("5-2", 5 - 2) - @TestCase("6*3", 6 * 3) - @TestCase("6**3", 6 ** 3) - @TestCase("20/5", 20 / 5) - @TestCase("15/10", 15 / 10) - @TestCase("15%3", 15 % 3) - @Test("Binary expressions basic numeric") - public binaryNum(input: string, output: number): void { - const result = util.transpileAndExecute(`return ${input}`); - - // Assert - Expect(result).toBe(output); - } - - @TestCase("1==1", true) - @TestCase("1===1", true) - @TestCase("1!=1", false) - @TestCase("1!==1", false) - @TestCase("1>1", false) - @TestCase("1>=1", true) - @TestCase("1<1", false) - @TestCase("1<=1", true) - @TestCase("1&&1", 1) - @TestCase("1||1", 1) - @Test("Binary expressions basic boolean") - public binaryBool(input: string, expected: any): void { - const result = util.transpileAndExecute(`return ${input}`); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase("'key' in obj") - @TestCase("'existingKey' in obj") - @TestCase("0 in obj") - @TestCase("9 in obj") - @Test("Binary expression in") - public binaryIn(input: string): void +test.each([ + { input: "i++", lua: "i = i + 1;" }, + { input: "++i", lua: "i = i + 1;" }, + { input: "i--", lua: "i = i - 1;" }, + { input: "--i", lua: "i = i - 1;" }, + { input: "!a", lua: "not a;" }, + { input: "-a", lua: "-a;" }, + { input: "+a", lua: "a;" }, { + input: "let a = delete tbl['test']", + lua: "local a = (function()\n tbl.test = nil;\n return true;\nend)();", + }, + { input: "delete tbl['test']", lua: "tbl.test = nil;" }, + { + input: "let a = delete tbl.test", + lua: "local a = (function()\n tbl.test = nil;\n return true;\nend)();", + }, + { input: "delete tbl.test", lua: "tbl.test = nil;" }, +])("Unary expressions basic (%p)", ({ input, lua }) => { + expect(util.transpileString(input)).toBe(lua); +}); + +test.each([ + { input: "3+4", output: 3 + 4 }, + { input: "5-2", output: 5 - 2 }, + { input: "6*3", output: 6 * 3 }, + { input: "6**3", output: 6 ** 3 }, + { input: "20/5", output: 20 / 5 }, + { input: "15/10", output: 15 / 10 }, + { input: "15%3", output: 15 % 3 }, +])("Binary expressions basic numeric (%p)", ({ input, output }) => { + const result = util.transpileAndExecute(`return ${input}`); + + expect(result).toBe(output); +}); + +test.each([ + { input: "1==1", expected: true }, + { input: "1===1", expected: true }, + { input: "1!=1", expected: false }, + { input: "1!==1", expected: false }, + { input: "1>1", expected: false }, + { input: "1>=1", expected: true }, + { input: "1<1", expected: false }, + { input: "1<=1", expected: true }, + { input: "1&&1", expected: 1 }, + { input: "1||1", expected: 1 }, +])("Binary expressions basic boolean (%p)", ({ input, expected }) => { + const result = util.transpileAndExecute(`return ${input}`); + + expect(result).toBe(expected); +}); + +test.each(["'key' in obj", "'existingKey' in obj", "0 in obj", "9 in obj"])( + "Binary expression in (%p)", + input => { const tsHeader = "declare var obj: any;"; const tsSource = `return ${input}`; const luaHeader = "obj = { existingKey = 1 }"; const result = util.transpileAndExecute(tsSource, undefined, luaHeader, tsHeader); - // Assert - Expect(result).toBe(eval(`let obj = { existingKey: 1 }; ${input}`)); - } - - @TestCase("a+=b", 5 + 3) - @TestCase("a-=b", 5 - 3) - @TestCase("a*=b", 5 * 3) - @TestCase("a/=b", 5 / 3) - @TestCase("a%=b", 5 % 3) - @TestCase("a**=b", 5 ** 3) - @Test("Binary expressions overridden operators") - public binaryOperatorOverride(input: string, expected: number): void { - const result = util.transpileAndExecute(`let a = 5; let b = 3; ${input}; return a;`); - - Expect(result).toBe(expected); - } - - @TestCase("~b") - @TestCase("a&b") - @TestCase("a&=b") - @TestCase("a|b") - @TestCase("a|=b") - @TestCase("a^b") - @TestCase("a^=b") - @TestCase("a<>b") - @TestCase("a>>=b") - @TestCase("a>>>b") - @TestCase("a>>>=b") - @Test("Bitop [5.1]") - public bitOperatorOverride51(input: string, lua: string): void { - // Bit operations not supported in 5.1, expect an exception - Expect(() => util.transpileString(input, { luaTarget: LuaTarget.Lua51, luaLibImport: LuaLibImportKind.None })) - .toThrow(); - } - - @TestCase("~a", "bit.bnot(a);") - @TestCase("a&b", "bit.band(a, b);") - @TestCase("a&=b", "a = bit.band(a, b);") - @TestCase("a|b", "bit.bor(a, b);") - @TestCase("a|=b", "a = bit.bor(a, b);") - @TestCase("a^b", "bit.bxor(a, b);") - @TestCase("a^=b", "a = bit.bxor(a, b);") - @TestCase("a<>b", "bit.arshift(a, b);") - @TestCase("a>>=b", "a = bit.arshift(a, b);") - @TestCase("a>>>b", "bit.rshift(a, b);") - @TestCase("a>>>=b", "a = bit.rshift(a, b);") - @Test("Bitop [JIT]") - public bitOperatorOverrideJIT(input: string, lua: string): void { - const options = { luaTarget: LuaTarget.LuaJIT, luaLibImport: LuaLibImportKind.None }; - Expect(util.transpileString(input, options)).toBe(lua); - } - - @TestCase("~a", "bit32.bnot(a);") - @TestCase("a&b", "bit32.band(a, b);") - @TestCase("a&=b", "a = bit32.band(a, b);") - @TestCase("a|b", "bit32.bor(a, b);") - @TestCase("a|=b", "a = bit32.bor(a, b);") - @TestCase("a^b", "bit32.bxor(a, b);") - @TestCase("a^=b", "a = bit32.bxor(a, b);") - @TestCase("a<>b", "bit32.arshift(a, b);") - @TestCase("a>>=b", "a = bit32.arshift(a, b);") - @TestCase("a>>>b", "bit32.rshift(a, b);") - @TestCase("a>>>=b", "a = bit32.rshift(a, b);") - @Test("Bitop [5.2]") - public bitOperatorOverride52(input: string, lua: string): void { - const options = { luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None }; - Expect(util.transpileString(input, options)).toBe(lua); - } - - @TestCase("~a", "~a;") - @TestCase("a&b", "a & b;") - @TestCase("a&=b", "a = a & b;") - @TestCase("a|b", "a | b;") - @TestCase("a|=b", "a = a | b;") - @TestCase("a^b", "a ~ b;") - @TestCase("a^=b", "a = a ~ b;") - @TestCase("a<>>b", "a >> b;") - @TestCase("a>>>=b", "a = a >> b;") - @Test("Bitop [5.3]") - public bitOperatorOverride53(input: string, lua: string): void { - const options = { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None }; - Expect(util.transpileString(input, options)).toBe(lua); - } - - @TestCase("a>>b") - @TestCase("a>>=b") - @Test("Unsupported bitop 5.3") - public bitOperatorOverride53Unsupported(input: string): void { - Expect(() => util.transpileString(input, { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None })) - .toThrowError(TranspileError, TSTLErrors.UnsupportedKind( + expect(result).toBe(eval(`let obj = { existingKey: 1 }; ${input}`)); + }, +); + +test.each([ + { input: "a+=b", expected: 5 + 3 }, + { input: "a-=b", expected: 5 - 3 }, + { input: "a*=b", expected: 5 * 3 }, + { input: "a/=b", expected: 5 / 3 }, + { input: "a%=b", expected: 5 % 3 }, + { input: "a**=b", expected: 5 ** 3 }, +])("Binary expressions overridden operators (%p)", ({ input, expected }) => { + const result = util.transpileAndExecute(`let a = 5; let b = 3; ${input}; return a;`); + + expect(result).toBe(expected); +}); + +test.each([ + { input: "~b" }, + { input: "a&b" }, + { input: "a&=b" }, + { input: "a|b" }, + { input: "a|=b" }, + { input: "a^b" }, + { input: "a^=b" }, + { input: "a<>b" }, + { input: "a>>=b" }, + { input: "a>>>b" }, + { input: "a>>>=b" }, +])("Bitop [5.1] (%p)", ({ input }) => { + // Bit operations not supported in 5.1, expect an exception + expect(() => + util.transpileString(input, { + luaTarget: LuaTarget.Lua51, + luaLibImport: LuaLibImportKind.None, + }), + ).toThrow(); +}); + +test.each([ + { input: "~a", lua: "bit.bnot(a);" }, + { input: "a&b", lua: "bit.band(a, b);" }, + { input: "a&=b", lua: "a = bit.band(a, b);" }, + { input: "a|b", lua: "bit.bor(a, b);" }, + { input: "a|=b", lua: "a = bit.bor(a, b);" }, + { input: "a^b", lua: "bit.bxor(a, b);" }, + { input: "a^=b", lua: "a = bit.bxor(a, b);" }, + { input: "a<>b", lua: "bit.arshift(a, b);" }, + { input: "a>>=b", lua: "a = bit.arshift(a, b);" }, + { input: "a>>>b", lua: "bit.rshift(a, b);" }, + { input: "a>>>=b", lua: "a = bit.rshift(a, b);" }, +])("Bitop [JIT] (%p)", ({ input, lua }) => { + const options = { luaTarget: LuaTarget.LuaJIT, luaLibImport: LuaLibImportKind.None }; + expect(util.transpileString(input, options)).toBe(lua); +}); + +test.each([ + { input: "~a", lua: "bit32.bnot(a);" }, + { input: "a&b", lua: "bit32.band(a, b);" }, + { input: "a&=b", lua: "a = bit32.band(a, b);" }, + { input: "a|b", lua: "bit32.bor(a, b);" }, + { input: "a|=b", lua: "a = bit32.bor(a, b);" }, + { input: "a^b", lua: "bit32.bxor(a, b);" }, + { input: "a^=b", lua: "a = bit32.bxor(a, b);" }, + { input: "a<>b", lua: "bit32.arshift(a, b);" }, + { input: "a>>=b", lua: "a = bit32.arshift(a, b);" }, + { input: "a>>>b", lua: "bit32.rshift(a, b);" }, + { input: "a>>>=b", lua: "a = bit32.rshift(a, b);" }, +])("Bitop [5.2] (%p)", ({ input, lua }) => { + const options = { luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None }; + expect(util.transpileString(input, options)).toBe(lua); +}); + +test.each([ + { input: "~a", lua: "~a;" }, + { input: "a&b", lua: "a & b;" }, + { input: "a&=b", lua: "a = a & b;" }, + { input: "a|b", lua: "a | b;" }, + { input: "a|=b", lua: "a = a | b;" }, + { input: "a^b", lua: "a ~ b;" }, + { input: "a^=b", lua: "a = a ~ b;" }, + { input: "a<>>b", lua: "a >> b;" }, + { input: "a>>>=b", lua: "a = a >> b;" }, +])("Bitop [5.3] (%p)", ({ input, lua }) => { + const options = { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None }; + expect(util.transpileString(input, options)).toBe(lua); +}); + +test.each(["a>>b", "a>>=b"])("Unsupported bitop 5.3 (%p)", input => { + expect(() => + util.transpileString(input, { + luaTarget: LuaTarget.Lua53, + luaLibImport: LuaLibImportKind.None, + }), + ).toThrowExactError( + new TranspileError( + TSTLErrors.UnsupportedKind( "right shift operator (use >>> instead)", ts.SyntaxKind.GreaterThanGreaterThanToken, - undefined - ).message); - } - - @TestCase("1+1", "1 + 1;") - @TestCase("-1+1", "(-1) + 1;") - @TestCase("1*30+4", "(1 * 30) + 4;") - @TestCase("1*(3+4)", "1 * (3 + 4);") - @TestCase("1*(3+4*2)", "1 * (3 + (4 * 2));") - @Test("Binary expressions ordering parentheses") - public binaryParentheses(input: string, lua: string): void { - Expect(util.transpileString(input)).toBe(lua); - } - - @TestCase("bar(),foo()", 1) - @TestCase("foo(),bar()", 2) - @TestCase("foo(),bar(),baz()", 3) - @Test("Binary Comma") - public binaryComma(input: string, expectResult: number): void { - const code = - `function foo() { return 1; } - function bar() { return 2; }; - function baz() { return 3; }; - return (${input});`; - Expect(util.transpileAndExecute(code)).toBe(expectResult); - } - - @Test("Binary Comma Statement in For Loop") - public binaryCommaStatementInForLoop(): void { - const code = - `let x: number, y: number; - for (x = 0, y = 17; x < 5; ++x, --y) {} - return y;`; - Expect(util.transpileAndExecute(code)).toBe(12); - } - - @Test("Null Expression") - public nullExpression(): void { - Expect(util.transpileString("null")).toBe("nil;"); - } - - @Test("Undefined Expression") - public undefinedExpression(): void { - Expect(util.transpileString("undefined")).toBe("nil;"); - } - - @TestCase("true ? 'a' : 'b'", "a") - @TestCase("false ? 'a' : 'b'", "b") - @TestCase("true ? false : true", false) - @TestCase("false ? false : true", true) - @TestCase("true ? literalValue : true", "literal") - @TestCase("true ? variableValue : true", undefined) - @TestCase("true ? maybeUndefinedValue : true", undefined) - @TestCase("true ? maybeBooleanValue : true", false) - @TestCase("true ? maybeUndefinedValue : true", undefined, { strictNullChecks: true }) - @TestCase("true ? maybeBooleanValue : true", false, { strictNullChecks: true }) - @TestCase("true ? undefined : true", undefined, { strictNullChecks: true }) - @TestCase("true ? null : true", undefined, { strictNullChecks: true }) - @TestCase("true ? false : true", false, { luaTarget: LuaTarget.Lua51 }) - @TestCase("false ? false : true", true, { luaTarget: LuaTarget.Lua51 }) - @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.Lua51 }) - @TestCase("true ? false : true", false, { luaTarget: LuaTarget.LuaJIT }) - @TestCase("false ? false : true", true, { luaTarget: LuaTarget.LuaJIT }) - @TestCase("true ? undefined : true", undefined, { luaTarget: LuaTarget.LuaJIT }) - @Test("Ternary operator") - public ternaryOperator(input: string, expected: any, options?: ts.CompilerOptions): void { - const result = util.transpileAndExecute( - `const literalValue = 'literal'; - let variableValue:string; - let maybeBooleanValue:string|boolean = false; - let maybeUndefinedValue:string|undefined; - return ${input};`, options); - - Expect(result).toBe(expected); - } - - @TestCase("inst.field", 8) - @TestCase("inst.field + 3", 8 + 3) - @TestCase("inst.field * 3", 8 * 3) - @TestCase("inst.field / 2", 8 / 2) - @TestCase("inst.field && 3", 8 && 3) - @TestCase("inst.field || 3", 8 || 3) - @TestCase("(inst.field + 3) & 3", (8 + 3) & 3) - @TestCase("inst.field | 3", 8 | 3) - @TestCase("inst.field << 3", 8 << 3) - @TestCase("inst.field >>> 1", 8 >> 1) - @TestCase("inst.field = 3", 3) - @TestCase(`"abc" + inst.field`, "abc8") - @Test("Get accessor expression") - public getAccessorBinary(expression: string, expected: any): void { - const source = `class MyClass {` - + ` public _field: number;` - + ` public get field(): number { return this._field + 4; }` - + ` public set field(v: number) { this._field = v; }` - + `}` - + `var inst = new MyClass();` - + `inst._field = 4;` - + `return ${expression};`; - - // Transpile/Execute - const result = util.transpileAndExecute(source); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase("= 4", 4 + 4) - @TestCase("-= 3", (4 - 3) + 4) - @TestCase("+= 3", (4 + 3) + 4) - @TestCase("*= 3", (4 * 3) + 4) - @TestCase("/= 2", (4 / 2) + 4) - @TestCase("&= 3", (4 & 3) + 4) - @TestCase("|= 3", (4 | 3) + 4) - @TestCase("<<= 3", (4 << 3) + 4) - @TestCase(">>>= 3", (4 >> 3) + 4) - @Test("Set accessorExpression") - public setAccessorBinary(expression: string, expected: any): void { - const source = `class MyClass {` - + ` public _field: number = 4;` - + ` public get field(): number { return this._field; }` - + ` public set field(v: number) { this._field = v + 4; }` - + `}` - + `var inst = new MyClass();` - + `inst.field ${expression};` - + `return inst._field;`; - - // Transpile/Execute - const result = util.transpileAndExecute(source); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase("inst.baseField", 7) - @TestCase("inst.field", 6) - @TestCase("inst.superField", 5) - @TestCase("inst.superBaseField", 4) - @Test("Inherited accessors") - public inheritedAccessors(expression: string, expected: any): void { - const source = `class MyBaseClass {` - + ` public _baseField: number;` - + ` public get baseField(): number { return this._baseField + 6; }` - + ` public set baseField(v: number) { this._baseField = v; }` - + `}` - + `class MyClass extends MyBaseClass {` - + ` public _field: number;` - + ` public get field(): number { return this._field + 4; }` - + ` public set field(v: number) { this._field = v; }` - + `}` - + `class MySuperClass extends MyClass {` - + ` public _superField: number;` - + ` public get superField(): number { return this._superField + 2; }` - + ` public set superField(v: number) { this._superField = v; }` - + ` public get superBaseField() { return this.baseField - 3; }` - + `}` - + `var inst = new MySuperClass();` - + `inst.baseField = 1;` - + `inst.field = 2;` - + `inst.superField = 3;` - + `return ${expression};`; - - const result = util.transpileAndExecute(source); - Expect(result).toBe(expected); - } - - @TestCase("return x.value;", 1) - @TestCase("x.value = 3; return x.value;", 3) - @Test("Union accessors") - public unionAccessors(expression: string, expected: any): void { - const result = util.transpileAndExecute( - `class A{ get value(){ return this.v || 1; } set value(v){ this.v = v; } v: number; } - class B{ get value(){ return this.v || 2; } set value(v){ this.v = v; } v: number; } - let x: A|B = new A(); - ${expression}` - ); - - Expect(result).toBe(expected); - } - - @TestCase("i++", 10) - @TestCase("i--", 10) - @TestCase("++i", 11) - @TestCase("--i", 9) - @Test("Incrementor value") - public incrementorValue(expression: string, expected: number): void { - const result = util.transpileAndExecute(`let i = 10; return ${expression};`); - - Expect(result).toBe(expected); - } - - @TestCase("a++", "val3") - @TestCase("a--", "val3") - @TestCase("--a", "val2") - @TestCase("++a", "val4") - @Test("Template string expression") - public templateStringExpression(lambda: string, expected: string): void { - const result = util.transpileAndExecute("let a = 3; return `val${" + lambda + "}`;"); - - Expect(result).toEqual(expected); - } - - @TestCase("x = y", "y") - @TestCase("x += y", "xy") - @Test("Assignment expressions") - public assignmentExpression(expression: string, expected: string): void { + undefined, + ).message, + ), + ); +}); + +test.each([ + { input: "1+1", lua: "1 + 1;" }, + { input: "-1+1", lua: "(-1) + 1;" }, + { input: "1*30+4", lua: "(1 * 30) + 4;" }, + { input: "1*(3+4)", lua: "1 * (3 + 4);" }, + { input: "1*(3+4*2)", lua: "1 * (3 + (4 * 2));" }, +])("Binary expressions ordering parentheses (%p)", ({ input, lua }) => { + expect(util.transpileString(input)).toBe(lua); +}); + +test.each([ + { input: "bar(),foo()", expectResult: 1 }, + { input: "foo(),bar()", expectResult: 2 }, + { input: "foo(),bar(),baz()", expectResult: 3 }, +])("Binary Comma (%p)", ({ input, expectResult }) => { + const code = `function foo() { return 1; } + function bar() { return 2; }; + function baz() { return 3; }; + return (${input});`; + expect(util.transpileAndExecute(code)).toBe(expectResult); +}); + +test("Binary Comma Statement in For Loop", () => { + const code = `let x: number, y: number; + for (x = 0, y = 17; x < 5; ++x, --y) {} + return y;`; + expect(util.transpileAndExecute(code)).toBe(12); +}); + +test("Null Expression", () => { + expect(util.transpileString("null")).toBe("nil;"); +}); + +test("Undefined Expression", () => { + expect(util.transpileString("undefined")).toBe("nil;"); +}); + +test.each([ + { input: "true ? 'a' : 'b'", expected: "a" }, + { input: "false ? 'a' : 'b'", expected: "b" }, + { input: "true ? false : true", expected: false }, + { input: "false ? false : true", expected: true }, + { input: "true ? literalValue : true", expected: "literal" }, + { input: "true ? variableValue : true" }, + { input: "true ? maybeUndefinedValue : true" }, + { input: "true ? maybeBooleanValue : true", expected: false }, + { input: "true ? maybeUndefinedValue : true", options: { strictNullChecks: true } }, + { + input: "true ? maybeBooleanValue : true", + expected: false, + options: { strictNullChecks: true }, + }, + { input: "true ? undefined : true", options: { strictNullChecks: true } }, + { input: "true ? null : true", options: { strictNullChecks: true } }, + { input: "true ? false : true", expected: false, options: { luaTarget: LuaTarget.Lua51 } }, + { input: "false ? false : true", expected: true, options: { luaTarget: LuaTarget.Lua51 } }, + { input: "true ? undefined : true", options: { luaTarget: LuaTarget.Lua51 } }, + { input: "true ? false : true", expected: false, options: { luaTarget: LuaTarget.LuaJIT } }, + { input: "false ? false : true", expected: true, options: { luaTarget: LuaTarget.LuaJIT } }, + { input: "true ? undefined : true", options: { luaTarget: LuaTarget.LuaJIT } }, +])("Ternary operator (%p)", ({ input, expected, options }) => { + const result = util.transpileAndExecute( + `const literalValue = 'literal'; + let variableValue:string; + let maybeBooleanValue:string|boolean = false; + let maybeUndefinedValue:string|undefined; + return ${input};`, + options, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { expression: "inst.field", expected: 8 }, + { expression: "inst.field + 3", expected: 8 + 3 }, + { expression: "inst.field * 3", expected: 8 * 3 }, + { expression: "inst.field / 2", expected: 8 / 2 }, + { expression: "inst.field && 3", expected: 8 && 3 }, + { expression: "inst.field || 3", expected: 8 || 3 }, + { expression: "(inst.field + 3) & 3", expected: (8 + 3) & 3 }, + { expression: "inst.field | 3", expected: 8 | 3 }, + { expression: "inst.field << 3", expected: 8 << 3 }, + { expression: "inst.field >>> 1", expected: 8 >> 1 }, + { expression: "inst.field = 3", expected: 3 }, + { expression: `"abc" + inst.field`, expected: "abc8" }, +])("Get accessor expression (%p)", ({ expression, expected }) => { + const source = + `class MyClass {` + + ` public _field: number;` + + ` public get field(): number { return this._field + 4; }` + + ` public set field(v: number) { this._field = v; }` + + `}` + + `var inst = new MyClass();` + + `inst._field = 4;` + + `return ${expression};`; + + const result = util.transpileAndExecute(source); + + expect(result).toBe(expected); +}); + +test.each([ + { expression: "= 4", expected: 4 + 4 }, + { expression: "-= 3", expected: 4 - 3 + 4 }, + { expression: "+= 3", expected: 4 + 3 + 4 }, + { expression: "*= 3", expected: 4 * 3 + 4 }, + { expression: "/= 2", expected: 4 / 2 + 4 }, + { expression: "&= 3", expected: (4 & 3) + 4 }, + { expression: "|= 3", expected: (4 | 3) + 4 }, + { expression: "<<= 3", expected: (4 << 3) + 4 }, + { expression: ">>>= 3", expected: (4 >> 3) + 4 }, +])("Set accessorExpression (%p)", ({ expression, expected }) => { + const source = + `class MyClass {` + + ` public _field: number = 4;` + + ` public get field(): number { return this._field; }` + + ` public set field(v: number) { this._field = v + 4; }` + + `}` + + `var inst = new MyClass();` + + `inst.field ${expression};` + + `return inst._field;`; + + const result = util.transpileAndExecute(source); + + expect(result).toBe(expected); +}); + +test.each([ + { expression: "inst.baseField", expected: 7 }, + { expression: "inst.field", expected: 6 }, + { expression: "inst.superField", expected: 5 }, + { expression: "inst.superBaseField", expected: 4 }, +])("Inherited accessors (%p)", ({ expression, expected }) => { + const source = + `class MyBaseClass {` + + ` public _baseField: number;` + + ` public get baseField(): number { return this._baseField + 6; }` + + ` public set baseField(v: number) { this._baseField = v; }` + + `}` + + `class MyClass extends MyBaseClass {` + + ` public _field: number;` + + ` public get field(): number { return this._field + 4; }` + + ` public set field(v: number) { this._field = v; }` + + `}` + + `class MySuperClass extends MyClass {` + + ` public _superField: number;` + + ` public get superField(): number { return this._superField + 2; }` + + ` public set superField(v: number) { this._superField = v; }` + + ` public get superBaseField() { return this.baseField - 3; }` + + `}` + + `var inst = new MySuperClass();` + + `inst.baseField = 1;` + + `inst.field = 2;` + + `inst.superField = 3;` + + `return ${expression};`; + + const result = util.transpileAndExecute(source); + expect(result).toBe(expected); +}); + +test.each([ + { expression: "return x.value;", expected: 1 }, + { expression: "x.value = 3; return x.value;", expected: 3 }, +])("Union accessors (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `class A{ get value(){ return this.v || 1; } set value(v){ this.v = v; } v: number; } + class B{ get value(){ return this.v || 2; } set value(v){ this.v = v; } v: number; } + let x: A|B = new A(); + ${expression}`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { expression: "i++", expected: 10 }, + { expression: "i--", expected: 10 }, + { expression: "++i", expected: 11 }, + { expression: "--i", expected: 9 }, +])("Incrementor value (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute(`let i = 10; return ${expression};`); + + expect(result).toBe(expected); +}); + +test.each([ + { lambda: "a++", expected: "val3" }, + { lambda: "a--", expected: "val3" }, + { lambda: "--a", expected: "val2" }, + { lambda: "++a", expected: "val4" }, +])("Template string expression (%p)", ({ lambda, expected }) => { + const result = util.transpileAndExecute("let a = 3; return `val${" + lambda + "}`;"); + + expect(result).toEqual(expected); +}); + +test.each([{ expression: "x = y", expected: "y" }, { expression: "x += y", expected: "xy" }])( + "Assignment expressions (%p)", + ({ expression, expected }) => { const result = util.transpileAndExecute(`let x = "x"; let y = "y"; return ${expression};`); - Expect(result).toBe(expected); - } - - @TestCase("x = o.p", "o") - @TestCase("x = a[0]", "a") - @TestCase("x = y = o.p", "o") - @TestCase("x = o.p", "o") - @Test("Assignment expressions using temp") - public assignmentWithTempExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `let x = "x"; - let y = "y"; - let o = {p: "o"}; - let a = ["a"]; - return ${expression};`); - Expect(result).toBe(expected); - } - - @TestCase("o.p = x", "x") - @TestCase("a[0] = x", "x") - @TestCase("o.p = a[0]", "a") - @TestCase("o.p = a[0] = x", "x") - @Test("Property assignment expressions") - public propertyAssignmentExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `let x = "x"; - let o = {p: "o"}; - let a = ["a"]; - return ${expression};`); - Expect(result).toBe(expected); - } - - @TestCase("x = t()", "t0,t1") - @TestCase("x = tr()", "tr0,tr1") - @TestCase("[x[1], x[0]] = t()", "t0,t1") - @TestCase("[x[1], x[0]] = tr()", "tr0,tr1") - @TestCase("x = [y[1], y[0]]", "y1,y0") - @TestCase("[x[0], x[1]] = [y[1], y[0]]", "y1,y0") - @Test("Tuple assignment expressions") - public tupleAssignmentExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `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"] }; - const r = ${expression}; - return \`\${r[0]},\${r[1]}\``); - Expect(result).toBe(expected); - } - - @Test("Block expression") - public blockExpresion(): void { - const result = util.transpileAndExecute(`let a = 4; {let a = 42; } return a;`); - Expect(result).toBe(4); - } - - @Test("Non-null expression") - public nonNullExpression(): void { - const result = util.transpileAndExecute(`function abc(): number | undefined { return 3; } - const a: number = abc()!; - return a;`); - Expect(result).toBe(3); - } - // ==================================== - // Test expected errors - // ==================================== - - @Test("Unknown unary postfix error") - public unknownUnaryPostfixError(): void { - const transformer = util.makeTestTransformer(); - - const mockExpression: any = { - operand: ts.createLiteral(false), - operator: ts.SyntaxKind.AsteriskToken, - }; - - Expect(() => transformer.transformPostfixUnaryExpression(mockExpression as ts.PostfixUnaryExpression)) - .toThrowError(TranspileError, "Unsupported unary postfix operator kind: AsteriskToken"); - } - - @Test("Unknown unary postfix error") - public unknownUnaryPrefixError(): void { - const transformer = util.makeTestTransformer(); - - const mockExpression: any = { - operand: ts.createLiteral(false), - operator: ts.SyntaxKind.AsteriskToken, - }; - - Expect(() => transformer.transformPrefixUnaryExpression(mockExpression as ts.PrefixUnaryExpression)) - .toThrowError(TranspileError, "Unsupported unary prefix operator kind: AsteriskToken"); - } - - @Test("Incompatible fromCodePoint expression error") - public incompatibleFromCodePointExpression(): void { - const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); - - const identifier = ts.createIdentifier("fromCodePoint"); - Expect(() => transformer.transformStringExpression(identifier)) - .toThrowError(TranspileError, "string property fromCodePoint is/are not supported " + - "for target Lua jit."); - } - - @Test("Unknown string expression error") - public unknownStringExpression(): void { - const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); - - const identifier = ts.createIdentifier("abcd"); - Expect(() => transformer.transformStringExpression(identifier)) - .toThrowError(TranspileError, "string property abcd is/are not supported for target Lua jit."); - } - - @Test("Unsupported array function error") - public unsupportedArrayFunctionError(): void { - const transformer = util.makeTestTransformer(); - - const mockNode: any = { - kind: ts.SyntaxKind.CallExpression, - arguments: [], - caller: ts.createLiteral(false), - expression: {name: ts.createIdentifier("unknownFunction"), expression: ts.createLiteral(false)}, - }; - - Expect(() => transformer.transformArrayCallExpression(mockNode as ts.CallExpression)) - .toThrowError(TranspileError, "Unsupported property on array: unknownFunction"); - } - - @Test("Unsupported math property error") - public unsupportedMathPropertyError(): void { - const transformer = util.makeTestTransformer(); - - Expect(() => transformer.transformMathExpression(ts.createIdentifier("unknownProperty"))) - .toThrowError(TranspileError, "Unsupported property on math: unknownProperty"); - } - - @Test("Unsupported object literal element error") - public unsupportedObjectLiteralElementError(): void { - const transformer = util.makeTestTransformer(); - - const mockObject: any = { - properties: [{ + expect(result).toBe(expected); + }, +); + +test.each([ + { expression: "x = o.p", expected: "o" }, + { expression: "x = a[0]", expected: "a" }, + { expression: "x = y = o.p", expected: "o" }, + { expression: "x = o.p", expected: "o" }, +])("Assignment expressions using temp (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `let x = "x"; + let y = "y"; + let o = {p: "o"}; + let a = ["a"]; + return ${expression};`, + ); + expect(result).toBe(expected); +}); + +test.each([ + { expression: "o.p = x", expected: "x" }, + { expression: "a[0] = x", expected: "x" }, + { expression: "o.p = a[0]", expected: "a" }, + { expression: "o.p = a[0] = x", expected: "x" }, +])("Property assignment expressions (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `let x = "x"; + let o = {p: "o"}; + let a = ["a"]; + return ${expression};`, + ); + expect(result).toBe(expected); +}); + +test.each([ + { expression: "x = t()", expected: "t0,t1" }, + { expression: "x = tr()", expected: "tr0,tr1" }, + { expression: "[x[1], x[0]] = t()", expected: "t0,t1" }, + { expression: "[x[1], x[0]] = tr()", expected: "tr0,tr1" }, + { expression: "x = [y[1], y[0]]", expected: "y1,y0" }, + { expression: "[x[0], x[1]] = [y[1], y[0]]", expected: "y1,y0" }, +])("Tuple assignment expressions (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `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"] }; + const r = ${expression}; + return \`\${r[0]},\${r[1]}\``, + ); + expect(result).toBe(expected); +}); + +test("Block expression", () => { + const result = util.transpileAndExecute(`let a = 4; {let a = 42; } return a;`); + expect(result).toBe(4); +}); + +test("Non-null expression", () => { + const result = util.transpileAndExecute(`function abc(): number | undefined { return 3; } + const a: number = abc()!; + return a;`); + expect(result).toBe(3); +}); + +test("Unknown unary postfix error", () => { + const transformer = util.makeTestTransformer(); + + const mockExpression: any = { + operand: ts.createLiteral(false), + operator: ts.SyntaxKind.AsteriskToken, + }; + + expect(() => + transformer.transformPostfixUnaryExpression(mockExpression as ts.PostfixUnaryExpression), + ).toThrowExactError( + new TranspileError("Unsupported unary postfix operator kind: AsteriskToken"), + ); +}); + +test("Unknown unary postfix error", () => { + const transformer = util.makeTestTransformer(); + + const mockExpression: any = { + operand: ts.createLiteral(false), + operator: ts.SyntaxKind.AsteriskToken, + }; + + expect(() => + transformer.transformPrefixUnaryExpression(mockExpression as ts.PrefixUnaryExpression), + ).toThrowExactError( + new TranspileError("Unsupported unary prefix operator kind: AsteriskToken"), + ); +}); + +test("Incompatible fromCodePoint expression error", () => { + const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); + + const identifier = ts.createIdentifier("fromCodePoint"); + expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( + new TranspileError( + "string property fromCodePoint is/are not supported for target Lua jit.", + ), + ); +}); + +test("Unknown string expression error", () => { + const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); + + const identifier = ts.createIdentifier("abcd"); + expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( + new TranspileError("string property abcd is/are not supported for target Lua jit."), + ); +}); + +test("Unsupported array function error", () => { + const transformer = util.makeTestTransformer(); + + const mockNode: any = { + kind: ts.SyntaxKind.CallExpression, + arguments: [], + caller: ts.createLiteral(false), + expression: { + name: ts.createIdentifier("unknownFunction"), + expression: ts.createLiteral(false), + }, + }; + + expect(() => + transformer.transformArrayCallExpression(mockNode as ts.CallExpression), + ).toThrowExactError(new TranspileError("Unsupported property on array: unknownFunction")); +}); + +test("Unsupported math property error", () => { + const transformer = util.makeTestTransformer(); + + expect(() => + transformer.transformMathExpression(ts.createIdentifier("unknownProperty")), + ).toThrowExactError(new TranspileError("Unsupported property on math: unknownProperty")); +}); + +test("Unsupported object literal element error", () => { + const transformer = util.makeTestTransformer(); + + const mockObject: any = { + properties: [ + { kind: ts.SyntaxKind.FalseKeyword, name: ts.createIdentifier("testProperty"), - }], - }; - - Expect(() => transformer.transformObjectLiteral(mockObject as ts.ObjectLiteralExpression)) - .toThrowError(TranspileError, "Unsupported object literal element kind: FalseKeyword"); - } -} + }, + ], + }; + + expect(() => + transformer.transformObjectLiteral(mockObject as ts.ObjectLiteralExpression), + ).toThrowExactError( + new TranspileError("Unsupported object literal element kind: FalseKeyword"), + ); +}); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index 55161623b..5d1fb1763 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -1,52 +1,82 @@ -import { Expect, Test, TestCase } from "alsatian"; - import * as ts from "typescript"; -import * as util from "../src/util"; - -export class FunctionTests { - - @Test("Arrow Function Expression") - public arrowFunctionExpression(): void - { - const result = util.transpileAndExecute(`let add = (a, b) => a+b; return add(1,2);`); - - // Assert - Expect(result).toBe(3); - } - - @TestCase("i++", 15) - @TestCase("i--", 5) - @TestCase("++i", 15) - @TestCase("--i", 5) - @Test("Arrow function unary expression") - public arrowFunctionUnary(lambda: string, expected: number): void { - const result = util.transpileAndExecute(`let i = 10; [1,2,3,4,5].forEach(() => ${lambda}); return i;`); - - Expect(result).toBe(expected); - } - - @TestCase("b => a = b", 5) - @TestCase("b => a += b", 15) - @TestCase("b => a -= b", 5) - @TestCase("b => a *= b", 50) - @TestCase("b => a /= b", 2) - @TestCase("b => a **= b", 100000) - @TestCase("b => a %= b", 0) - @Test("Arrow function assignment") - public arrowFunctionAssignment(lambda: string, expected: number): void - { - const result = util.transpileAndExecute(`let a = 10; let lambda = ${lambda}; - lambda(5); return a;`); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase([]) - @TestCase([5]) - @TestCase([1, 2]) - @Test("Arrow Default Values") - public arrowExpressionDefaultValues(inp: number[]): void { +import * as util from "../util"; + +test("Arrow Function Expression", () => { + const result = util.transpileAndExecute(`let add = (a, b) => a+b; return add(1,2);`); + + expect(result).toBe(3); +}); + +test.each([ + { lambda: "i++", expected: 15 }, + { lambda: "i--", expected: 5 }, + { lambda: "++i", expected: 15 }, + { lambda: "--i", expected: 5 }, +])("Arrow function unary expression (%p)", ({ lambda, expected }) => { + const result = util.transpileAndExecute( + `let i = 10; [1,2,3,4,5].forEach(() => ${lambda}); return i;`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { lambda: "b => a = b", expected: 5 }, + { lambda: "b => a += b", expected: 15 }, + { lambda: "b => a -= b", expected: 5 }, + { lambda: "b => a *= b", expected: 50 }, + { lambda: "b => a /= b", expected: 2 }, + { lambda: "b => a **= b", expected: 100000 }, + { lambda: "b => a %= b", expected: 0 }, +])("Arrow function assignment (%p)", ({ lambda, expected }) => { + const result = util.transpileAndExecute(`let a = 10; let lambda = ${lambda}; + lambda(5); return a;`); + + expect(result).toBe(expected); +}); + +test.each([{ inp: [] }, { inp: [5] }, { inp: [1, 2] }])("Arrow Default Values (%p)", ({ inp }) => { + // Default value is 3 for v1 + const v1 = inp.length > 0 ? inp[0] : 3; + // Default value is 4 for v2 + const v2 = inp.length > 1 ? inp[1] : 4; + + const callArgs = inp.join(","); + + const result = util.transpileAndExecute( + `let add = (a: number = 3, b: number = 4) => a+b; + return add(${callArgs});`, + ); + + expect(result).toBe(v1 + v2); +}); + +test("Function Expression", () => { + const result = util.transpileAndExecute( + `let add = function(a, b) {return a+b}; return add(1,2);`, + ); + + expect(result).toBe(3); +}); + +test("Function definition scope", () => { + const result = util.transpileAndExecute(`function abc() { function xyz() { return 5; } }\n + function def() { function xyz() { return 3; } abc(); return xyz(); }\n + return def();`); + + expect(result).toBe(3); +}); + +test("Function default parameter", () => { + const result = util.transpileAndExecute(`function abc(defaultParam: string = "abc") { return defaultParam; }\n + return abc() + abc("def");`); + + expect(result).toBe("abcdef"); +}); + +test.each([{ inp: [] }, { inp: [5] }, { inp: [1, 2] }])( + "Function Default Values (%p)", + ({ inp }) => { // Default value is 3 for v1 const v1 = inp.length > 0 ? inp[0] : 3; // Default value is 4 for v2 @@ -54,473 +84,383 @@ export class FunctionTests { const callArgs = inp.join(","); - // Transpile/Execute - const result = util.transpileAndExecute( - `let add = (a: number = 3, b: number = 4) => a+b; - return add(${callArgs});` - ); - - // Assert - Expect(result).toBe(v1 + v2); - } - - @Test("Function Expression") - public functionExpression(): void - { - const result = util.transpileAndExecute(`let add = function(a, b) {return a+b}; return add(1,2);`); - - // Assert - Expect(result).toBe(3); - } - - @Test("Function definition scope") - public functionDefinitionScope(): void - { - const result = util.transpileAndExecute(`function abc() { function xyz() { return 5; } }\n - function def() { function xyz() { return 3; } abc(); return xyz(); }\n - return def();`); - - // Assert - Expect(result).toBe(3); - } - - @Test("Function default parameter") - public functionDefaultParameter(): void - { - const result = util.transpileAndExecute(`function abc(defaultParam: string = "abc") { return defaultParam; }\n - return abc() + abc("def");`); - - // Assert - Expect(result).toBe("abcdef"); - } - - @TestCase([]) - @TestCase([5]) - @TestCase([1, 2]) - @Test("Function Default Values") - public functionExpressionDefaultValues(inp: number[]): void { - // Default value is 3 for v1 - const v1 = inp.length > 0 ? inp[0] : 3; - // Default value is 4 for v2 - const v2 = inp.length > 1 ? inp[1] : 4; - - const callArgs = inp.join(","); - - // Transpile/Execute const result = util.transpileAndExecute( `let add = function(a: number = 3, b: number = 4) { return a+b; }; - return add(${callArgs});` + return add(${callArgs});`, ); - // Assert - Expect(result).toBe(v1 + v2); - } + expect(result).toBe(v1 + v2); + }, +); - @Test("Class method call") - public classMethod(): void { - const returnValue = 4; - const source = `class TestClass { - public classMethod(): number { return ${returnValue}; } - } +test("Class method call", () => { + const returnValue = 4; + const source = `class TestClass { + public classMethod(): number { return ${returnValue}; } + } - const classInstance = new TestClass(); - return classInstance.classMethod();`; + const classInstance = new TestClass(); + return classInstance.classMethod();`; - // Transpile/Execute - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - // Assert - Expect(result).toBe(returnValue); - } + expect(result).toBe(returnValue); +}); - @Test("Class dot method call void") - public classDotMethod(): void { - const returnValue = 4; - const source = `class TestClass { - public dotMethod: () => number = () => ${returnValue}; - } +test("Class dot method call void", () => { + const returnValue = 4; + const source = `class TestClass { + public dotMethod: () => number = () => ${returnValue}; + } - const classInstance = new TestClass(); - return classInstance.dotMethod();`; + const classInstance = new TestClass(); + return classInstance.dotMethod();`; - // Transpile/Execute - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - // Assert - Expect(result).toBe(returnValue); - } - - @Test("Class dot method call with parameter") - public classDotMethod2(): void { - const returnValue = 4; - const source = `class TestClass { - public dotMethod: (x: number) => number = x => 3 * x; - } + expect(result).toBe(returnValue); +}); - const classInstance = new TestClass(); - return classInstance.dotMethod(${returnValue});`; +test("Class dot method call with parameter", () => { + const returnValue = 4; + const source = `class TestClass { + public dotMethod: (x: number) => number = x => 3 * x; + } - // Transpile - const result = util.transpileAndExecute(source); + const classInstance = new TestClass(); + return classInstance.dotMethod(${returnValue});`; - // Assert - Expect(result).toBe(3 * returnValue); - } + const result = util.transpileAndExecute(source); - @Test("Class static dot method") - public classDotMethodStatic(): void { - const returnValue = 4; - const source = `class TestClass { - public static dotMethod: () => number = () => ${returnValue}; - } + expect(result).toBe(3 * returnValue); +}); - return TestClass.dotMethod();`; +test("Class static dot method", () => { + const returnValue = 4; + const source = `class TestClass { + public static dotMethod: () => number = () => ${returnValue}; + } - // Transpile/Execute - const result = util.transpileAndExecute(source); + return TestClass.dotMethod();`; - // Assert - Expect(result).toBe(returnValue); - } + const result = util.transpileAndExecute(source); - @Test("Class static dot method with parameter") - public classDotMethodStaticWithParameter(): void { - const returnValue = 4; - const source = `class TestClass { - public static dotMethod: (x: number) => number = x => 3 * x; - } + expect(result).toBe(returnValue); +}); - return TestClass.dotMethod(${returnValue});`; +test("Class static dot method with parameter", () => { + const returnValue = 4; + const source = `class TestClass { + public static dotMethod: (x: number) => number = x => 3 * x; + } - // Transpile - const result = util.transpileAndExecute(source); + return TestClass.dotMethod(${returnValue});`; - // Assert - Expect(result).toBe(3 * returnValue); - } + const result = util.transpileAndExecute(source); - @Test("Function bind") - public functionBind(): void { - const source = `const abc = function (this: { a: number }, a: string, b: string) { return this.a + a + b; } - return abc.bind({ a: 4 }, "b")("c");`; + expect(result).toBe(3 * returnValue); +}); - const result = util.transpileAndExecute(source); +test("Function bind", () => { + const source = `const abc = function (this: { a: number }, a: string, b: string) { return this.a + a + b; } + return abc.bind({ a: 4 }, "b")("c");`; - Expect(result).toBe("4bc"); - } + const result = util.transpileAndExecute(source); - @Test("Function apply") - public functionApply(): void { - const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } - return abc.apply({ a: 4 }, ["b"]);`; + expect(result).toBe("4bc"); +}); - const result = util.transpileAndExecute(source); +test("Function apply", () => { + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } + return abc.apply({ a: 4 }, ["b"]);`; - Expect(result).toBe("4b"); - } + const result = util.transpileAndExecute(source); - @Test("Function call") - public functionCall(): void { - const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } - return abc.call({ a: 4 }, "b");`; + expect(result).toBe("4b"); +}); - const result = util.transpileAndExecute(source); +test("Function call", () => { + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } + return abc.call({ a: 4 }, "b");`; - Expect(result).toBe("4b"); - } + const result = util.transpileAndExecute(source); - @Test("Invalid property access call transpilation") - public invalidPropertyCall(): void { - const transformer = util.makeTestTransformer(); + expect(result).toBe("4b"); +}); - const mockObject: any = { - expression: ts.createLiteral("abc"), - }; +test("Invalid property access call transpilation", () => { + const transformer = util.makeTestTransformer(); - Expect(() => transformer.transformPropertyCall(mockObject as ts.CallExpression)) - .toThrowError(Error, "Tried to transpile a non-property call as property call."); - } + const mockObject: any = { + expression: ts.createLiteral("abc"), + }; - @Test("Function dead code after return") - public functionDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `function abc() { return 3; const a = 5; } return abc();`); + expect(() => + transformer.transformPropertyCall(mockObject as ts.CallExpression), + ).toThrowExactError(new Error("Tried to transpile a non-property call as property call.")); +}); - Expect(result).toBe(3); - } +test("Function dead code after return", () => { + const result = util.transpileAndExecute( + `function abc() { return 3; const a = 5; } return abc();`, + ); - @Test("Method dead code after return") - public methodDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `class def { public static abc() { return 3; const a = 5; } } return def.abc();`); + expect(result).toBe(3); +}); - Expect(result).toBe(3); - } +test("Method dead code after return", () => { + const result = util.transpileAndExecute( + `class def { public static abc() { return 3; const a = 5; } } return def.abc();`, + ); - @Test("Recursive function definition") - public recursiveFunctionDefinition(): void { - const result = util.transpileAndExecute( - `function f() { return typeof f; }; return f();`); + expect(result).toBe(3); +}); - Expect(result).toBe("function"); - } +test("Recursive function definition", () => { + const result = util.transpileAndExecute(`function f() { return typeof f; }; return f();`); - @Test("Recursive function expression") - public recursiveFunctionExpression(): void { - const result = util.transpileAndExecute( - `let f = function() { return typeof f; }; return f();`); + expect(result).toBe("function"); +}); - Expect(result).toBe("function"); - } +test("Recursive function expression", () => { + const result = util.transpileAndExecute(`let f = function() { return typeof f; }; return f();`); - @Test("Wrapped recursive function expression") - public wrappedRecursiveFunctionExpression(): void { - const result = util.transpileAndExecute( - `function wrap(fn: T) { return fn; } - let f = wrap(function() { return typeof f; }); return f();`); + expect(result).toBe("function"); +}); - Expect(result).toBe("function"); - } +test("Wrapped recursive function expression", () => { + const result = util.transpileAndExecute( + `function wrap(fn: T) { return fn; } + let f = wrap(function() { return typeof f; }); return f();`, + ); - @Test("Recursive arrow function") - public recursiveArrowFunction(): void { - const result = util.transpileAndExecute( - `let f = () => typeof f; return f();`); + expect(result).toBe("function"); +}); - Expect(result).toBe("function"); - } +test("Recursive arrow function", () => { + const result = util.transpileAndExecute(`let f = () => typeof f; return f();`); - @Test("Wrapped recursive arrow function") - public wrappedRecursiveArrowFunction(): void { - const result = util.transpileAndExecute( - `function wrap(fn: T) { return fn; } - let f = wrap(() => typeof f); return f();`); + expect(result).toBe("function"); +}); - Expect(result).toBe("function"); - } +test("Wrapped recursive arrow function", () => { + const result = util.transpileAndExecute( + `function wrap(fn: T) { return fn; } + let f = wrap(() => typeof f); return f();`, + ); - @Test("Object method declaration") - public objectMethodDeclaration(): void { - const result = util.transpileAndExecute( - `let o = { v: 4, m(i: number): number { return this.v * i; } }; return o.m(3);`); - Expect(result).toBe(12); - } + expect(result).toBe("function"); +}); - @TestCase(["bar"], "foobar") - @TestCase(["baz", "bar"], "bazbar") - @Test("Function overload") - public functionOverload(args: string[], expectResult: string): void { - const code = `class O { - prop = "foo"; - method(s: string): string; - method(this: void, s1: string, s2: string): string; - method(s1: string) { - if (typeof this === "string") { - return this + s1; - } - return this.prop + s1; - } - }; - const o = new O(); - return o.method(${args.map(a => "\"" + a + "\"").join(", ")});`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(expectResult); - } +test("Object method declaration", () => { + const result = util.transpileAndExecute( + `let o = { v: 4, m(i: number): number { return this.v * i; } }; return o.m(3);`, + ); + expect(result).toBe(12); +}); - @Test("Nested Function") - public nestedFunction(): void { - const code = `class C { - private prop = "bar"; - public outer() { - const o = { - prop: "foo", - innerFunc: function() { return this.prop; }, - innerArrow: () => this.prop - }; - return o.innerFunc() + o.innerArrow(); +test.each([ + { args: ["bar"], expectResult: "foobar" }, + { args: ["baz", "bar"], expectResult: "bazbar" }, +])("Function overload (%p)", ({ args, expectResult }) => { + const code = `class O { + prop = "foo"; + method(s: string): string; + method(this: void, s1: string, s2: string): string; + method(s1: string) { + if (typeof this === "string") { + return this + s1; } + return this.prop + s1; } - let c = new C(); - return c.outer();`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foobar"); - } - - @TestCase("abc", "abc") - @TestCase("abc", "def") - @Test("Dot vs Colon method call") - public dotVColonMethodCall(s1: string, s2: string): void - { + }; + const o = new O(); + return o.method(${args.map(a => '"' + a + '"').join(", ")});`; + const result = util.transpileAndExecute(code); + expect(result).toBe(expectResult); +}); + +test("Nested Function", () => { + const code = `class C { + private prop = "bar"; + public outer() { + const o = { + prop: "foo", + innerFunc: function() { return this.prop; }, + innerArrow: () => this.prop + }; + return o.innerFunc() + o.innerArrow(); + } + } + let c = new C(); + return c.outer();`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foobar"); +}); + +test.each([{ s1: "abc", s2: "abc" }, { s1: "abc", s2: "def" }])( + "Dot vs Colon method call (%p)", + ({ s1, s2 }) => { const result = util.transpileAndExecute( `class MyClass { - dotMethod(this: void, s: string) { - return s; - } - colonMethod(s: string) { - return s; - } - } - const inst = new MyClass(); - return inst.dotMethod("${s1}") == inst.colonMethod("${s2}");` - ); - Expect(result).toBe(s1 === s2); - } - - @Test("Element access call") - public elementAccessCall(): void { - const code = `class C { - prop = "bar"; - method(s: string) { return s + this.prop; } - } - const c = new C(); - return c['method']("foo"); - `; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foobar"); - } - - @Test("Element access call no args") - public elementAccessCallNoArgs(): void { - const code = `class C { - prop = "bar"; - method() { return this.prop; } + dotMethod(this: void, s: string) { + return s; } - const c = new C(); - return c['method'](); - `; - const result = util.transpileAndExecute(code); - Expect(result).toBe("bar"); - } - - @Test("Complex element access call") - public elementAccessCallComplex(): void { - const code = `class C { - prop = "bar"; - method(s: string) { return s + this.prop; } + colonMethod(s: string) { + return s; } - function getC() { return new C(); } - return getC()['method']("foo"); - `; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foobar"); } - - @Test("Complex element access call no args") - public elementAccessCallComplexNoArgs(): void { - const code = `class C { - prop = "bar"; - method() { return this.prop; } - } - function getC() { return new C(); } - return getC()['method'](); - `; - const result = util.transpileAndExecute(code); - Expect(result).toBe("bar"); - } - - @Test("Complex element access call statement") - public elementAccessCallComplexStatement(): void { - const code = `let foo: string; - class C { - prop = "bar"; - method(s: string) { foo = s + this.prop; } - } - function getC() { return new C(); } - getC()['method']("foo"); - return foo; - `; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foobar"); - } - - @TestCase(1, 1) - @TestCase(2, 42) - @Test("Generator functions value") - public generatorFunctionValue(iterations: number, expectedResult: number): void { + const inst = new MyClass(); + return inst.dotMethod("${s1}") == inst.colonMethod("${s2}");`, + ); + expect(result).toBe(s1 === s2); + }, +); + +test("Element access call", () => { + const code = `class C { + prop = "bar"; + method(s: string) { return s + this.prop; } + } + const c = new C(); + return c['method']("foo"); + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("foobar"); +}); + +test("Element access call no args", () => { + const code = `class C { + prop = "bar"; + method() { return this.prop; } + } + const c = new C(); + return c['method'](); + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("bar"); +}); + +test("Complex element access call", () => { + const code = `class C { + prop = "bar"; + method(s: string) { return s + this.prop; } + } + function getC() { return new C(); } + return getC()['method']("foo"); + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("foobar"); +}); + +test("Complex element access call no args", () => { + const code = `class C { + prop = "bar"; + method() { return this.prop; } + } + function getC() { return new C(); } + return getC()['method'](); + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("bar"); +}); + +test("Complex element access call statement", () => { + const code = `let foo: string; + class C { + prop = "bar"; + method(s: string) { foo = s + this.prop; } + } + function getC() { return new C(); } + getC()['method']("foo"); + return foo; + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("foobar"); +}); + +test.each([{ iterations: 1, expectedResult: 1 }, { iterations: 2, expectedResult: 42 }])( + "Generator functions value (%p)", + ({ iterations, expectedResult }) => { const code = `function* seq(value: number) { - let a = yield value + 1; - return 42; - } - const gen = seq(0); - let ret: number; - for(let i = 0; i < ${iterations}; ++i) - { - ret = gen.next(i).value; - } - return ret; - `; + let a = yield value + 1; + return 42; +} +const gen = seq(0); +let ret: number; +for(let i = 0; i < ${iterations}; ++i) +{ + ret = gen.next(i).value; +} +return ret; +`; const result = util.transpileAndExecute(code); - Expect(result).toBe(expectedResult); - } + expect(result).toBe(expectedResult); + }, +); - @TestCase(1, false) - @TestCase(2, true) - @Test("Generator functions done") - public generatorFunctionDone(iterations: number, expectedResult: boolean): void { +test.each([{ iterations: 1, expectedResult: false }, { iterations: 2, expectedResult: true }])( + "Generator functions done (%p)", + ({ iterations, expectedResult }) => { const code = `function* seq(value: number) { - let a = yield value + 1; - return 42; - } - const gen = seq(0); - let ret: boolean; - for(let i = 0; i < ${iterations}; ++i) - { - ret = gen.next(i).done; - } - return ret; - `; + let a = yield value + 1; + return 42; +} +const gen = seq(0); +let ret: boolean; +for(let i = 0; i < ${iterations}; ++i) +{ + ret = gen.next(i).done; +} +return ret; +`; const result = util.transpileAndExecute(code); - Expect(result).toBe(expectedResult); + expect(result).toBe(expectedResult); + }, +); + +test("Generator for..of", () => { + const code = `function* seq() { + yield(1); + yield(2); + yield(3); + return 4; + } + let result = 0; + for(let i of seq()) + { + result = result * 10 + i; } + return result`; + const result = util.transpileAndExecute(code); + expect(result).toBe(123); +}); - @Test("Generator for..of") - public generatorFunctionForOf(): void { - const code = `function* seq() { - yield(1); - yield(2); - yield(3); - return 4; +test("Function local overriding export", () => { + const code = `export const foo = 5; + function bar(foo: number) { + return foo; } - let result = 0; - for(let i of seq()) - { - result = result * 10 + i; + export const result = bar(7);`; + expect(util.transpileExecuteAndReturnExport(code, "result")).toBe(7); +}); + +test("Function using global as this", () => { + const code = `var foo = "foo"; + function bar(this: any) { + return this.foo; + }`; + expect(util.transpileAndExecute("return foo;", undefined, undefined, code)).toBe("foo"); +}); + +test("Function rest binding pattern", () => { + const result = util.transpileAndExecute( + `function bar(foo: string, ...[bar, baz]: [string, string]) { + return bar + baz + foo; } - return result`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(123); - } - - @Test("Function local overriding export") - public functionLocalOverridingExport(): void { - const code = - `export const foo = 5; - function bar(foo: number) { - return foo; - } - export const result = bar(7);`; - Expect(util.transpileExecuteAndReturnExport(code, "result")).toBe(7); - } - - @Test("Function using global as this") - public functionUsingGlobalAsThis(): void { - const code = - `var foo = "foo"; - function bar(this: any) { - return this.foo; - }`; - Expect(util.transpileAndExecute("return foo;", undefined, undefined, code)).toBe("foo"); - } + return bar("abc", "def", "xyz"); + `, + ); - @Test("Function rest binding pattern") - public functionRestBindingPattern(): void { - const result = util.transpileAndExecute( - `function bar(foo: string, ...[bar, baz]: [string, string]) { - return bar + baz + foo; - } - return bar("abc", "def", "xyz"); - `); - - Expect(result).toBe("defxyzabc"); - } -} + expect(result).toBe("defxyzabc"); +}); diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index 44ed9d0dd..f570913cb 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -1,257 +1,213 @@ -import * as ts from "typescript"; -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; -import { CompilerOptions, LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import { TranspileError } from "../../src/TranspileError"; - -export class HoistingTests { - @Test("Var Hoisting") - public varHoisting(): void { - const code = - `foo = "foo"; - var foo; - return foo;`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Exported Var Hoisting") - public exportedVarHoisting(): void { - const code = - `foo = "foo"; - export var foo;`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @TestCase("let") - @TestCase("const") - @Test("Let/Const Hoisting") - public letConstHoisting(varType: string): void { - const code = - `let bar: string; - function setBar() { bar = foo; } - ${varType} foo = "foo"; - setBar(); - return foo;`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @TestCase("let") - @TestCase("const") - @Test("Exported Let/Const Hoisting") - public exportedLetConstHoisting(varType: string): void { - const code = - `let bar: string; - function setBar() { bar = foo; } - export ${varType} foo = "foo"; - setBar();`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @Test("Global Function Hoisting") - public globalFunctionHoisting(): void { - const code = - `const foo = bar(); +import * as util from "../util"; + +test("Var Hoisting", () => { + const code = `foo = "foo"; + var foo; + return foo;`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Exported Var Hoisting", () => { + const code = `foo = "foo"; + export var foo;`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test.each(["let", "const"])("Let/Const Hoisting (%p)", varType => { + const code = `let bar: string; + function setBar() { bar = foo; } + ${varType} foo = "foo"; + setBar(); + return foo;`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test.each(["let", "const"])("Exported Let/Const Hoisting (%p)", varType => { + const code = `let bar: string; + function setBar() { bar = foo; } + export ${varType} foo = "foo"; + setBar();`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test("Global Function Hoisting", () => { + const code = `const foo = bar(); + function bar() { return "bar"; } + return foo;`; + const result = util.transpileAndExecute(code); + expect(result).toBe("bar"); +}); + +test("Local Function Hoisting", () => { + const code = `export const foo = bar(); + function bar() { return "bar"; }`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("bar"); +}); + +test("Exported Function Hoisting", () => { + const code = `const foo = bar(); + export function bar() { return "bar"; } + export const baz = foo;`; + const result = util.transpileExecuteAndReturnExport(code, "baz"); + expect(result).toBe("bar"); +}); + +test("Namespace Function Hoisting", () => { + const code = `let foo: string; + namespace NS { + foo = bar(); function bar() { return "bar"; } - return foo;`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("bar"); - } - - @Test("Local Function Hoisting") - public localFunctionHoisting(): void { - const code = - `export const foo = bar(); - function bar() { return "bar"; }`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("bar"); - } - - @Test("Exported Function Hoisting") - public exportedFunctionHoisting(): void { - const code = - `const foo = bar(); + }`; + const result = util.transpileAndExecute("return foo;", undefined, undefined, code); + expect(result).toBe("bar"); +}); + +test("Exported Namespace Function Hoisting", () => { + const code = `let foo: string; + namespace NS { + foo = bar(); export function bar() { return "bar"; } - export const baz = foo;`; - const result = util.transpileExecuteAndReturnExport(code, "baz"); - Expect(result).toBe("bar"); - } - - @Test("Namespace Function Hoisting") - public namespaceFunctionHoisting(): void { - const code = - `let foo: string; - namespace NS { - foo = bar(); - function bar() { return "bar"; } - }`; - const result = util.transpileAndExecute("return foo;", undefined, undefined, code); - Expect(result).toBe("bar"); - } - - @Test("Exported Namespace Function Hoisting") - public exportedNamespaceFunctionHoisting(): void { - const code = - `let foo: string; - namespace NS { - foo = bar(); - export function bar() { return "bar"; } - }`; - const result = util.transpileAndExecute("return foo;", undefined, undefined, code); - Expect(result).toBe("bar"); - } - - @TestCase("var", "foo") - @TestCase("let", "bar") - @TestCase("const", "bar") - @Test("Hoisting in Non-Function Scope") - public hoistingInNonFunctionScope(varType: string, expectResult: string): void { - const code = - `function foo() { - ${varType} bar = "bar"; - for (let i = 0; i < 1; ++i) { - ${varType} bar = "foo"; - } - return bar; + }`; + const result = util.transpileAndExecute("return foo;", undefined, undefined, code); + expect(result).toBe("bar"); +}); + +test.each([ + { varType: "var", expectResult: "foo" }, + { varType: "let", expectResult: "bar" }, + { varType: "const", expectResult: "bar" }, +])("Hoisting in Non-Function Scope (%p)", ({ varType, expectResult }) => { + const code = `function foo() { + ${varType} bar = "bar"; + for (let i = 0; i < 1; ++i) { + ${varType} bar = "foo"; } - return foo();`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(expectResult); - } - - @TestCase("", "foofoo") - @TestCase(" = \"bar\"", "barbar") - @Test("Var hoisting from child scope") - public varHoistingFromChildScope(initializer: string, expectResult: string): void { - const code = - `foo = "foo"; - let result: string; - if (true) { - var foo${initializer}; - result = foo; + return bar; + } + return foo();`; + const result = util.transpileAndExecute(code); + expect(result).toBe(expectResult); +}); + +test.each([ + { initializer: "", expectResult: "foofoo" }, + { initializer: ' = "bar"', expectResult: "barbar" }, +])("Var hoisting from child scope (%p)", ({ initializer, expectResult }) => { + const code = `foo = "foo"; + let result: string; + if (true) { + var foo${initializer}; + result = foo; + } + return foo + result;`; + const result = util.transpileAndExecute(code); + expect(result).toBe(expectResult); +}); + +test("Hoisting due to reference from hoisted function", () => { + const code = `const foo = "foo"; + const result = bar(); + function bar() { + return foo; + } + return result;`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Namespace Hoisting", () => { + const code = `function bar() { + return NS.foo; + } + namespace NS { + export let foo = "foo"; + } + export const foo = bar();`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test("Exported Namespace Hoisting", () => { + const code = `function bar() { + return NS.foo; + } + export namespace NS { + export let foo = "foo"; + } + export const foo = bar();`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test("Nested Namespace Hoisting", () => { + const code = `export namespace Outer { + export function bar() { + return Inner.foo; } - return foo + result;`; - const result = util.transpileAndExecute(code); - Expect(result).toBe(expectResult); - } - - @Test("Hoisting due to reference from hoisted function") - public hoistingDueToReferenceFromHoistedFunction(): void { - const code = - `const foo = "foo"; - const result = bar(); - function bar() { - return foo; - } - return result;`; - const result = util.transpileAndExecute(code); - Expect(result).toBe("foo"); - } - - @Test("Namespace Hoisting") - public namespaceHoisting(): void { - const code = - `function bar() { - return NS.foo; - } - namespace NS { + namespace Inner { export let foo = "foo"; } - export const foo = bar();`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @Test("Exported Namespace Hoisting") - public exportedNamespaceHoisting(): void { - const code = - `function bar() { - return NS.foo; - } - export namespace NS { - export let foo = "foo"; - } - export const foo = bar();`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @Test("Nested Namespace Hoisting") - public nestedNamespaceHoisting(): void { - const code = - `export namespace Outer { - export function bar() { - return Inner.foo; - } - namespace Inner { - export let foo = "foo"; - } - } - export const foo = Outer.bar();`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @Test("Class Hoisting") - public classHoisting(): void { - const code = - `function makeFoo() { - return new Foo(); - } - class Foo { - public bar = "foo"; - } - export const foo = makeFoo().bar;`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @Test("Enum Hoisting") - public enumHoisting(): void { - const code = - `function bar() { - return E.A; - } - enum E { - A = "foo" - } - export const foo = bar();`; - const result = util.transpileExecuteAndReturnExport(code, "foo"); - Expect(result).toBe("foo"); - } - - @TestCase(`foo = "foo"; var foo;`, "foo") - @TestCase(`foo = "foo"; export var foo;`, "foo") - @TestCase(`function setBar() { const bar = foo; } let foo = "foo";`, "foo") - @TestCase(`function setBar() { const bar = foo; } const foo = "foo";`, "foo") - @TestCase(`function setBar() { const bar = foo; } export let foo = "foo";`, "foo") - @TestCase(`function setBar() { const bar = foo; } export const foo = "foo";`, "foo") - @TestCase(`const foo = bar(); function bar() { return "bar"; }`, "bar") - @TestCase(`export const foo = bar(); function bar() { return "bar"; }`, "bar") - @TestCase(`const foo = bar(); export function bar() { return "bar"; }`, "bar") - @TestCase(`function bar() { return NS.foo; } namespace NS { export let foo = "foo"; }`, "NS") - @TestCase( - `export namespace O { export function f() { return I.foo; } namespace I { export let foo = "foo"; } }`, - "I" - ) - @TestCase(`function makeFoo() { return new Foo(); } class Foo {}`, "Foo") - @TestCase(`function bar() { return E.A; } enum E { A = "foo" }`, "E") - @Test("No Hoisting") - public noHoisting(code: string, identifier: string): void { - const compilerOptions: CompilerOptions = { - noHoisting: true, - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - Expect(() => util.transpileString(code, compilerOptions)).toThrowError( - TranspileError, + } + export const foo = Outer.bar();`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test("Class Hoisting", () => { + const code = `function makeFoo() { + return new Foo(); + } + class Foo { + public bar = "foo"; + } + export const foo = makeFoo().bar;`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test("Enum Hoisting", () => { + const code = `function bar() { + return E.A; + } + enum E { + A = "foo" + } + export const foo = bar();`; + const result = util.transpileExecuteAndReturnExport(code, "foo"); + expect(result).toBe("foo"); +}); + +test.each([ + { code: `foo = "foo"; var foo;`, identifier: "foo" }, + { code: `foo = "foo"; export var foo;`, identifier: "foo" }, + { code: `function setBar() { const bar = foo; } let foo = "foo";`, identifier: "foo" }, + { code: `function setBar() { const bar = foo; } const foo = "foo";`, identifier: "foo" }, + { code: `function setBar() { const bar = foo; } export let foo = "foo";`, identifier: "foo" }, + { code: `function setBar() { const bar = foo; } export const foo = "foo";`, identifier: "foo" }, + { code: `const foo = bar(); function bar() { return "bar"; }`, identifier: "bar" }, + { code: `export const foo = bar(); function bar() { return "bar"; }`, identifier: "bar" }, + { code: `const foo = bar(); export function bar() { return "bar"; }`, identifier: "bar" }, + { + code: `function bar() { return NS.foo; } namespace NS { export let foo = "foo"; }`, + identifier: "NS", + }, + { + code: `export namespace O { export function f() { return I.foo; } namespace I { export let foo = "foo"; } }`, + identifier: "I", + }, + { code: `function makeFoo() { return new Foo(); } class Foo {}`, identifier: "Foo" }, + { code: `function bar() { return E.A; } enum E { A = "foo" }`, identifier: "E" }, +])("No Hoisting (%p)", ({ code, identifier }) => { + expect(() => util.transpileString(code, { noHoisting: true })).toThrowExactError( + new TranspileError( `Identifier "${identifier}" was referenced before it was declared. The declaration ` + - "must be moved before the identifier's use, or hoisting must be enabled." - ); - } -} + "must be moved before the identifier's use, or hoisting must be enabled.", + ), + ); +}); diff --git a/test/unit/importexport.spec.ts b/test/unit/importexport.spec.ts index 7aca64caf..f77be8e70 100644 --- a/test/unit/importexport.spec.ts +++ b/test/unit/importexport.spec.ts @@ -1,17 +1,14 @@ -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; import { TranspileError } from "../../src/TranspileError"; -export class ImportExportTests -{ - @TestCase("export { default } from '...'") - @TestCase("export { x as default } from '...';") - @TestCase("export { default as x } from '...';") - @Test("Export default keyword disallowed") - public exportDefaultKeywordError(exportStatement: string): void { - const expectedTest = TSTLErrors.UnsupportedDefaultExport(undefined).message; - Expect(() => util.transpileString(exportStatement)).toThrowError(TranspileError, expectedTest); - } -} +test.each([ + "export { default } from '...'", + "export { x as default } from '...';", + "export { default as x } from '...';", +])("Export default keyword disallowed (%p)", exportStatement => { + const expectedTest = TSTLErrors.UnsupportedDefaultExport(undefined).message; + expect(() => util.transpileString(exportStatement)).toThrowExactError( + new TranspileError(expectedTest), + ); +}); diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index 7ac15a776..03187e7fe 100644 --- a/test/unit/json.spec.ts +++ b/test/unit/json.spec.ts @@ -1,27 +1,24 @@ -import { Expect, Test, TestCase } from "alsatian"; import { transpileString } from "../../src/Compiler"; import { TranspileError } from "../../src/TranspileError"; -import * as util from "../src/util"; +import * as util from "../util"; -export class JsonTests { - @Test("JSON") - @TestCase("0") - @TestCase('""') - @TestCase("[]") - @TestCase('[1, "2", []]') - @TestCase('{ "a": "b" }') - @TestCase('{ "a": { "b": "c" } }') - public json(json: string): void { - const lua = transpileString(json, { resolveJsonModule: true, noHeader: true }, false, "file.json") - .replace(/^return ([\s\S]+);$/, "return JSONStringify($1);"); +test.each(["0", '""', "[]", '[1, "2", []]', '{ "a": "b" }', '{ "a": { "b": "c" } }'])( + "JSON (%p)", + json => { + const lua = transpileString( + json, + { resolveJsonModule: true, noHeader: true }, + false, + "file.json", + ).replace(/^return ([\s\S]+);$/, "return JSONStringify($1);"); const result = util.executeLua(lua); - Expect(JSON.parse(result)).toEqual(JSON.parse(json)); - } + expect(JSON.parse(result)).toEqual(JSON.parse(json)); + }, +); - @Test("Empty JSON") - public emptyJson(): void { - Expect(() => transpileString("", { resolveJsonModule: true, noHeader: true }, false, "file.json")) - .toThrowError(TranspileError, "Invalid JSON file content"); - } -} +test("Empty JSON", () => { + expect(() => + transpileString("", { resolveJsonModule: true, noHeader: true }, false, "file.json"), + ).toThrowExactError(new TranspileError("Invalid JSON file content")); +}); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 153e243b2..a42e4292e 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -1,828 +1,789 @@ -import { Expect, Test, TestCase } from "alsatian"; import * as ts from "typescript"; import { TranspileError } from "../../src/TranspileError"; import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; -import * as util from "../src/util"; - -const deepEqual = require("deep-equal"); - -export class LuaLoopTests -{ - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("while") - public while(inp: number[], expected: number[]): void - { +import * as util from "../util"; + +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("while (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + let i = 0; + while (i < arrTest.length) { + arrTest[i] = arrTest[i] + 1; + i++; + } + return JSONStringify(arrTest);`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 1, 2, 1, 4] }])( + "while with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - while (i < arrTest.length) { - arrTest[i] = arrTest[i] + 1; - i++; - } - return JSONStringify(arrTest);` + let i = 0; + while (i < arrTest.length) { + if (i % 2 == 0) { + i++; + continue; + } + let j = 2; + while (j > 0) { + if (j == 2) { + j-- + continue; + } + arrTest[i] = j; + j--; + } + + i++; + } + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3, 4], [0, 1, 2, 1, 4]) - @Test("while with continue") - public whileWithContinue(inp: number[], expected: number[]): void - { +test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 1, 2, 1, 4] }])( + "dowhile with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - while (i < arrTest.length) { - if (i % 2 == 0) { - i++; - continue; - } - let j = 2; - while (j > 0) { - if (j == 2) { - j-- - continue; - } - arrTest[i] = j; - j--; - } - - i++; - } - return JSONStringify(arrTest);` + let i = 0; + do { + if (i % 2 == 0) { + i++; + continue; + } + let j = 2; + do { + if (j == 2) { + j-- + continue; + } + arrTest[i] = j; + j--; + } while (j > 0) + + i++; + } while (i < arrTest.length) + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase([0, 1, 2, 3, 4], [0, 1, 2, 1, 4]) - @Test("dowhile with continue") - public dowhileWithContinue(inp: number[], expected: number[]): void - { + expect(result).toBe(JSON.stringify(expected)); + }, +); + +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("for (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + for (let i = 0; i < arrTest.length; ++i) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, + ); + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( + "for with expression (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - do { - if (i % 2 == 0) { - i++; - continue; - } - let j = 2; - do { - if (j == 2) { - j-- - continue; - } - arrTest[i] = j; - j--; - } while (j > 0) - - i++; - } while (i < arrTest.length) - return JSONStringify(arrTest);` - ); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); + let i: number; + for (i = 0 * 1; i < arrTest.length; ++i) { + arrTest[i] = arrTest[i] + 1; } - - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("for") - public for(inp: number[], expected: number[]): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; i < arrTest.length; ++i) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("for with expression") - public forWithExpression(inp: number[], expected: number[]): void - { +test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 0, 2, 0, 4] }])( + "for with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i: number; - for (i = 0 * 1; i < arrTest.length; ++i) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` - ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + for (let i = 0; i < arrTest.length; i++) { + if (i % 2 == 0) { + continue; + } - @TestCase([0, 1, 2, 3, 4], [0, 0, 2, 0, 4]) - @Test("for with continue") - public forWithContinue(inp: number[], expected: number[]): void - { - // Transpile - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; i < arrTest.length; i++) { - if (i % 2 == 0) { - continue; - } - - for (let j = 0; j < 2; j++) { - if (j == 1) { - continue; - } - arrTest[i] = j; - } + for (let j = 0; j < 2; j++) { + if (j == 1) { + continue; } - return JSONStringify(arrTest); - ` - ); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); + arrTest[i] = j; + } } - - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("forMirror") - public forMirror(inp: number[], expected: number[]): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; arrTest.length > i; i++) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` + return JSONStringify(arrTest); + `, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3], [0, 1, 2, 3]) - @Test("forBreak") - public forBreak(inp: number[], expected: number[]): void - { +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( + "forMirror (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; i < arrTest.length; ++i) { - break; - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` + for (let i = 0; arrTest.length > i; i++) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("forNoDeclarations") - public forNoDeclarations(inp: number[], expected: number[]): void - { + expect(result).toBe(JSON.stringify(expected)); + }, +); + +test.each([{ inp: [0, 1, 2, 3], expected: [0, 1, 2, 3] }])("forBreak (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + for (let i = 0; i < arrTest.length; ++i) { + break; + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( + "forNoDeclarations (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (; i < arrTest.length; ++i) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` - ); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); + let i = 0; + for (; i < arrTest.length; ++i) { + arrTest[i] = arrTest[i] + 1; } - - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("forNoCondition") - public forNoCondition(inp: number[], expected: number[]): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (;; ++i) { - if (i >= arrTest.length) { - break; - } - - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("forNoPostExpression") - public forNoPostExpression(inp: number[], expected: number[]): void - { +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( + "forNoCondition (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (;;) { - if (i >= arrTest.length) { - break; - } + let i = 0; + for (;; ++i) { + if (i >= arrTest.length) { + break; + } - arrTest[i] = arrTest[i] + 1; - - i++; - } - return JSONStringify(arrTest);` + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3], [1, 2, 3, 4], "let i = 0; i < arrTest.length; i++") - @TestCase([0, 1, 2, 3], [1, 2, 3, 4], "let i = 0; i <= arrTest.length - 1; i++") - @TestCase([0, 1, 2, 3], [1, 2, 3, 4], "let i = 0; arrTest.length > i; i++") - @TestCase([0, 1, 2, 3], [1, 2, 3, 4], "let i = 0; arrTest.length - 1 >= i; i++") - @TestCase([0, 1, 2, 3], [1, 1, 3, 3], "let i = 0; i < arrTest.length; i += 2") - @TestCase([0, 1, 2, 3], [1, 2, 3, 4 ], "let i = arrTest.length - 1; i >= 0; i--") - @TestCase([0, 1, 2, 3], [0, 2, 2, 4], "let i = arrTest.length - 1; i >= 0; i -= 2") - @TestCase([0, 1, 2, 3], [0, 2, 2, 4], "let i = arrTest.length - 1; i > 0; i -= 2") - @Test("forheader") - public forheader(inp: number[], expected: number[], header: string): void - { +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( + "forNoPostExpression (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - for (${header}) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);` - ); + let i = 0; + for (;;) { + if (i >= arrTest.length) { + break; + } - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + arrTest[i] = arrTest[i] + 1; - @TestCase("for scope") - public forScope(): void { - const code = - `let i = 42; - for (let i = 0; i < 10; ++i) {} - return i;`; - Expect(util.transpileAndExecute(code)).toBe(42); + i++; } - - @TestCase({ ["test1"]: 0, ["test2"]: 1, ["test3"]: 2 }, { ["test1"]: 1, ["test2"]: 2, ["test3"]: 3 }) - @Test("forin[Object]") - public forinObject(inp: any, expected: any): void - { - const result = util.transpileAndExecute( - `let objTest = ${JSON.stringify(inp)}; - for (let key in objTest) { - objTest[key] = objTest[key] + 1; - } - return JSONStringify(objTest);` + return JSONStringify(arrTest);`, ); - // Assert - Expect(deepEqual(JSON.parse(result), expected)).toBe(true); - } - - @TestCase([1, 2, 3]) - @Test("forin[Array]") - public forinArray(inp: number[]): void { - // Transpile & Assert - Expect(() => - util.transpileString( - `let arrTest = ${JSON.stringify(inp)}; - for (let key in arrTest) { - arrTest[key]++; - }` - ) - ).toThrowError(TranspileError, "Iterating over arrays with 'for ... in' is not allowed."); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase({a: 0, b: 1, c: 2, d: 3, e: 4}, {a: 0, b: 0, c: 2, d: 0, e: 4}) - @Test("forin with continue") - public forinWithContinue(inp: number[], expected: number[]): void +test.each([ + { inp: [0, 1, 2, 3], expected: [1, 2, 3, 4], header: "let i = 0; i < arrTest.length; i++" }, + { + inp: [0, 1, 2, 3], + expected: [1, 2, 3, 4], + header: "let i = 0; i <= arrTest.length - 1; i++", + }, + { inp: [0, 1, 2, 3], expected: [1, 2, 3, 4], header: "let i = 0; arrTest.length > i; i++" }, + { + inp: [0, 1, 2, 3], + expected: [1, 2, 3, 4], + header: "let i = 0; arrTest.length - 1 >= i; i++", + }, + { inp: [0, 1, 2, 3], expected: [1, 1, 3, 3], header: "let i = 0; i < arrTest.length; i += 2" }, + { + inp: [0, 1, 2, 3], + expected: [1, 2, 3, 4], + header: "let i = arrTest.length - 1; i >= 0; i--", + }, + { + inp: [0, 1, 2, 3], + expected: [0, 2, 2, 4], + header: "let i = arrTest.length - 1; i >= 0; i -= 2", + }, { + inp: [0, 1, 2, 3], + expected: [0, 2, 2, 4], + header: "let i = arrTest.length - 1; i > 0; i -= 2", + }, +])("forheader (%p)", ({ inp, expected, header }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + for (${header}) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test("for scope", () => { + const code = `let i = 42; + for (let i = 0; i < 10; ++i) {} + return i;`; + expect(util.transpileAndExecute(code)).toBe(42); +}); + +test.each([ + { + inp: { ["test1"]: 0, ["test2"]: 1, ["test3"]: 2 }, + expected: { ["test1"]: 1, ["test2"]: 2, ["test3"]: 3 }, + }, +])("forin[Object] (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let objTest = ${JSON.stringify(inp)}; + for (let key in objTest) { + objTest[key] = objTest[key] + 1; + } + return JSONStringify(objTest);`, + ); + + expect(JSON.parse(result)).toEqual(expected); +}); + +test.each([{ inp: [1, 2, 3] }])("forin[Array] (%p)", ({ inp }) => { + expect(() => + util.transpileString( + `let arrTest = ${JSON.stringify(inp)}; + for (let key in arrTest) { + arrTest[key]++; + }`, + ), + ).toThrowExactError( + new TranspileError("Iterating over arrays with 'for ... in' is not allowed."), + ); +}); + +test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 }, expected: { a: 0, b: 0, c: 2, d: 0, e: 4 } }])( + "forin with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let obj = ${JSON.stringify(inp)}; - for (let i in obj) { - if (obj[i] % 2 == 0) { - continue; - } - - obj[i] = 0; - } - return JSONStringify(obj); - ` - ); + for (let i in obj) { + if (obj[i] % 2 == 0) { + continue; + } - // Assert - Expect(result).toBe(JSON.stringify(expected)); + obj[i] = 0; } - - @TestCase([0, 1, 2], [1, 2, 3]) - @Test("forof") - public forof(inp: any, expected: any): void - { - const result = util.transpileAndExecute( - `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - for (let value of objTest) { - arrResultTest.push(value + 1) - } - return JSONStringify(arrResultTest);` + return JSONStringify(obj); + `, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase([0, 1, 2], [1, 2, 3]) - @Test("forof existing variable") - public forofExistingVar(inp: any, expected: any): void - { + expect(result).toBe(JSON.stringify(expected)); + }, +); + +test.each([{ inp: [0, 1, 2], expected: [1, 2, 3] }])("forof (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let objTest = ${JSON.stringify(inp)}; + let arrResultTest = []; + for (let value of objTest) { + arrResultTest.push(value + 1) + } + return JSONStringify(arrResultTest);`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([{ inp: [0, 1, 2], expected: [1, 2, 3] }])( + "forof existing variable (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - let value: number; - for (value of objTest) { - arrResultTest.push(value + 1) - } - return JSONStringify(arrResultTest);` + let arrResultTest = []; + let value: number; + for (value of objTest) { + arrResultTest.push(value + 1) + } + return JSONStringify(arrResultTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([[1, 2], [2, 3], [3, 4]], [3, 5, 7]) - @Test("forof destructing") - public forofDestructing(inp: number[][], expected: any): void - { +test.each([{ inp: [[1, 2], [2, 3], [3, 4]], expected: [3, 5, 7] }])( + "forof destructing (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - for (let [a,b] of objTest) { - arrResultTest.push(a + b) - } - return JSONStringify(arrResultTest);` + let arrResultTest = []; + for (let [a,b] of objTest) { + arrResultTest.push(a + b) + } + return JSONStringify(arrResultTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([[1, 2], [2, 3], [3, 4]], [3, 5, 7]) - @Test("forof destructing with existing variables") - public forofDestructingExistingVars(inp: number[][], expected: any): void - { +test.each([{ inp: [[1, 2], [2, 3], [3, 4]], expected: [3, 5, 7] }])( + "forof destructing with existing variables (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - let a: number; - let b: number; - for ([a,b] of objTest) { - arrResultTest.push(a + b) - } - return JSONStringify(arrResultTest);` + let arrResultTest = []; + let a: number; + let b: number; + for ([a,b] of objTest) { + arrResultTest.push(a + b) + } + return JSONStringify(arrResultTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @TestCase([0, 1, 2, 3, 4], [0, 0, 2, 0, 4]) - @Test("forof with continue") - public forofWithContinue(inp: number[], expected: number[]): void - { +test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 0, 2, 0, 4] }])( + "forof with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let testArr = ${JSON.stringify(inp)}; - let a = 0; - for (let i of testArr) { - if (i % 2 == 0) { - a++; - continue; - } - - for (let j of [0, 1]) { - if (j == 1) { - continue; - } - testArr[a] = j; - } - a++; - } - return JSONStringify(testArr);` + let a = 0; + for (let i of testArr) { + if (i % 2 == 0) { + a++; + continue; + } + + for (let j of [0, 1]) { + if (j == 1) { + continue; + } + testArr[a] = j; + } + a++; + } + return JSONStringify(testArr);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @Test("forof with iterator") - public forofWithIterator(): void { - const code = `const arr = ["a", "b", "c"]; - function iter(): IterableIterator { - let i = 0; - return { - [Symbol.iterator]() { return this; }, - next() { return {value: arr[i], done: i++ >= arr.length} }, - } - } - let result = ""; - for (let e of iter()) { - result += e; - } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } - - @Test("forof with iterator and existing variable") - public forofWithIteratorExistingVar(): void { - const code = `const arr = ["a", "b", "c"]; - function iter(): IterableIterator { - let i = 0; - return { - [Symbol.iterator]() { return this; }, - next() { return {value: arr[i], done: i++ >= arr.length} }, - } - } - let result = ""; - let e: string; - for (e of iter()) { - result += e; - } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } - - @Test("forof destructuring with iterator") - public forofDestructuringWithIterator(): void { - const code = `const arr = ["a", "b", "c"]; - function iter(): IterableIterator<[string, string]> { - let i = 0; - return { - [Symbol.iterator]() { return this; }, - next() { return {value: [i.toString(), arr[i]], done: i++ >= arr.length} }, - } - } - let result = ""; - for (let [a, b] of iter()) { - result += a + b; - } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof destructuring with iterator and existing variables") - public forofDestructuringWithIteratorExistingVars(): void { - const code = `const arr = ["a", "b", "c"]; - function iter(): IterableIterator<[string, string]> { - let i = 0; - return { - [Symbol.iterator]() { return this; }, - next() { return {value: [i.toString(), arr[i]], done: i++ >= arr.length} }, - } - } - let result = ""; - let a: string; - let b: string; - for ([a, b] of iter()) { - result += a + b; - } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof lua iterator") - public forofLuaIterator(): void { - const code = `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;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } - - @Test("forof array lua iterator") - public forofArrayLuaIterator(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Array {} - function luaIter(): Iter { - let i = 0; - return (() => arr[i++]) as any; - } - let result = ""; - for (let e of luaIter()) { result += e; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } - - @Test("forof lua iterator with existing variable") - public forofLuaIteratorExistingVar(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Iterable {} - function luaIter(): Iter { - let i = 0; - return (() => arr[i++]) as any; - } - let result = ""; - let e: string; - for (e of luaIter()) { result += e; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } + expect(result).toBe(JSON.stringify(expected)); + }, +); - @Test("forof lua iterator destructuring") - public forofLuaIteratorDestructuring(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Iterable<[string, string]> {} - function luaIter(): Iter { - let i = 0; - return (() => arr[i] && [i.toString(), arr[i++]]) as any; - } - let result = ""; - for (let [a, b] of luaIter()) { result += a + b; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof lua iterator destructuring with existing variables") - public forofLuaIteratorDestructuringExistingVar(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Iterable<[string, string]> {} - function luaIter(): Iter { - let i = 0; - return (() => arr[i] && [i.toString(), arr[i++]]) as any; - } - let result = ""; - let a: string; - let b: string; - for ([a, b] of luaIter()) { result += a + b; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof lua iterator tuple-return") - public forofLuaIteratorTupleReturn(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - /** @tupleReturn */ - interface Iter extends Iterable<[string, string]> {} - function luaIter(): Iter { - let i = 0; - /** @tupleReturn */ - function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } - return iter as any; - } - let result = ""; - for (let [a, b] of luaIter()) { result += a + b; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof lua iterator tuple-return with existing variables") - public forofLuaIteratorTupleReturnExistingVars(): void { - const code = `const arr = ["a", "b", "c"]; - /** @luaIterator */ - /** @tupleReturn */ - interface Iter extends Iterable<[string, string]> {} - function luaIter(): Iter { - let i = 0; - /** @tupleReturn */ - function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } - return iter as any; - } - let result = ""; - let a: string; - let b: string; - for ([a, b] of luaIter()) { result += a + b; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @Test("forof lua iterator tuple-return single variable") - public forofLuaIteratorTupleReturnSingleVar(): void { - const code = `/** @luaIterator */ +test("forof with iterator", () => { + const code = `const arr = ["a", "b", "c"]; + function iter(): IterableIterator { + let i = 0; + return { + [Symbol.iterator]() { return this; }, + next() { return {value: arr[i], done: i++ >= arr.length} }, + } + } + let result = ""; + for (let e of iter()) { + result += e; + } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof with iterator and existing variable", () => { + const code = `const arr = ["a", "b", "c"]; + function iter(): IterableIterator { + let i = 0; + return { + [Symbol.iterator]() { return this; }, + next() { return {value: arr[i], done: i++ >= arr.length} }, + } + } + let result = ""; + let e: string; + for (e of iter()) { + result += e; + } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof destructuring with iterator", () => { + const code = `const arr = ["a", "b", "c"]; + function iter(): IterableIterator<[string, string]> { + let i = 0; + return { + [Symbol.iterator]() { return this; }, + next() { return {value: [i.toString(), arr[i]], done: i++ >= arr.length} }, + } + } + let result = ""; + for (let [a, b] of iter()) { + result += a + b; + } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof destructuring with iterator and existing variables", () => { + const code = `const arr = ["a", "b", "c"]; + function iter(): IterableIterator<[string, string]> { + let i = 0; + return { + [Symbol.iterator]() { return this; }, + next() { return {value: [i.toString(), arr[i]], done: i++ >= arr.length} }, + } + } + let result = ""; + let a: string; + let b: string; + for ([a, b] of iter()) { + result += a + b; + } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof lua iterator", () => { + const code = `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;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof array lua iterator", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + interface Iter extends Array {} + function luaIter(): Iter { + let i = 0; + return (() => arr[i++]) as any; + } + let result = ""; + for (let e of luaIter()) { result += e; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof lua iterator with existing variable", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + interface Iter extends Iterable {} + function luaIter(): Iter { + let i = 0; + return (() => arr[i++]) as any; + } + let result = ""; + let e: string; + for (e of luaIter()) { result += e; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof lua iterator destructuring", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + interface Iter extends Iterable<[string, string]> {} + function luaIter(): Iter { + let i = 0; + return (() => arr[i] && [i.toString(), arr[i++]]) as any; + } + let result = ""; + for (let [a, b] of luaIter()) { result += a + b; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof lua iterator destructuring with existing variables", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + interface Iter extends Iterable<[string, string]> {} + function luaIter(): Iter { + let i = 0; + return (() => arr[i] && [i.toString(), arr[i++]]) as any; + } + let result = ""; + let a: string; + let b: string; + for ([a, b] of luaIter()) { result += a + b; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof lua iterator tuple-return", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + /** @tupleReturn */ + interface Iter extends Iterable<[string, string]> {} + function luaIter(): Iter { + let i = 0; /** @tupleReturn */ - interface Iter extends Iterable<[string, string]> {} - declare function luaIter(): Iter; - for (let x of luaIter()) {}`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - Expect(() => util.transpileString(code, compilerOptions)).toThrowError( - TranspileError, - "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " - + "You must use a destructuring statement to catch results from a lua iterator with " - + "the TupleReturn decorator."); - } - - @Test("forof lua iterator tuple-return single existing variable") - public forofLuaIteratorTupleReturnSingleExistingVar(): void { - const code = `/** @luaIterator */ + function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } + return iter as any; + } + let result = ""; + for (let [a, b] of luaIter()) { result += a + b; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof lua iterator tuple-return with existing variables", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + /** @tupleReturn */ + interface Iter extends Iterable<[string, string]> {} + function luaIter(): Iter { + let i = 0; /** @tupleReturn */ - interface Iter extends Iterable<[string, string]> {} - declare function luaIter(): Iter; - let x: [string, string]; - for (x of luaIter()) {}`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - Expect(() => util.transpileString(code, compilerOptions)).toThrowError( - TranspileError, - "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " - + "You must use a destructuring statement to catch results from a lua iterator with " - + "the TupleReturn decorator."); - } - - @Test("forof forwarded lua iterator") - public forofForwardedLuaIterator(): void { - const code = - `const arr = ["a", "b", "c"]; - /** @luaIterator */ - interface Iter extends Iterable {} - function luaIter(): Iter { - let i = 0; - function iter() { return arr[i++]; } - return iter as any; - } - function forward() { - const iter = luaIter(); - return iter; - } - let result = ""; - for (let a of forward()) { result += a; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("abc"); - } - - @Test("forof forwarded lua iterator with tupleReturn") - public forofForwardedLuaIteratorWithTupleReturn(): void { - const code = - `const arr = ["a", "b", "c"]; - /** @luaIterator */ + function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } + return iter as any; + } + let result = ""; + let a: string; + let b: string; + for ([a, b] of luaIter()) { result += a + b; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test("forof lua iterator tuple-return single variable", () => { + const code = `/** @luaIterator */ + /** @tupleReturn */ + interface Iter extends Iterable<[string, string]> {} + declare function luaIter(): Iter; + for (let x of luaIter()) {}`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + new TranspileError( + "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + + "You must use a destructuring statement to catch results from a lua iterator with " + + "the TupleReturn decorator.", + ), + ); +}); + +test("forof lua iterator tuple-return single existing variable", () => { + const code = `/** @luaIterator */ + /** @tupleReturn */ + interface Iter extends Iterable<[string, string]> {} + declare function luaIter(): Iter; + let x: [string, string]; + for (x of luaIter()) {}`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + new TranspileError( + "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + + "You must use a destructuring statement to catch results from a lua iterator with " + + "the TupleReturn decorator.", + ), + ); +}); + +test("forof forwarded lua iterator", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + interface Iter extends Iterable {} + function luaIter(): Iter { + let i = 0; + function iter() { return arr[i++]; } + return iter as any; + } + function forward() { + const iter = luaIter(); + return iter; + } + let result = ""; + for (let a of forward()) { result += a; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("abc"); +}); + +test("forof forwarded lua iterator with tupleReturn", () => { + const code = `const arr = ["a", "b", "c"]; + /** @luaIterator */ + /** @tupleReturn */ + interface Iter extends Iterable<[string, string]> {} + function luaIter(): Iter { + let i = 0; /** @tupleReturn */ - interface Iter extends Iterable<[string, string]> {} - function luaIter(): Iter { - let i = 0; - /** @tupleReturn */ - function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } - return iter as any; - } - function forward() { - const iter = luaIter(); - return iter; - } - let result = ""; - for (let [a, b] of forward()) { result += a + b; } - return result;`; - const compilerOptions = { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - }; - const result = util.transpileAndExecute(code, compilerOptions); - Expect(result).toBe("0a1b2c"); - } - - @TestCase("while (a < b) { i++; }") - @TestCase("do { i++; } while (a < b)") - @TestCase("for (let i = 0; i < 3; i++) {}") - @TestCase("for (let a in b) {}") - @TestCase("for (let a of b) {}") - @Test("loop versions") - public whileVersions(loop: string): void { - // Transpile - const lua51 = util.transpileString(loop, { luaTarget: LuaTarget.Lua51 }); - const lua52 = util.transpileString(loop, { luaTarget: LuaTarget.Lua52 }); - const lua53 = util.transpileString(loop, { luaTarget: LuaTarget.Lua53 }); - const luajit = util.transpileString(loop, { luaTarget: LuaTarget.LuaJIT }); - - // Assert - Expect(lua51.indexOf("::__continue1::") !== -1).toBe(false); // No labels in 5.1 - Expect(lua52.indexOf("::__continue1::") !== -1).toBe(true); // Labels from 5.2 onwards - Expect(lua53.indexOf("::__continue1::") !== -1).toBe(true); - Expect(luajit.indexOf("::__continue1::") !== -1).toBe(true); - } - - @Test("for dead code after return") - public forDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `for (let i = 0; i < 10; i++) { return 3; const b = 8; }`); - - Expect(result).toBe(3); - } - - @Test("for..in dead code after return") - public forInDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `for (let a in {"a": 5, "b": 8}) { return 3; const b = 8; }`); - - Expect(result).toBe(3); - } - - @Test("for..of dead code after return") - public forOfDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `for (let a of [1,2,4]) { return 3; const b = 8; }`); - - Expect(result).toBe(3); - } - - @Test("while dead code after return") - public whileDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `while (true) { return 3; const b = 8; }`); - - Expect(result).toBe(3); - } -} + function iter() { return arr[i] && [i.toString(), arr[i++]] || []; } + return iter as any; + } + function forward() { + const iter = luaIter(); + return iter; + } + let result = ""; + for (let [a, b] of forward()) { result += a + b; } + return result;`; + const compilerOptions = { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ES2015, + }; + const result = util.transpileAndExecute(code, compilerOptions); + expect(result).toBe("0a1b2c"); +}); + +test.each([ + "while (a < b) { i++; }", + "do { i++; } while (a < b)", + "for (let i = 0; i < 3; i++) {}", + "for (let a in b) {}", + "for (let a of b) {}", +])("loop versions (%p)", loop => { + const lua51 = util.transpileString(loop, { luaTarget: LuaTarget.Lua51 }); + const lua52 = util.transpileString(loop, { luaTarget: LuaTarget.Lua52 }); + const lua53 = util.transpileString(loop, { luaTarget: LuaTarget.Lua53 }); + const luajit = util.transpileString(loop, { luaTarget: LuaTarget.LuaJIT }); + + expect(lua51.indexOf("::__continue1::") !== -1).toBe(false); // No labels in 5.1 + expect(lua52.indexOf("::__continue1::") !== -1).toBe(true); // Labels from 5.2 onwards + expect(lua53.indexOf("::__continue1::") !== -1).toBe(true); + expect(luajit.indexOf("::__continue1::") !== -1).toBe(true); +}); + +test("for dead code after return", () => { + const result = util.transpileAndExecute( + `for (let i = 0; i < 10; i++) { return 3; const b = 8; }`, + ); + + expect(result).toBe(3); +}); + +test("for..in dead code after return", () => { + const result = util.transpileAndExecute( + `for (let a in {"a": 5, "b": 8}) { return 3; const b = 8; }`, + ); + + expect(result).toBe(3); +}); + +test("for..of dead code after return", () => { + const result = util.transpileAndExecute(`for (let a of [1,2,4]) { return 3; const b = 8; }`); + + expect(result).toBe(3); +}); + +test("while dead code after return", () => { + const result = util.transpileAndExecute(`while (true) { return 3; const b = 8; }`); + + expect(result).toBe(3); +}); diff --git a/test/unit/lualib/inlining.spec.ts b/test/unit/lualib/inlining.spec.ts index 89aed54a9..ae54ebf42 100644 --- a/test/unit/lualib/inlining.spec.ts +++ b/test/unit/lualib/inlining.spec.ts @@ -1,50 +1,45 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../../src/util"; +import * as util from "../../util"; import { LuaLibImportKind, LuaTarget } from "../../../src/CompilerOptions"; -export class InliningTests { - @Test("map constructor") - public mapConstructor(): void - { - const result = util.transpileAndExecute(`let mymap = new Map(); return mymap.size;`, - { luaLibImport: LuaLibImportKind.Inline, luaTarget: LuaTarget.Lua53 }); - - Expect(result).toBe(0); - } - - @Test("map foreach keys") - public mapForEachKeys(): void { - const result = util.transpileAndExecute( - `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); - let count = 0; - mymap.forEach((value, key) => { count += key; }); - return count;`, - { luaLibImport: LuaLibImportKind.Inline, luaTarget: LuaTarget.Lua53 }); - - Expect(result).toBe(18); - } - - @Test("set constructor") - public setConstructor(): void - { - const result = util.transpileAndExecute( - `class abc {} let def = new abc(); let myset = new Set(); return myset.size;`, - { luaLibImport: LuaLibImportKind.Inline, luaTarget: LuaTarget.Lua53 } - ); - - Expect(result).toBe(0); - } - - @Test("set foreach keys") - public setForEachKeys(): void { - const result = util.transpileAndExecute( - `let myset = new Set([2, 3, 4]); - let count = 0; - myset.forEach((value, key) => { count += key; }); - return count;`, - { luaLibImport: LuaLibImportKind.Inline, luaTarget: LuaTarget.Lua53 }); - - Expect(result).toBe(9); - } -} +test("map constructor", () => { + const result = util.transpileAndExecute(`let mymap = new Map(); return mymap.size;`, { + luaLibImport: LuaLibImportKind.Inline, + luaTarget: LuaTarget.Lua53, + }); + + expect(result).toBe(0); +}); + +test("map foreach keys", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); + let count = 0; + mymap.forEach((value, key) => { count += key; }); + return count;`, + { luaLibImport: LuaLibImportKind.Inline }, + ); + + expect(result).toBe(18); +}); + +test("set constructor", () => { + const result = util.transpileAndExecute( + `class abc {} let def = new abc(); let myset = new Set(); return myset.size;`, + { luaLibImport: LuaLibImportKind.Inline }, + ); + + expect(result).toBe(0); +}); + +test("set foreach keys", () => { + const result = util.transpileAndExecute( + `let myset = new Set([2, 3, 4]); + let count = 0; + myset.forEach((value, key) => { count += key; }); + return count;`, + { luaLibImport: LuaLibImportKind.Inline }, + ); + + expect(result).toBe(9); +}); diff --git a/test/unit/lualib/lualib.spec.ts b/test/unit/lualib/lualib.spec.ts index 59b4f4418..b6a0343b7 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -1,521 +1,490 @@ -import { Expect, Test, TestCase } from "alsatian"; import * as ts from "typescript"; -import * as util from "../../src/util"; +import * as util from "../../util"; import { LuaLibImportKind } from "../../../src/CompilerOptions"; -export class LuaLibTests -{ - @TestCase([0, 1, 2, 3], [1, 2, 3, 4]) - @Test("forEach") - public forEach(inp: number[], expected: number[]): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - arrTest.forEach((elem, index) => { - arrTest[index] = arrTest[index] + 1; - }) - return JSONStringify(arrTest);` - ); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase([], 3, -1) - @TestCase([0, 2, 4, 8], 10, -1) - @TestCase([0, 2, 4, 8], 8, 3) - @Test("array.findIndex[value]") - public findIndexByValue(inp: number[], searchEl: number, expected: number): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - return JSONStringify(arrTest.findIndex((elem, index) => { - return elem === ${searchEl}; - }));` +test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("forEach (%p)", ({ inp, expected }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + arrTest.forEach((elem, index) => { + arrTest[index] = arrTest[index] + 1; + }) + return JSONStringify(arrTest);`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([ + { inp: [], searchEl: 3, expected: -1 }, + { inp: [0, 2, 4, 8], searchEl: 10, expected: -1 }, + { inp: [0, 2, 4, 8], searchEl: 8, expected: 3 }, +])("array.findIndex[value] (%p)", ({ inp, searchEl, expected }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + return JSONStringify(arrTest.findIndex((elem, index) => { + return elem === ${searchEl}; + }));`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: [0, 2, 4, 8], expected: 3, value: 8 }, + { inp: [0, 2, 4, 8], expected: 1, value: 2 }, +])("array.findIndex[index] (%p)", ({ inp, expected, value }) => { + const result = util.transpileAndExecute( + `let arrTest = ${JSON.stringify(inp)}; + return JSONStringify(arrTest.findIndex((elem, index, arr) => { + return index === ${expected} && arr[${expected}] === ${value}; + }));`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { inp: [], func: "x => x" }, + { inp: [0, 1, 2, 3], func: "x => x" }, + { inp: [0, 1, 2, 3], func: "x => x*2" }, + { inp: [1, 2, 3, 4], func: "x => -x" }, + { inp: [0, 1, 2, 3], func: "x => x+2" }, + { inp: [0, 1, 2, 3], func: "x => x%2 == 0 ? x + 1 : x - 1" }, +])("array.map (%p)", ({ inp, func }) => { + const result = util.transpileAndExecute( + `return JSONStringify([${inp.toString()}].map(${func}))`, + ); + + expect(result).toBe(JSON.stringify(inp.map(eval(func)))); +}); + +test.each([ + { inp: [], func: "x => x > 1" }, + { inp: [0, 1, 2, 3], func: "x => x > 1" }, + { inp: [0, 1, 2, 3], func: "x => x < 3" }, + { inp: [0, 1, 2, 3], func: "x => x < 0" }, + { inp: [0, -1, -2, -3], func: "x => x < 0" }, + { inp: [0, 1, 2, 3], func: "() => true" }, + { inp: [0, 1, 2, 3], func: "() => false" }, +])("array.filter (%p)", ({ inp, func }) => { + const result = util.transpileAndExecute( + `return JSONStringify([${inp.toString()}].filter(${func}))`, + ); + + expect(result).toBe(JSON.stringify(inp.filter(eval(func)))); +}); + +test.each([ + { inp: [], func: "x => x > 1" }, + { inp: [0, 1, 2, 3], func: "x => x > 1" }, + { inp: [false, true, false], func: "x => x" }, + { inp: [true, true, true], func: "x => x" }, +])("array.every (%p)", ({ inp, func }) => { + const result = util.transpileAndExecute( + `return JSONStringify([${inp.toString()}].every(${func}))`, + ); + + expect(result).toBe(JSON.stringify(inp.every(eval(func)))); +}); + +test.each([ + { inp: [], func: "x => x > 1" }, + { inp: [0, 1, 2, 3], func: "x => x > 1" }, + { inp: [false, true, false], func: "x => x" }, + { inp: [true, true, true], func: "x => x" }, +])("array.some (%p)", ({ inp, func }) => { + const result = util.transpileAndExecute( + `return JSONStringify([${inp.toString()}].some(${func}))`, + ); + + expect(result).toBe(JSON.stringify(inp.some(eval(func)))); +}); + +test.each([ + { inp: [], start: 1, end: 2 }, + { inp: [0, 1, 2, 3], start: 1, end: 2 }, + { inp: [0, 1, 2, 3], start: 1, end: 1 }, + { inp: [0, 1, 2, 3], start: 1, end: -1 }, + { inp: [0, 1, 2, 3], start: -3, end: -1 }, + { inp: [0, 1, 2, 3, 4, 5], start: 1, end: 3 }, + { inp: [0, 1, 2, 3, 4, 5], start: 3 }, +])("array.slice (%p)", ({ inp, start, end }) => { + const result = util.transpileAndExecute( + `return JSONStringify([${inp.toString()}].slice(${start}, ${end}))`, + ); + + expect(result).toBe(JSON.stringify(inp.slice(start, end))); +}); + +test.each([ + { inp: [], start: 0, deleteCount: 0, newElements: [9, 10, 11] }, + { inp: [0, 1, 2, 3], start: 1, deleteCount: 0, newElements: [9, 10, 11] }, + { inp: [0, 1, 2, 3], start: 2, deleteCount: 2, newElements: [9, 10, 11] }, + { inp: [0, 1, 2, 3], start: 4, deleteCount: 1, newElements: [8, 9] }, + { inp: [0, 1, 2, 3], start: 4, deleteCount: 0, newElements: [8, 9] }, + { inp: [0, 1, 2, 3, 4, 5], start: 5, deleteCount: 9, newElements: [10, 11] }, + { inp: [0, 1, 2, 3, 4, 5], start: 3, deleteCount: 2, newElements: [3, 4, 5] }, +])("array.splice[Insert] (%p)", ({ inp, start, deleteCount, newElements }) => { + const result = util.transpileAndExecute( + `let spliceTestTable = [${inp.toString()}]; + spliceTestTable.splice(${start}, ${deleteCount}, ${newElements}); + return JSONStringify(spliceTestTable);`, + ); + + inp.splice(start, deleteCount, ...newElements); + expect(result).toBe(JSON.stringify(inp)); +}); + +test.each([ + { inp: [], start: 1, deleteCount: 1 }, + { inp: [0, 1, 2, 3], start: 1, deleteCount: 1 }, + { inp: [0, 1, 2, 3], start: 10, deleteCount: 1 }, + { inp: [0, 1, 2, 3], start: 4 }, + { inp: [0, 1, 2, 3, 4, 5], start: 3 }, + { inp: [0, 1, 2, 3, 4, 5], start: 2, deleteCount: 2 }, + { inp: [0, 1, 2, 3, 4, 5, 6, 7, 8], start: 5, deleteCount: 9, newElements: [10, 11] }, +])("array.splice[Remove] (%p)", ({ inp, start, deleteCount, newElements = [] }) => { + let result; + if (deleteCount) { + result = util.transpileAndExecute( + `let spliceTestTable = [${inp.toString()}]; + spliceTestTable.splice(${start}, ${deleteCount}, ${newElements}); + return JSONStringify(spliceTestTable);`, ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase([0, 2, 4, 8], 3, 8) - @TestCase([0, 2, 4, 8], 1, 2) - @Test("array.findIndex[index]") - public findIndexByIndex(inp: number[], expected: number, value: number): void - { - const result = util.transpileAndExecute( - `let arrTest = ${JSON.stringify(inp)}; - return JSONStringify(arrTest.findIndex((elem, index, arr) => { - return index === ${expected} && arr[${expected}] === ${value}; - }));` + } else { + result = util.transpileAndExecute( + `let spliceTestTable = [${inp.toString()}]; + spliceTestTable.splice(${start}); + return JSONStringify(spliceTestTable);`, ); - - // Assert - Expect(result).toBe(expected); } - @TestCase([], "x => x") - @TestCase([0, 1, 2, 3], "x => x") - @TestCase([0, 1, 2, 3], "x => x*2") - @TestCase([1, 2, 3, 4], "x => -x") - @TestCase([0, 1, 2, 3], "x => x+2") - @TestCase([0, 1, 2, 3], "x => x%2 == 0 ? x + 1 : x - 1") - @Test("array.map") - public map(inp: T[], func: string): void - { - const result = util.transpileAndExecute(`return JSONStringify([${inp.toString()}].map(${func}))`); - - // Assert - Expect(result).toBe(JSON.stringify(inp.map(eval(func)))); + if (deleteCount) { + inp.splice(start, deleteCount, ...newElements); + expect(result).toBe(JSON.stringify(inp)); + } else { + inp.splice(start); + expect(result).toBe(JSON.stringify(inp)); } - - @TestCase([], "x => x > 1") - @TestCase([0, 1, 2, 3], "x => x > 1") - @TestCase([0, 1, 2, 3], "x => x < 3") - @TestCase([0, 1, 2, 3], "x => x < 0") - @TestCase([0, -1, -2, -3], "x => x < 0") - @TestCase([0, 1, 2, 3], "() => true") - @TestCase([0, 1, 2, 3], "() => false") - @Test("array.filter") - public filter(inp: T[], func: string): void - { - const result = util.transpileAndExecute(`return JSONStringify([${inp.toString()}].filter(${func}))`); - - // Assert - Expect(result).toBe(JSON.stringify(inp.filter(eval(func)))); +}); + +test.each([ + { arr: [], args: [[]] }, + { arr: [1, 2, 3], args: [[]] }, + { arr: [1, 2, 3], args: [[4]] }, + { arr: [1, 2, 3], args: [[4, 5]] }, + { arr: [1, 2, 3], args: [[4, 5]] }, + { arr: [1, 2, 3], args: [4, [5]] }, + { arr: [1, 2, 3], args: [4, [5, 6]] }, + { arr: [1, 2, 3], args: [4, [5, 6], 7] }, + { arr: [1, 2, 3], args: ["test", [5, 6], 7, ["test1", "test2"]] }, + { arr: [1, 2, "test"], args: ["test", ["test1", "test2"]] }, +])("array.concat (%p)", ({ arr, args }: { arr: any[]; args: any[] }) => { + const argStr = args.map(arg => JSON.stringify(arg)).join(","); + + const result = util.transpileAndExecute( + `let concatTestTable: any[] = ${JSON.stringify(arr)}; + return JSONStringify(concatTestTable.concat(${argStr}));`, + ); + + const concatArr = arr.concat(...args); + expect(result).toBe(JSON.stringify(concatArr)); +}); + +test.each([ + { inp: [], expected: "" }, + { inp: ["test1"], expected: "test1" }, + { inp: ["test1", "test2"], expected: "test1,test2" }, + { inp: ["test1", "test2"], expected: "test1;test2", seperator: ";" }, + { inp: ["test1", "test2"], expected: "test1test2", seperator: "" }, +])("array.join (%p)", ({ inp, expected, seperator }) => { + let seperatorLua; + if (seperator === "") { + seperatorLua = '""'; + } else if (seperator) { + seperatorLua = '"' + seperator + '"'; + } else { + seperatorLua = ""; } - - @TestCase([], "x => x > 1") - @TestCase([0, 1, 2, 3], "x => x > 1") - @TestCase([false, true, false], "x => x") - @TestCase([true, true, true], "x => x") - @Test("array.every") - public every(inp: T[], func: string): void - { - const result = util.transpileAndExecute(`return JSONStringify([${inp.toString()}].every(${func}))`); - - // Assert - Expect(result).toBe(JSON.stringify(inp.every(eval(func)))); + const result = util.transpileAndExecute( + `let joinTestTable = ${JSON.stringify(inp)}; + return joinTestTable.join(${seperatorLua});`, + ); + + const joinedInp = inp.join(seperator); + expect(result).toBe(joinedInp); +}); + +test.each([ + { inp: [], element: "test1" }, + { inp: ["test1"], element: "test1" }, + { inp: ["test1", "test2"], element: "test2" }, + { inp: ["test1", "test2", "test3"], element: "test3", fromIndex: 1 }, + { inp: ["test1", "test2", "test3"], element: "test1", fromIndex: 2 }, + { inp: ["test1", "test2", "test3"], element: "test1", fromIndex: -2 }, + { inp: ["test1", "test2", "test3"], element: "test1", fromIndex: 12 }, +])("array.indexOf (%p)", ({ inp, element, fromIndex }) => { + let str = `return ${JSON.stringify(inp)}.indexOf("${element}");`; + if (fromIndex) { + str = `return ${JSON.stringify(inp)}.indexOf("${element}", ${fromIndex});`; } - @TestCase([], "x => x > 1") - @TestCase([0, 1, 2, 3], "x => x > 1") - @TestCase([false, true, false], "x => x") - @TestCase([true, true, true], "x => x") - @Test("array.some") - public some(inp: T[], func: string): void - { - const result = util.transpileAndExecute(`return JSONStringify([${inp.toString()}].some(${func}))`); + const result = util.transpileAndExecute(str); - // Assert - Expect(result).toBe(JSON.stringify(inp.some(eval(func)))); - } + // Account for lua indexing (-1) + expect(result).toBe(inp.indexOf(element, fromIndex)); +}); - @TestCase([], 1, 2) - @TestCase([0, 1, 2, 3], 1, 2) - @TestCase([0, 1, 2, 3], 1, 1) - @TestCase([0, 1, 2, 3], 1, -1) - @TestCase([0, 1, 2, 3], -3, -1) - @TestCase([0, 1, 2, 3, 4, 5], 1, 3) - @TestCase([0, 1, 2, 3, 4, 5], 3) - @Test("array.slice") - public slice(inp: T[], start: number, end?: number): void - { - const result = util.transpileAndExecute(`return JSONStringify([${inp.toString()}].slice(${start}, ${end}))`); - - // Assert - Expect(result).toBe(JSON.stringify(inp.slice(start, end))); - } - - @TestCase([], 0, 0, 9, 10, 11) - @TestCase([0, 1, 2, 3], 1, 0, 9, 10, 11) - @TestCase([0, 1, 2, 3], 2, 2, 9, 10, 11) - @TestCase([0, 1, 2, 3], 4, 1, 8, 9) - @TestCase([0, 1, 2, 3], 4, 0, 8, 9) - @TestCase([0, 1, 2, 3, 4, 5], 5, 9, 10, 11) - @TestCase([0, 1, 2, 3, 4, 5], 3, 2, 3, 4, 5) - @Test("array.splice[Insert]") - public spliceInsert(inp: T[], start: number, deleteCount: number, ...newElements: any[]): void - { +test.each([{ inp: [1, 2, 3], expected: 3 }, { inp: [1, 2, 3, 4, 5], expected: 3 }])( + "array.destructuring.simple (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( - `let spliceTestTable = [${inp.toString()}]; - spliceTestTable.splice(${start}, ${deleteCount}, ${newElements}); - return JSONStringify(spliceTestTable);` + `let [x, y, z] = ${JSON.stringify(inp)} + return z; + `, ); - // Assert - inp.splice(start, deleteCount, ...newElements); - Expect(result).toBe(JSON.stringify(inp)); - } - - @TestCase([], 1, 1) - @TestCase([0, 1, 2, 3], 1, 1) - @TestCase([0, 1, 2, 3], 10, 1) - @TestCase([0, 1, 2, 3], 4) - @TestCase([0, 1, 2, 3, 4, 5], 3) - @TestCase([0, 1, 2, 3, 4, 5], 2, 2) - @TestCase([0, 1, 2, 3, 4, 5, 6, 7, 8], 5, 9, 10, 11) - @Test("array.splice[Remove]") - public spliceRemove(inp: T[], start: number, deleteCount?: number, ...newElements: any[]): void + expect(result).toBe(expected); + }, +); + +test.each([{ inp: [1] }, { inp: [1, 2, 3] }])("array.push (%p)", ({ inp }) => { + const result = util.transpileAndExecute( + `let testArray = [0]; + testArray.push(${inp.join(", ")}); + return JSONStringify(testArray); + `, + ); + + expect(result).toBe(JSON.stringify([0].concat(inp))); +}); + +test.each([ + { array: "[1, 2, 3]", expected: [3, 2] }, + { array: "[1, 2, 3, null]", expected: [3, 2] }, +])("array.pop (%p)", ({ array, expected }) => { { - let result; - if (deleteCount) { - result = util.transpileAndExecute( - `let spliceTestTable = [${inp.toString()}]; - spliceTestTable.splice(${start}, ${deleteCount}, ${newElements}); - return JSONStringify(spliceTestTable);` - ); - } else { - result = util.transpileAndExecute( - `let spliceTestTable = [${inp.toString()}]; - spliceTestTable.splice(${start}); - return JSONStringify(spliceTestTable);` - ); - } - - // Assert - if (deleteCount) { - inp.splice(start, deleteCount, ...newElements); - Expect(result).toBe(JSON.stringify(inp)); - } else { - inp.splice(start); - Expect(result).toBe(JSON.stringify(inp)); - } - } - - @TestCase([], []) - @TestCase([1, 2, 3], []) - @TestCase([1, 2, 3], [4]) - @TestCase([1, 2, 3], [4, 5]) - @TestCase([1, 2, 3], [4, 5]) - @TestCase([1, 2, 3], 4, [5]) - @TestCase([1, 2, 3], 4, [5, 6]) - @TestCase([1, 2, 3], 4, [5, 6], 7) - @TestCase([1, 2, 3], "test", [5, 6], 7, ["test1", "test2"]) - @TestCase([1, 2, "test"], "test", ["test1", "test2"]) - @Test("array.concat") - public concat(arr: T[], ...args: T[]): void - { - const argStr = args.map(arg => JSON.stringify(arg)).join(","); - const result = util.transpileAndExecute( - `let concatTestTable: any[] = ${JSON.stringify(arr)}; - return JSONStringify(concatTestTable.concat(${argStr}));` - ); - - // Assert - const concatArr = arr.concat(...args); - Expect(result).toBe(JSON.stringify(concatArr)); - } - - @TestCase([], "") - @TestCase(["test1"], "test1") - @TestCase(["test1", "test2"], "test1,test2") - @TestCase(["test1", "test2"], "test1;test2", ";") - @TestCase(["test1", "test2"], "test1test2", "") - @Test("array.join") - public join(inp: T[], expected: string, seperator?: string): void { - let seperatorLua; - if (seperator === "") { - seperatorLua = "\"\""; - } else if (seperator) { - seperatorLua = "\"" + seperator + "\""; - } else { - seperatorLua = ""; - } - // Transpile/Execute - const result = util.transpileAndExecute( - `let joinTestTable = ${JSON.stringify(inp)}; - return joinTestTable.join(${seperatorLua});` + `let testArray = ${array}; + let val = testArray.pop(); + return val`, ); - // Assert - const joinedInp = inp.join(seperator); - Expect(result).toBe(joinedInp); + expect(result).toBe(expected[0]); } - - @TestCase([], "test1") - @TestCase(["test1"], "test1") - @TestCase(["test1", "test2"], "test2") - @TestCase(["test1", "test2", "test3"], "test3", 1) - @TestCase(["test1", "test2", "test3"], "test1", 2) - @TestCase(["test1", "test2", "test3"], "test1", -2) - @TestCase(["test1", "test2", "test3"], "test1", 12) - @Test("array.indexOf") - public indexOf(inp: string[], element: string, fromIndex?: number): void - { - let str = `return ${JSON.stringify(inp)}.indexOf("${element}");`; - if (fromIndex) { - str = `return ${JSON.stringify(inp)}.indexOf("${element}", ${fromIndex});`; - } - - // Transpile/Execute - const result = util.transpileAndExecute(str); - - // Assert - // Account for lua indexing (-1) - Expect(result).toBe(inp.indexOf(element, fromIndex)); - } - - @TestCase([1, 2, 3], 3) - @TestCase([1, 2, 3, 4, 5], 3) - @Test("array.destructuring.simple") - public arrayDestructuringSimple(inp: number[], expected: number): void { const result = util.transpileAndExecute( - `let [x, y, z] = ${JSON.stringify(inp)} - return z; - `); + `let testArray = ${array}; + testArray.pop(); + return testArray.length`, + ); - // Assert - Expect(result).toBe(expected); + expect(result).toBe(expected[1]); } - - @TestCase([1]) - @TestCase([1, 2, 3]) - @Test("array.push") - public arrayPush(inp: number[]): void +}); + +test.each([ + { array: "[1, 2, 3]", expected: [3, 2, 1] }, + { array: "[1, 2, 3, null]", expected: [3, 2, 1] }, + { array: "[1, 2, 3, 4]", expected: [4, 3, 2, 1] }, + { array: "[1]", expected: [1] }, + { array: "[]", expected: [] }, +])("array.reverse (%p)", ({ array, expected }) => { + const result = util.transpileAndExecute( + `let testArray = ${array}; + let val = testArray.reverse(); + return JSONStringify(testArray)`, + ); + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([ + { array: "[1, 2, 3]", expectedArray: [2, 3], expectedValue: 1 }, + { array: "[1]", expectedArray: [], expectedValue: 1 }, + { array: "[]", expectedArray: [], expectedValue: undefined }, +])("array.shift (%p)", ({ array, expectedArray, expectedValue }) => { { - const result = util.transpileAndExecute( - `let testArray = [0]; - testArray.push(${inp.join(", ")}); - return JSONStringify(testArray); - ` - ); - - // Assert - Expect(result).toBe(JSON.stringify([0].concat(inp))); - } - - @TestCase("[1, 2, 3]", [3, 2]) - @TestCase("[1, 2, 3, null]", [3, 2]) - @Test("array.pop") - public arrayPop(array: string, expected): void { + // test array mutation { const result = util.transpileAndExecute( `let testArray = ${array}; - let val = testArray.pop(); - return val`); - - // Assert - Expect(result).toBe(expected[0]); + let val = testArray.shift(); + return JSONStringify(testArray)`, + ); + expect(result).toBe(JSON.stringify(expectedArray)); } + // test return value { const result = util.transpileAndExecute( `let testArray = ${array}; - testArray.pop(); - return testArray.length`); - - // Assert - Expect(result).toBe(expected[1]); - } - } - - @TestCase("[1, 2, 3]", [3, 2, 1]) - @TestCase("[1, 2, 3, null]", [3, 2, 1]) - @TestCase("[1, 2, 3, 4]", [4, 3, 2, 1]) - @TestCase("[1]", [1]) - @TestCase("[]", []) - @Test("array.reverse") - public arrayReverse(array: string, expected): void - { - const result = util.transpileAndExecute( - `let testArray = ${array}; - let val = testArray.reverse(); - return JSONStringify(testArray)`); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } + let val = testArray.shift(); + return val`, + ); - @TestCase("[1, 2, 3]", [2, 3], 1) - @TestCase("[1]", [], 1) - @TestCase("[]", [], undefined) - @Test("array.shift") - public arrayShift(array: string, expectedArray: number[], expectedValue: number): void { - { - // test array mutation - { - const result = util.transpileAndExecute( - `let testArray = ${array}; - let val = testArray.shift(); - return JSONStringify(testArray)`); - // Assert - Expect(result).toBe(JSON.stringify(expectedArray)); - } - // test return value - { - const result = util.transpileAndExecute( - `let testArray = ${array}; - let val = testArray.shift(); - return val`); - - // Assert - Expect(result).toBe(expectedValue); - } + expect(result).toBe(expectedValue); } } - @TestCase("[3, 4, 5]", [1, 2], [1, 2, 3, 4, 5]) - @TestCase("[]", [], []) - @TestCase("[1]", [], [1]) - @TestCase("[]", [1], [1]) - @Test("array.unshift") - public arrayUnshift(array: string, toUnshift, expected): void - { - const result = util.transpileAndExecute( - `let testArray = ${array}; - testArray.unshift(${toUnshift}); - return JSONStringify(testArray)`); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase("[4, 5, 3, 2, 1]", [1, 2, 3, 4, 5]) - @TestCase("[1]", [1]) - @TestCase("[1, null]", [1]) - @TestCase("[]", []) - @Test("array.sort") - public arraySort(array: string, expected): void +}); + +test.each([ + { array: "[3, 4, 5]", toUnshift: [1, 2], expected: [1, 2, 3, 4, 5] }, + { array: "[]", toUnshift: [], expected: [] }, + { array: "[1]", toUnshift: [], expected: [1] }, + { array: "[]", toUnshift: [1], expected: [1] }, +])("array.unshift (%p)", ({ array, toUnshift, expected }) => { + const result = util.transpileAndExecute( + `let testArray = ${array}; + testArray.unshift(${toUnshift}); + return JSONStringify(testArray)`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([ + { array: "[4, 5, 3, 2, 1]", expected: [1, 2, 3, 4, 5] }, + { array: "[1]", expected: [1] }, + { array: "[1, null]", expected: [1] }, + { array: "[]", expected: [] }, +])("array.sort (%p)", ({ array, expected }) => { + const result = util.transpileAndExecute( + `let testArray = ${array}; + testArray.sort(); + return JSONStringify(testArray)`, + ); + + expect(result).toBe(JSON.stringify(expected)); +}); + +test.each([ + { array: [1, 2, 3, 4, 5], compareStr: "a - b", compareFn: (a: any, b: any) => a - b }, { - const result = util.transpileAndExecute( - `let testArray = ${array}; - testArray.sort(); - return JSONStringify(testArray)`); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @Test("array.sort with compare function") - @TestCase([1, 2, 3, 4, 5], "a - b", (a: number, b: number) => a - b) - @TestCase(["4", "5", "3", "2", "1"], "tonumber(a) - tonumber(b)", (a: string, b: string) => Number(a) - Number(b)) - @TestCase(["4", "5", "3", "2", "1"], "tonumber(b) - tonumber(a)", (a: string, b: string) => Number(b) - Number(a)) - public arraySortWithCompareFunction( - array: any[], - compareStr: string, - compareFn: (a: any, b: any) => number - ): void { - const result = util.transpileAndExecute( - `let testArray = ${JSON.stringify(array)}; - testArray.sort((a, b) => ${compareStr}); - return JSONStringify(testArray)`, - undefined, - undefined, - `declare function tonumber(this: void, e: any): number` - ); - - // Assert - Expect(result).toBe(JSON.stringify(array.sort(compareFn))); - } - - @TestCase("true", "4", "5", 4) - @TestCase("false", "4", "5", 5) - @TestCase("3", "4", "5", 4) - @Test("Ternary Conditional") - public ternaryConditional(condition: string, lhs: string, rhs: string, expected: any): void + array: ["4", "5", "3", "2", "1"], + compareStr: "tonumber(a) - tonumber(b)", + compareFn: (a: any, b: any) => Number(a) - Number(b), + }, { - const result = util.transpileAndExecute(`return ${condition} ? ${lhs} : ${rhs};`); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase("true", 11) - @TestCase("false", 13) - @TestCase("a < 4", 13) - @TestCase("a == 8", 11) - @Test("Ternary Conditional Delayed") - public ternaryConditionalDelayed(condition: string, expected: any): void - { - const result = util.transpileAndExecute( - `let a = 3; - let delay = () => ${condition} ? a + 3 : a + 5; - a = 8; - return delay();`); - - // Assert - Expect(result).toBe(expected); + array: ["4", "5", "3", "2", "1"], + compareStr: "tonumber(b) - tonumber(a)", + compareFn: (a: any, b: any) => Number(b) - Number(a), + }, +])("array.sort with compare function (%p)", ({ array, compareStr, compareFn }) => { + const result = util.transpileAndExecute( + `let testArray = ${JSON.stringify(array)}; + testArray.sort((a, b) => ${compareStr}); + return JSONStringify(testArray)`, + undefined, + undefined, + `declare function tonumber(this: void, e: any): number`, + ); + + expect(result).toBe(JSON.stringify(array.sort(compareFn))); +}); + +test.each([ + { condition: "true", lhs: "4", rhs: "5", expected: 4 }, + { condition: "false", lhs: "4", rhs: "5", expected: 5 }, + { condition: "3", lhs: "4", rhs: "5", expected: 4 }, +])("Ternary Conditional (%p)", ({ condition, lhs, rhs, expected }) => { + const result = util.transpileAndExecute(`return ${condition} ? ${lhs} : ${rhs};`); + + expect(result).toBe(expected); +}); + +test.each([ + { condition: "true", expected: 11 }, + { condition: "false", expected: 13 }, + { condition: "a < 4", expected: 13 }, + { condition: "a == 8", expected: 11 }, +])("Ternary Conditional Delayed (%p)", ({ condition, expected }) => { + const result = util.transpileAndExecute( + `let a = 3; + let delay = () => ${condition} ? a + 3 : a + 5; + a = 8; + return delay();`, + ); + + expect(result).toBe(expected); +}); + +test.each([ + { initial: "{a: 3}", parameters: "{}", expected: { a: 3 } }, + { initial: "{}", parameters: "{a: 3}", expected: { a: 3 } }, + { initial: "{a: 3}", parameters: "{a: 5}", expected: { a: 5 } }, + { initial: "{a: 3}", parameters: "{b: 5},{c: 7}", expected: { a: 3, b: 5, c: 7 } }, +])("Object.Assign (%p)", ({ initial, parameters, expected }) => { + const jsonResult = util.transpileAndExecute(` + return JSONStringify(Object.assign(${initial},${parameters})); + `); + + const result = JSON.parse(jsonResult); + for (const key in expected) { + expect(result[key]).toBe(expected[key]); } - - @TestCase("{a: 3}", "{}", {a : 3}) - @TestCase("{}", "{a: 3}", {a : 3}) - @TestCase("{a: 3}", "{a: 5}", {a : 5}) - @TestCase("{a: 3}", "{b: 5},{c: 7}", {a : 3, b: 5, c: 7}) - @Test("Object.Assign") - public objectAssign(initial: string, parameters: string, expected: object): void { - const jsonResult = util.transpileAndExecute(` - return JSONStringify(Object.assign(${initial},${parameters})); - `); - - const result = JSON.parse(jsonResult); - for (const key in expected) { - Expect(result[key]).toBe(expected[key]); - } - } - - @TestCase("{}", []) - @TestCase("{abc: 3}", ["abc,3"]) - @TestCase("{abc: 3, def: 'xyz'}", ["abc,3", "def,xyz"]) - @Test("Object.entries") - public objectEntries(obj: string, expected: string[]): void { - const result = util.transpileAndExecute(` - const obj = ${obj}; - return Object.entries(obj).map(e => e.join(",")).join(";"); - `, {target: ts.ScriptTarget.ES2018, lib: ["es2018"], luaLibImport: LuaLibImportKind.Require}) as string; - - const foundKeys = result.split(";"); - if (expected.length === 0) { - Expect(foundKeys.length).toBe(1); - Expect(foundKeys[0]).toBe(""); - } else { - Expect(foundKeys.length).toBe(expected.length); - for (const key of expected) { - Expect(foundKeys.indexOf(key) >= 0).toBeTruthy(); - } +}); + +test.each([ + { obj: "{}", expected: [] }, + { obj: "{abc: 3}", expected: ["abc,3"] }, + { obj: "{abc: 3, def: 'xyz'}", expected: ["abc,3", "def,xyz"] }, +])("Object.entries (%p)", ({ obj, expected }) => { + const result = util.transpileAndExecute(` + const obj = ${obj}; + return Object.entries(obj).map(e => e.join(",")).join(";"); + `) as string; + + const foundKeys = result.split(";"); + if (expected.length === 0) { + expect(foundKeys.length).toBe(1); + expect(foundKeys[0]).toBe(""); + } else { + expect(foundKeys.length).toBe(expected.length); + for (const key of expected) { + expect(foundKeys.indexOf(key) >= 0).toBeTruthy(); } } - - @TestCase("{}", []) - @TestCase("{abc: 3}", ["abc"]) - @TestCase("{abc: 3, def: 'xyz'}", ["abc", "def"]) - @Test("Object.keys") - public objectKeys(obj: string, expected: string[]): void { - const result = util.transpileAndExecute(` - const obj = ${obj}; - return Object.keys(obj).join(","); - `) as string; - - const foundKeys = result.split(","); - if (expected.length === 0) { - Expect(foundKeys.length).toBe(1); - Expect(foundKeys[0]).toBe(""); - } else { - Expect(foundKeys.length).toBe(expected.length); - for (const key of expected) { - Expect(foundKeys.indexOf(key) >= 0).toBeTruthy(); - } +}); + +test.each([ + { obj: "{}", expected: [] }, + { obj: "{abc: 3}", expected: ["abc"] }, + { obj: "{abc: 3, def: 'xyz'}", expected: ["abc", "def"] }, +])("Object.keys (%p)", ({ obj, expected }) => { + const result = util.transpileAndExecute(` + const obj = ${obj}; + return Object.keys(obj).join(","); + `) as string; + + const foundKeys = result.split(","); + if (expected.length === 0) { + expect(foundKeys.length).toBe(1); + expect(foundKeys[0]).toBe(""); + } else { + expect(foundKeys.length).toBe(expected.length); + for (const key of expected) { + expect(foundKeys.indexOf(key) >= 0).toBeTruthy(); } } - - @TestCase("{}", []) - @TestCase("{abc: 'def'}", ["def"]) - @TestCase("{abc: 3, def: 'xyz'}", ["3", "xyz"]) - @Test("Object.values") - public objectValues(obj: string, expected: string[]): void { - const result = util.transpileAndExecute(` - const obj = ${obj}; - return Object.values(obj).join(","); - `, {target: ts.ScriptTarget.ES2018, lib: ["es2018"], luaLibImport: LuaLibImportKind.Require}) as string; - - const foundValues = result.split(","); - if (expected.length === 0) { - Expect(foundValues.length).toBe(1); - Expect(foundValues[0]).toBe(""); - } else { - Expect(foundValues.length).toBe(expected.length); - for (const key of expected) { - Expect(foundValues.indexOf(key) >= 0).toBeTruthy(); - } +}); + +test.each([ + { obj: "{}", expected: [] }, + { obj: "{abc: 'def'}", expected: ["def"] }, + { obj: "{abc: 3, def: 'xyz'}", expected: ["3", "xyz"] }, +])("Object.values (%p)", ({ obj, expected }) => { + const result = util.transpileAndExecute(` + const obj = ${obj}; + return Object.values(obj).join(","); + `) as string; + + const foundValues = result.split(","); + if (expected.length === 0) { + expect(foundValues.length).toBe(1); + expect(foundValues[0]).toBe(""); + } else { + expect(foundValues.length).toBe(expected.length); + for (const key of expected) { + expect(foundValues.indexOf(key) >= 0).toBeTruthy(); } } -} +}); diff --git a/test/unit/lualib/map.spec.ts b/test/unit/lualib/map.spec.ts index 20e85c344..01b18028d 100644 --- a/test/unit/lualib/map.spec.ts +++ b/test/unit/lualib/map.spec.ts @@ -1,169 +1,147 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../../src/util"; - -export class MapTests { - @Test("map constructor") - public mapConstructor(): void - { - const result = util.transpileAndExecute(`let mymap = new Map(); return mymap.size;`); - - Expect(result).toBe(0); - } - - @Test("map iterable constructor") - public mapIterableConstructor(): void - { - const result = util.transpileAndExecute( - `let mymap = new Map([["a", "c"],["b", "d"]]); - return mymap.has("a") && mymap.has("b");`); - - Expect(result).toBe(true); - } - - @Test("map iterable constructor map") - public mapIterableConstructor2(): void - { - const result = util.transpileAndExecute(`let mymap = new Map(new Map([["a", "c"],["b", "d"]])); - return mymap.has("a") && mymap.has("b");`); - - Expect(result).toBe(true); - } - - @Test("map clear") - public mapClear(): void - { - const mapTS = `let mymap = new Map([["a", "c"],["b", "d"]]); mymap.clear();`; - const size = util.transpileAndExecute(mapTS + `return mymap.size;`); - Expect(size).toBe(0); - - const contains = util.transpileAndExecute(mapTS + `return !mymap.has("a") && !mymap.has("b");`); - Expect(contains).toBe(true); - } - - @Test("map delete") - public mapDelete(): void - { - const mapTS = `let mymap = new Map([["a", "c"],["b", "d"]]); mymap.delete("a");`; - const contains = util.transpileAndExecute(mapTS + `return mymap.has("b") && !mymap.has("a");`); - Expect(contains).toBe(true); - } - - @Test("map entries") - public mapEntries(): void - { - const result = util.transpileAndExecute( - `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); - let count = 0; - for (var [key, value] of mymap.entries()) { count += key + value; } - return count;` - ); - Expect(result).toBe(27); - } - - @Test("map foreach") - public mapForEach(): void - { - const result = util.transpileAndExecute( - `let mymap = new Map([["a", 2],["b", 3],["c", 4]]); - let count = 0; - mymap.forEach(i => count += i); - return count;` - ); - - Expect(result).toBe(9); - } - - @Test("map foreach keys") - public mapForEachKeys(): void - { - const result = util.transpileAndExecute( - `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); - let count = 0; - mymap.forEach((value, key) => { count += key; }); - return count;` - ); - - Expect(result).toBe(18); - } - - @Test("map get") - public mapGet(): void - { - const result = util.transpileAndExecute(`let mymap = new Map([["a", "c"],["b", "d"]]); return mymap.get("a");`); - - Expect(result).toBe("c"); - } - - @Test("map get missing") - public mapGetMissing(): void - { - const result = util.transpileAndExecute(`let mymap = new Map([["a", "c"],["b", "d"]]); return mymap.get("c");`); - Expect(result).toBe(undefined); - } - - @Test("map has") - public mapHas(): void - { - const contains = util.transpileAndExecute(`let mymap = new Map([["a", "c"]]); return mymap.has("a");`); - Expect(contains).toBe(true); - } - - @Test("map has false") - public mapHasFalse(): void - { - const contains = util.transpileAndExecute(`let mymap = new Map(); return mymap.has("a");`); - Expect(contains).toBe(false); - } - - @Test("map has null") - public mapHasNull(): void - { - const contains = util.transpileAndExecute(`let mymap = new Map([["a", "c"]]); return mymap.has(null);`); - Expect(contains).toBe(false); - } - - @Test("map keys") - public mapKeys(): void - { - const result = util.transpileAndExecute( - `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); - let count = 0; - for (var key of mymap.keys()) { count += key; } - return count;` - ); - - Expect(result).toBe(18); - } - - @Test("map set") - public mapSet(): void - { - const mapTS = `let mymap = new Map(); mymap.set("a", 5);`; - const has = util.transpileAndExecute(mapTS + `return mymap.has("a");`); - Expect(has).toBe(true); - - const value = util.transpileAndExecute(mapTS + `return mymap.get("a")`); - Expect(value).toBe(5); - } - - @Test("map values") - public mapValues(): void { - const result = util.transpileAndExecute( - `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); - let count = 0; - for (var value of mymap.values()) { count += value; } - return count;` - ); - - Expect(result).toBe(9); - } - - @Test("map size") - public mapSize(): void { - Expect(util.transpileAndExecute(`let m = new Map(); return m.size;`)).toBe(0); - Expect(util.transpileAndExecute(`let m = new Map(); m.set(1,3); return m.size;`)).toBe(1); - Expect(util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); return m.size;`)).toBe(2); - Expect(util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); m.clear(); return m.size;`)).toBe(0); - Expect(util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); m.delete(3); return m.size;`)).toBe(1); - } -} +import * as util from "../../util"; + +test("map constructor", () => { + const result = util.transpileAndExecute(`let mymap = new Map(); return mymap.size;`); + + expect(result).toBe(0); +}); + +test("map iterable constructor", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([["a", "c"],["b", "d"]]); + return mymap.has("a") && mymap.has("b");`, + ); + + expect(result).toBe(true); +}); + +test("map iterable constructor map", () => { + const result = util.transpileAndExecute(`let mymap = new Map(new Map([["a", "c"],["b", "d"]])); + return mymap.has("a") && mymap.has("b");`); + + expect(result).toBe(true); +}); + +test("map clear", () => { + const mapTS = `let mymap = new Map([["a", "c"],["b", "d"]]); mymap.clear();`; + const size = util.transpileAndExecute(mapTS + `return mymap.size;`); + expect(size).toBe(0); + + const contains = util.transpileAndExecute(mapTS + `return !mymap.has("a") && !mymap.has("b");`); + expect(contains).toBe(true); +}); + +test("map delete", () => { + const mapTS = `let mymap = new Map([["a", "c"],["b", "d"]]); mymap.delete("a");`; + const contains = util.transpileAndExecute(mapTS + `return mymap.has("b") && !mymap.has("a");`); + expect(contains).toBe(true); +}); + +test("map entries", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); + let count = 0; + for (var [key, value] of mymap.entries()) { count += key + value; } + return count;`, + ); + expect(result).toBe(27); +}); + +test("map foreach", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([["a", 2],["b", 3],["c", 4]]); + let count = 0; + mymap.forEach(i => count += i); + return count;`, + ); + + expect(result).toBe(9); +}); + +test("map foreach keys", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); + let count = 0; + mymap.forEach((value, key) => { count += key; }); + return count;`, + ); + + expect(result).toBe(18); +}); + +test("map get", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([["a", "c"],["b", "d"]]); return mymap.get("a");`, + ); + + expect(result).toBe("c"); +}); + +test("map get missing", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([["a", "c"],["b", "d"]]); return mymap.get("c");`, + ); + expect(result).toBe(undefined); +}); + +test("map has", () => { + const contains = util.transpileAndExecute( + `let mymap = new Map([["a", "c"]]); return mymap.has("a");`, + ); + expect(contains).toBe(true); +}); + +test("map has false", () => { + const contains = util.transpileAndExecute(`let mymap = new Map(); return mymap.has("a");`); + expect(contains).toBe(false); +}); + +test("map has null", () => { + const contains = util.transpileAndExecute( + `let mymap = new Map([["a", "c"]]); return mymap.has(null);`, + ); + expect(contains).toBe(false); +}); + +test("map keys", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); + let count = 0; + for (var key of mymap.keys()) { count += key; } + return count;`, + ); + + expect(result).toBe(18); +}); + +test("map set", () => { + const mapTS = `let mymap = new Map(); mymap.set("a", 5);`; + const has = util.transpileAndExecute(mapTS + `return mymap.has("a");`); + expect(has).toBe(true); + + const value = util.transpileAndExecute(mapTS + `return mymap.get("a")`); + expect(value).toBe(5); +}); + +test("map values", () => { + const result = util.transpileAndExecute( + `let mymap = new Map([[5, 2],[6, 3],[7, 4]]); + let count = 0; + for (var value of mymap.values()) { count += value; } + return count;`, + ); + + expect(result).toBe(9); +}); + +test("map size", () => { + expect(util.transpileAndExecute(`let m = new Map(); return m.size;`)).toBe(0); + expect(util.transpileAndExecute(`let m = new Map(); m.set(1,3); return m.size;`)).toBe(1); + expect(util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); return m.size;`)).toBe(2); + expect( + util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); m.clear(); return m.size;`), + ).toBe(0); + expect( + util.transpileAndExecute(`let m = new Map([[1,2],[3,4]]); m.delete(3); return m.size;`), + ).toBe(1); +}); diff --git a/test/unit/lualib/set.spec.ts b/test/unit/lualib/set.spec.ts index 954ee06b8..61ffed054 100644 --- a/test/unit/lualib/set.spec.ts +++ b/test/unit/lualib/set.spec.ts @@ -1,152 +1,130 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../../src/util"; - -export class SetTests { - @Test("set constructor") - public setConstructor(): void - { - const result = util.transpileAndExecute(`let myset = new Set(); return myset.size;`); - - Expect(result).toBe(0); - } - - @Test("set iterable constructor") - public setIterableConstructor(): void - { - const result = util.transpileAndExecute( - `let myset = new Set(["a", "b"]); - return myset.has("a") || myset.has("b");`); - - Expect(result).toBe(true); - } - - @Test("set iterable constructor set") - public setIterableConstructorSet(): void - { - const result = util.transpileAndExecute( - `let myset = new Set(new Set(["a", "b"])); - return myset.has("a") || myset.has("b");`); - - Expect(result).toBe(true); - } - - @Test("set add") - public setAdd(): void - { - const has = util.transpileAndExecute(`let myset = new Set(); myset.add("a"); return myset.has("a");`); - Expect(has).toBe(true); - } - - @Test("set clear") - public setClear(): void - { - const setTS = `let myset = new Set(["a", "b"]); myset.clear();`; - const size = util.transpileAndExecute(setTS + `return myset.size;`); - Expect(size).toBe(0); - - const contains = util.transpileAndExecute(setTS + `return !myset.has("a") && !myset.has("b");`); - Expect(contains).toBe(true); - } - - @Test("set delete") - public setDelete(): void - { - const setTS = `let myset = new Set(["a", "b"]); myset.delete("a");`; - const contains = util.transpileAndExecute(setTS + `return myset.has("b") && !myset.has("a");`); - Expect(contains).toBe(true); - } - - @Test("set entries") - public setEntries(): void - { - const result = util.transpileAndExecute( - `let myset = new Set([5, 6, 7]); - let count = 0; - for (var [key, value] of myset.entries()) { count += key + value; } - return count;` - ); - - Expect(result).toBe(36); - } - - @Test("set foreach") - public setForEach(): void - { - const result = util.transpileAndExecute( - `let myset = new Set([2, 3, 4]); - let count = 0; - myset.forEach(i => { count += i; }); - return count;` - ); - Expect(result).toBe(9); - } - - @Test("set foreach keys") - public setForEachKeys(): void - { - const result = util.transpileAndExecute( - `let myset = new Set([2, 3, 4]); - let count = 0; - myset.forEach((value, key) => { count += key; }); - return count;` - ); - - Expect(result).toBe(9); - } - - @Test("set has") - public setHas(): void - { - const contains = util.transpileAndExecute(`let myset = new Set(["a", "c"]); return myset.has("a");`); - Expect(contains).toBe(true); - } - - @Test("set has false") - public setHasFalse(): void - { - const contains = util.transpileAndExecute(`let myset = new Set(); return myset.has("a");`); - Expect(contains).toBe(false); - } - - @Test("set has null") - public setHasNull(): void - { - const contains = util.transpileAndExecute(`let myset = new Set(["a", "c"]); return myset.has(null);`); - Expect(contains).toBe(false); - } - - @Test("set keys") - public setKeys(): void - { - const result = util.transpileAndExecute( - `let myset = new Set([5, 6, 7]); - let count = 0; - for (var key of myset.keys()) { count += key; } - return count;` - ); - - Expect(result).toBe(18); - } - - @Test("set values") - public setValues(): void - { - const result = util.transpileAndExecute( - `let myset = new Set([5, 6, 7]); - let count = 0; - for (var value of myset.values()) { count += value; } - return count;` - ); - - Expect(result).toBe(18); - } - - @Test("set size") - public setSize(): void { - Expect(util.transpileAndExecute(`let m = new Set(); return m.size;`)).toBe(0); - Expect(util.transpileAndExecute(`let m = new Set(); m.add(1); return m.size;`)).toBe(1); - Expect(util.transpileAndExecute(`let m = new Set([1, 2]); return m.size;`)).toBe(2); - Expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.clear(); return m.size;`)).toBe(0); - Expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.delete(2); return m.size;`)).toBe(1); - } -} +import * as util from "../../util"; + +test("set constructor", () => { + const result = util.transpileAndExecute(`let myset = new Set(); return myset.size;`); + + expect(result).toBe(0); +}); + +test("set iterable constructor", () => { + const result = util.transpileAndExecute( + `let myset = new Set(["a", "b"]); + return myset.has("a") || myset.has("b");`, + ); + + expect(result).toBe(true); +}); + +test("set iterable constructor set", () => { + const result = util.transpileAndExecute( + `let myset = new Set(new Set(["a", "b"])); + return myset.has("a") || myset.has("b");`, + ); + + expect(result).toBe(true); +}); + +test("set add", () => { + const has = util.transpileAndExecute( + `let myset = new Set(); myset.add("a"); return myset.has("a");`, + ); + expect(has).toBe(true); +}); + +test("set clear", () => { + const setTS = `let myset = new Set(["a", "b"]); myset.clear();`; + const size = util.transpileAndExecute(setTS + `return myset.size;`); + expect(size).toBe(0); + + const contains = util.transpileAndExecute(setTS + `return !myset.has("a") && !myset.has("b");`); + expect(contains).toBe(true); +}); + +test("set delete", () => { + const setTS = `let myset = new Set(["a", "b"]); myset.delete("a");`; + const contains = util.transpileAndExecute(setTS + `return myset.has("b") && !myset.has("a");`); + expect(contains).toBe(true); +}); + +test("set entries", () => { + const result = util.transpileAndExecute( + `let myset = new Set([5, 6, 7]); + let count = 0; + for (var [key, value] of myset.entries()) { count += key + value; } + return count;`, + ); + + expect(result).toBe(36); +}); + +test("set foreach", () => { + const result = util.transpileAndExecute( + `let myset = new Set([2, 3, 4]); + let count = 0; + myset.forEach(i => { count += i; }); + return count;`, + ); + expect(result).toBe(9); +}); + +test("set foreach keys", () => { + const result = util.transpileAndExecute( + `let myset = new Set([2, 3, 4]); + let count = 0; + myset.forEach((value, key) => { count += key; }); + return count;`, + ); + + expect(result).toBe(9); +}); + +test("set has", () => { + const contains = util.transpileAndExecute( + `let myset = new Set(["a", "c"]); return myset.has("a");`, + ); + expect(contains).toBe(true); +}); + +test("set has false", () => { + const contains = util.transpileAndExecute(`let myset = new Set(); return myset.has("a");`); + expect(contains).toBe(false); +}); + +test("set has null", () => { + const contains = util.transpileAndExecute( + `let myset = new Set(["a", "c"]); return myset.has(null);`, + ); + expect(contains).toBe(false); +}); + +test("set keys", () => { + const result = util.transpileAndExecute( + `let myset = new Set([5, 6, 7]); + let count = 0; + for (var key of myset.keys()) { count += key; } + return count;`, + ); + + expect(result).toBe(18); +}); + +test("set values", () => { + const result = util.transpileAndExecute( + `let myset = new Set([5, 6, 7]); + let count = 0; + for (var value of myset.values()) { count += value; } + return count;`, + ); + + expect(result).toBe(18); +}); + +test("set size", () => { + expect(util.transpileAndExecute(`let m = new Set(); return m.size;`)).toBe(0); + expect(util.transpileAndExecute(`let m = new Set(); m.add(1); return m.size;`)).toBe(1); + expect(util.transpileAndExecute(`let m = new Set([1, 2]); return m.size;`)).toBe(2); + expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.clear(); return m.size;`)).toBe(0); + expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.delete(2); return m.size;`)).toBe( + 1, + ); +}); diff --git a/test/unit/lualib/symbol.spec.ts b/test/unit/lualib/symbol.spec.ts index a15b79664..a094c2ddb 100644 --- a/test/unit/lualib/symbol.spec.ts +++ b/test/unit/lualib/symbol.spec.ts @@ -1,89 +1,66 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../../src/util"; -import { CompilerOptions, LuaLibImportKind } from '../../../src/CompilerOptions'; +import * as util from "../../util"; -export class SymbolTests { - private compilerOptions: CompilerOptions = { - lib: ["esnext"], - luaLibImport: LuaLibImportKind.Require, - }; - - @Test("symbol.toString()") - @TestCase() - @TestCase(1) - @TestCase("name") - public symbolToString(description?: string | number): void - { +test.each([{}, { description: 1 }, { description: "name" }])( + "symbol.toString() (%p)", + ({ description }) => { const result = util.transpileAndExecute(` - return Symbol(${JSON.stringify(description)}).toString(); - `, this.compilerOptions); + return Symbol(${JSON.stringify(description)}).toString(); +`); - Expect(result).toBe(`Symbol(${description || ''})`); - } + expect(result).toBe(`Symbol(${description || ""})`); + }, +); - @Test("symbol.description") - @TestCase() - @TestCase(1) - @TestCase("name") - public symbolDescription(description?: string | number): void - { +test.each([{}, { description: 1 }, { description: "name" }])( + "symbol.description (%p)", + ({ description }) => { const result = util.transpileAndExecute(` - return Symbol(${JSON.stringify(description)}).description; - `, this.compilerOptions); + return Symbol(${JSON.stringify(description)}).description; +`); - Expect(result).toBe(description); - } + expect(result).toBe(description); + }, +); - @Test("symbol uniqueness") - public symbolUniqueness(): void - { - const result = util.transpileAndExecute(` - return Symbol("a") === Symbol("a"); - `); +test("symbol uniqueness", () => { + const result = util.transpileAndExecute(` + return Symbol("a") === Symbol("a"); + `); - Expect(result).toBe(false); - } + expect(result).toBe(false); +}); - @Test("Symbol.for") - public symbolFor(): void - { - const result = util.transpileAndExecute(` - return Symbol.for("name").description; - `, this.compilerOptions); +test("Symbol.for", () => { + const result = util.transpileAndExecute(` + return Symbol.for("name").description; + `); - Expect(result).toBe("name"); - } + expect(result).toBe("name"); +}); - @Test("Symbol.for non-uniqueness") - public symbolForNonUniqueness(): void - { - const result = util.transpileAndExecute(` - return Symbol.for("a") === Symbol.for("a"); - `); +test("Symbol.for non-uniqueness", () => { + const result = util.transpileAndExecute(` + return Symbol.for("a") === Symbol.for("a"); + `); - Expect(result).toBe(true); - } + expect(result).toBe(true); +}); - @Test("Symbol.keyFor") - public symbolKeyFor(): void - { - const result = util.transpileAndExecute(` - const sym = Symbol.for("a"); - Symbol.for("b"); - return Symbol.keyFor(sym); - `); +test("Symbol.keyFor", () => { + const result = util.transpileAndExecute(` + const sym = Symbol.for("a"); + Symbol.for("b"); + return Symbol.keyFor(sym); + `); - Expect(result).toBe("a"); - } + expect(result).toBe("a"); +}); - @Test("Symbol.keyFor empty") - public symbolKeyForEmpty(): void - { - const result = util.transpileAndExecute(` - Symbol.for("a"); - return Symbol.keyFor(Symbol()); - `); +test("Symbol.keyFor empty", () => { + const result = util.transpileAndExecute(` + Symbol.for("a"); + return Symbol.keyFor(Symbol()); + `); - Expect(result).toBe(undefined); - } -} + expect(result).toBe(undefined); +}); diff --git a/test/unit/lualib/weakMap.spec.ts b/test/unit/lualib/weakMap.spec.ts index d9e829778..e386b8370 100644 --- a/test/unit/lualib/weakMap.spec.ts +++ b/test/unit/lualib/weakMap.spec.ts @@ -1,134 +1,139 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../../src/util"; - -export class WeakMapTests { - private initRefsTs = `let ref = {}; - let ref2 = () => {};`; - - @Test("weakMap constructor") - public weakMapConstructor(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, 1]]); - return mymap.get(ref); - `); - - Expect(result).toBe(1); - } - - @Test("weakMap iterable constructor") - public weakMapIterableConstructor(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, 1], [ref2, 2]]); - return mymap.has(ref) && mymap.has(ref2); - `); - - Expect(result).toBe(true); - } - - @Test("weakMap iterable constructor map") - public weakMapIterableConstructor2(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap(new Map([[ref, 1], [ref2, 2]])); - return mymap.has(ref) && mymap.has(ref2); - `); - - Expect(result).toBe(true); - } - - @Test("weakMap delete") - public weakMapDelete(): void - { - const contains = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, true], [ref2, true]]); - mymap.delete(ref2); - return mymap.has(ref) && !mymap.has(ref2); - `); - - Expect(contains).toBe(true); - } - - @Test("weakMap get") - public weakMapGet(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, 1], [{}, 2]]); - return mymap.get(ref); - `); - - Expect(result).toBe(1); - } - - @Test("weakMap get missing") - public weakMapGetMissing(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[{}, true]]); - return mymap.get({}); - `); - - Expect(result).toBe(undefined); - } - - @Test("weakMap has") - public weakMapHas(): void - { - const contains = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, true]]); - return mymap.has(ref); - `); - - Expect(contains).toBe(true); - } - - @Test("weakMap has false") - public weakMapHasFalse(): void - { - const contains = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[ref, true]]); - return mymap.has(ref2); - `); - - Expect(contains).toBe(false); - } - - @Test("weakMap has null") - public weakMapHasNull(): void - { - const contains = util.transpileAndExecute(this.initRefsTs + ` - let mymap = new WeakMap([[{}, true]]); - return mymap.has(null); - `); - - Expect(contains).toBe(false); - } - - @Test("weakMap set") - public weakMapSet(): void - { - const init = this.initRefsTs + ` - let mymap = new WeakMap(); - mymap.set(ref, 5); - `; - - const has = util.transpileAndExecute(init + `return mymap.has(ref);`); - Expect(has).toBe(true); - - const value = util.transpileAndExecute(init + `return mymap.get(ref)`); - Expect(value).toBe(5); - } - - @Test("weakMap has no map features") - public weakMapHasNoMapFeatures(): void - { - const transpileAndExecute = (tsStr: string) => util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); - Expect(transpileAndExecute(`return new WeakMap().size`)).toBe(undefined); - Expect(() => transpileAndExecute(`new WeakMap().clear()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakMap().keys()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakMap().values()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakMap().entries()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakMap().forEach(() => {})`)).toThrow(); - } -} +import * as util from "../../util"; + +const initRefsTs = `let ref = {}; + let ref2 = () => {};`; + +test("weakMap constructor", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, 1]]); + return mymap.get(ref); + `, + ); + + expect(result).toBe(1); +}); + +test("weakMap iterable constructor", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, 1], [ref2, 2]]); + return mymap.has(ref) && mymap.has(ref2); + `, + ); + + expect(result).toBe(true); +}); + +test("weakMap iterable constructor map", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap(new Map([[ref, 1], [ref2, 2]])); + return mymap.has(ref) && mymap.has(ref2); + `, + ); + + expect(result).toBe(true); +}); + +test("weakMap delete", () => { + const contains = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, true], [ref2, true]]); + mymap.delete(ref2); + return mymap.has(ref) && !mymap.has(ref2); + `, + ); + + expect(contains).toBe(true); +}); + +test("weakMap get", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, 1], [{}, 2]]); + return mymap.get(ref); + `, + ); + + expect(result).toBe(1); +}); + +test("weakMap get missing", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[{}, true]]); + return mymap.get({}); + `, + ); + + expect(result).toBe(undefined); +}); + +test("weakMap has", () => { + const contains = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, true]]); + return mymap.has(ref); + `, + ); + + expect(contains).toBe(true); +}); + +test("weakMap has false", () => { + const contains = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[ref, true]]); + return mymap.has(ref2); + `, + ); + + expect(contains).toBe(false); +}); + +test("weakMap has null", () => { + const contains = util.transpileAndExecute( + initRefsTs + + ` + let mymap = new WeakMap([[{}, true]]); + return mymap.has(null); + `, + ); + + expect(contains).toBe(false); +}); + +test("weakMap set", () => { + const init = + initRefsTs + + ` + let mymap = new WeakMap(); + mymap.set(ref, 5); + `; + + const has = util.transpileAndExecute(init + `return mymap.has(ref);`); + expect(has).toBe(true); + + const value = util.transpileAndExecute(init + `return mymap.get(ref)`); + expect(value).toBe(5); +}); + +test("weakMap has no map features", () => { + const transpileAndExecute = (tsStr: string) => + util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); + expect(transpileAndExecute(`return new WeakMap().size`)).toBe(undefined); + expect(() => transpileAndExecute(`new WeakMap().clear()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakMap().keys()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakMap().values()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakMap().entries()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakMap().forEach(() => {})`)).toThrow(); +}); diff --git a/test/unit/lualib/weakSet.spec.ts b/test/unit/lualib/weakSet.spec.ts index e4425618e..fbc462ea3 100644 --- a/test/unit/lualib/weakSet.spec.ts +++ b/test/unit/lualib/weakSet.spec.ts @@ -1,87 +1,89 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../../src/util"; +import * as util from "../../util"; -export class WeakSetTests { - private initRefsTs = `let ref = {}; - let ref2 = () => {};`; +const initRefsTs = `let ref = {}; + let ref2 = () => {};`; - @Test("weakSet constructor") - public weakSetConstructor(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet([ref]); - return myset.has(ref) - `); +test("weakSet constructor", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet([ref]); + return myset.has(ref) + `, + ); - Expect(result).toBe(true); - } + expect(result).toBe(true); +}); - @Test("weakSet iterable constructor") - public weakSetIterableConstructor(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet([ref, ref2]); - return myset.has(ref) && myset.has(ref2); - `); +test("weakSet iterable constructor", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet([ref, ref2]); + return myset.has(ref) && myset.has(ref2); + `, + ); - Expect(result).toBe(true); - } + expect(result).toBe(true); +}); - @Test("weakSet iterable constructor set") - public weakSetIterableConstructorSet(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet(new Set([ref, ref2])); - return myset.has(ref) && myset.has(ref2); - `); +test("weakSet iterable constructor set", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet(new Set([ref, ref2])); + return myset.has(ref) && myset.has(ref2); + `, + ); - Expect(result).toBe(true); - } + expect(result).toBe(true); +}); - @Test("weakSet add") - public weakSetAdd(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet(); - myset.add(ref); - return myset.has(ref); - `); +test("weakSet add", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet(); + myset.add(ref); + return myset.has(ref); + `, + ); - Expect(result).toBe(true); - } + expect(result).toBe(true); +}); - @Test("weakSet add different references") - public weakSetAddDifferentReferences(): void - { - const result = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet(); - myset.add({}); - return myset.has({}); - `); +test("weakSet add different references", () => { + const result = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet(); + myset.add({}); + return myset.has({}); + `, + ); - Expect(result).toBe(false); - } + expect(result).toBe(false); +}); - @Test("weakSet delete") - public weakSetDelete(): void - { - const contains = util.transpileAndExecute(this.initRefsTs + ` - let myset = new WeakSet([ref, ref2]); - myset.delete(ref); - return myset.has(ref2) && !myset.has(ref); - `); - Expect(contains).toBe(true); - } +test("weakSet delete", () => { + const contains = util.transpileAndExecute( + initRefsTs + + ` + let myset = new WeakSet([ref, ref2]); + myset.delete(ref); + return myset.has(ref2) && !myset.has(ref); + `, + ); + expect(contains).toBe(true); +}); - @Test("weakSet has no set features") - public weakSetHasNoSetFeatures(): void - { - const transpileAndExecute = (tsStr: string) => util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); - Expect(transpileAndExecute(`return new WeakSet().size`)).toBe(undefined); - Expect(() => transpileAndExecute(`new WeakSet().clear()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakSet().keys()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakSet().values()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakSet().entries()`)).toThrow(); - Expect(() => transpileAndExecute(`new WeakSet().forEach(() => {})`)).toThrow(); - } -} +test("weakSet has no set features", () => { + const transpileAndExecute = (tsStr: string) => + util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); + expect(transpileAndExecute(`return new WeakSet().size`)).toBe(undefined); + expect(() => transpileAndExecute(`new WeakSet().clear()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakSet().keys()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakSet().values()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakSet().entries()`)).toThrow(); + expect(() => transpileAndExecute(`new WeakSet().forEach(() => {})`)).toThrow(); +}); diff --git a/test/unit/math.spec.ts b/test/unit/math.spec.ts index ad9047553..f44429f7f 100644 --- a/test/unit/math.spec.ts +++ b/test/unit/math.spec.ts @@ -1,258 +1,253 @@ -import { Expect, Test, TestCase, IgnoreTest } from "alsatian"; -import * as util from "../src/util"; +import * as util from "../util"; -export class MathTests { +test.each([ + { inp: "Math.cos()", expected: "math.cos();" }, + { inp: "Math.sin()", expected: "math.sin();" }, + { inp: "Math.min()", expected: "math.min();" }, + { inp: "Math.atan2(2, 3)", expected: "math.atan(2 / 3);" }, + { inp: "Math.log2(3)", expected: `(math.log(3) / ${Math.LN2});` }, + { inp: "Math.log10(3)", expected: `(math.log(3) / ${Math.LN10});` }, + { inp: "Math.log1p(3)", expected: "math.log(1 + 3);" }, + { inp: "Math.round(3.3)", expected: "math.floor(3.3 + 0.5);" }, + { inp: "Math.PI", expected: "math.pi;" }, +])("Math (%p)", ({ inp, expected }) => { + const lua = util.transpileString(inp); - // Dont test all and dont do functional test - // because math implementations may differ between js and lua - @TestCase("Math.cos()", "math.cos();") - @TestCase("Math.sin()", "math.sin();") - @TestCase("Math.min()", "math.min();") - @TestCase("Math.atan2(2, 3)", "math.atan(2 / 3);") - @TestCase("Math.log2(3)", `(math.log(3) / ${Math.LN2});`) - @TestCase("Math.log10(3)", `(math.log(3) / ${Math.LN10});`) - @TestCase("Math.log1p(3)", "math.log(1 + 3);") - @TestCase("Math.round(3.3)", "math.floor(3.3 + 0.5);") - @TestCase("Math.PI", "math.pi;") - @Test("Math") - public math(inp: string, expected: string): void { - // Transpile - const lua = util.transpileString(inp); + expect(lua).toBe(expected); +}); - // Assert - Expect(lua).toBe(expected); - } - - @TestCase("E") - @TestCase("LN10") - @TestCase("LN2") - @TestCase("LOG10E") - @TestCase("LOG2E") - @TestCase("SQRT1_2") - @TestCase("SQRT2") - @Test("Math constant") - public mathConstant(constant: string): void { +test.each(["E", "LN10", "LN2", "LOG10E", "LOG2E", "SQRT1_2", "SQRT2"])( + "Math constant (%p)", + constant => { const epsilon = 0.000001; const code = `return Math.abs(Math.${constant} - ${Math[constant]}) <= ${epsilon}`; - Expect(util.transpileAndExecute(code)).toBe(true); - } + expect(util.transpileAndExecute(code)).toBe(true); + }, +); - @TestCase("++x", "x=4;y=6") - @TestCase("x++", "x=4;y=6") - @TestCase("--x", "x=2;y=6") - @TestCase("x--", "x=2;y=6") - @TestCase("x += y", "x=9;y=6") - @TestCase("x -= y", "x=-3;y=6") - @TestCase("x *= y", "x=18;y=6") - @TestCase("y /= x", "x=3;y=2.0") - @TestCase("y %= x", "x=3;y=0") - @TestCase("y **= x", "x=3;y=216.0") - @TestCase("x |= y", "x=7;y=6") - @TestCase("x &= y", "x=2;y=6") - @TestCase("x ^= y", "x=5;y=6") - @TestCase("x <<= y", "x=192;y=6") - @TestCase("x >>>= y", "x=0;y=6") - @Test("Operator assignment statements") - public opAssignmentStatement(statement: string, expected: string): void { - const result = util.transpileAndExecute( - `let x = 3; - let y = 6; - ${statement}; - return \`x=\${x};y=\${y}\``); - Expect(result).toBe(expected); - } +test.each([ + { statement: "++x", expected: "x=4;y=6" }, + { statement: "x++", expected: "x=4;y=6" }, + { statement: "--x", expected: "x=2;y=6" }, + { statement: "x--", expected: "x=2;y=6" }, + { statement: "x += y", expected: "x=9;y=6" }, + { statement: "x -= y", expected: "x=-3;y=6" }, + { statement: "x *= y", expected: "x=18;y=6" }, + { statement: "y /= x", expected: "x=3;y=2.0" }, + { statement: "y %= x", expected: "x=3;y=0" }, + { statement: "y **= x", expected: "x=3;y=216.0" }, + { statement: "x |= y", expected: "x=7;y=6" }, + { statement: "x &= y", expected: "x=2;y=6" }, + { statement: "x ^= y", expected: "x=5;y=6" }, + { statement: "x <<= y", expected: "x=192;y=6" }, + { statement: "x >>>= y", expected: "x=0;y=6" }, +])("Operator assignment statements (%p)", ({ statement, expected }) => { + const result = util.transpileAndExecute( + `let x = 3; + let y = 6; + ${statement}; + return \`x=\${x};y=\${y}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++o.p", "o=4;a=6") - @TestCase("o.p++", "o=4;a=6") - @TestCase("--o.p", "o=2;a=6") - @TestCase("o.p--", "o=2;a=6") - @TestCase("o.p += a[0]", "o=9;a=6") - @TestCase("o.p -= a[0]", "o=-3;a=6") - @TestCase("o.p *= a[0]", "o=18;a=6") - @TestCase("a[0] /= o.p", "o=3;a=2.0") - @TestCase("a[0] %= o.p", "o=3;a=0") - @TestCase("a[0] **= o.p", "o=3;a=216.0") - @TestCase("o.p |= a[0]", "o=7;a=6") - @TestCase("o.p &= a[0]", "o=2;a=6") - @TestCase("o.p ^= a[0]", "o=5;a=6") - @TestCase("o.p <<= a[0]", "o=192;a=6") - @TestCase("o.p >>>= a[0]", "o=0;a=6") - @Test("Operator assignment to simple property statements") - public opSimplePropAssignmentStatement(statement: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: 3}; - let a = [6]; - ${statement}; - return \`o=\${o.p};a=\${a[0]}\``); - Expect(result).toBe(expected); - } +test.each([ + { statement: "++o.p", expected: "o=4;a=6" }, + { statement: "o.p++", expected: "o=4;a=6" }, + { statement: "--o.p", expected: "o=2;a=6" }, + { statement: "o.p--", expected: "o=2;a=6" }, + { statement: "o.p += a[0]", expected: "o=9;a=6" }, + { statement: "o.p -= a[0]", expected: "o=-3;a=6" }, + { statement: "o.p *= a[0]", expected: "o=18;a=6" }, + { statement: "a[0] /= o.p", expected: "o=3;a=2.0" }, + { statement: "a[0] %= o.p", expected: "o=3;a=0" }, + { statement: "a[0] **= o.p", expected: "o=3;a=216.0" }, + { statement: "o.p |= a[0]", expected: "o=7;a=6" }, + { statement: "o.p &= a[0]", expected: "o=2;a=6" }, + { statement: "o.p ^= a[0]", expected: "o=5;a=6" }, + { statement: "o.p <<= a[0]", expected: "o=192;a=6" }, + { statement: "o.p >>>= a[0]", expected: "o=0;a=6" }, +])("Operator assignment to simple property statements (%p)", ({ statement, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: 3}; + let a = [6]; + ${statement}; + return \`o=\${o.p};a=\${a[0]}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++o.p.d", "o=4;a=[6,11],[7,13]") - @TestCase("o.p.d++", "o=4;a=[6,11],[7,13]") - @TestCase("--o.p.d", "o=2;a=[6,11],[7,13]") - @TestCase("o.p.d--", "o=2;a=[6,11],[7,13]") - @TestCase("o.p.d += a[0][0]", "o=9;a=[6,11],[7,13]") - @TestCase("o.p.d -= a[0][0]", "o=-3;a=[6,11],[7,13]") - @TestCase("o.p.d *= a[0][0]", "o=18;a=[6,11],[7,13]") - @TestCase("a[0][0] /= o.p.d", "o=3;a=[2.0,11],[7,13]") - @TestCase("a[0][0] %= o.p.d", "o=3;a=[0,11],[7,13]") - @TestCase("a[0][0] **= o.p.d", "o=3;a=[216.0,11],[7,13]") - @TestCase("o.p.d |= a[0][0]", "o=7;a=[6,11],[7,13]") - @TestCase("o.p.d &= a[0][0]", "o=2;a=[6,11],[7,13]") - @TestCase("o.p.d ^= a[0][0]", "o=5;a=[6,11],[7,13]") - @TestCase("o.p.d <<= a[0][0]", "o=192;a=[6,11],[7,13]") - @TestCase("o.p.d >>>= a[0][0]", "o=0;a=[6,11],[7,13]") - @Test("Operator assignment to deep property statements") - public opDeepPropAssignmentStatement(statement: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: {d: 3}}; - let a = [[6,11], [7,13]]; - ${statement}; - return \`o=\${o.p.d};a=[\${a[0][0]},\${a[0][1]}],[\${a[1][0]},\${a[1][1]}]\``); - Expect(result).toBe(expected); - } +test.each([ + { statement: "++o.p.d", expected: "o=4;a=[6,11],[7,13]" }, + { statement: "o.p.d++", expected: "o=4;a=[6,11],[7,13]" }, + { statement: "--o.p.d", expected: "o=2;a=[6,11],[7,13]" }, + { statement: "o.p.d--", expected: "o=2;a=[6,11],[7,13]" }, + { statement: "o.p.d += a[0][0]", expected: "o=9;a=[6,11],[7,13]" }, + { statement: "o.p.d -= a[0][0]", expected: "o=-3;a=[6,11],[7,13]" }, + { statement: "o.p.d *= a[0][0]", expected: "o=18;a=[6,11],[7,13]" }, + { statement: "a[0][0] /= o.p.d", expected: "o=3;a=[2.0,11],[7,13]" }, + { statement: "a[0][0] %= o.p.d", expected: "o=3;a=[0,11],[7,13]" }, + { statement: "a[0][0] **= o.p.d", expected: "o=3;a=[216.0,11],[7,13]" }, + { statement: "o.p.d |= a[0][0]", expected: "o=7;a=[6,11],[7,13]" }, + { statement: "o.p.d &= a[0][0]", expected: "o=2;a=[6,11],[7,13]" }, + { statement: "o.p.d ^= a[0][0]", expected: "o=5;a=[6,11],[7,13]" }, + { statement: "o.p.d <<= a[0][0]", expected: "o=192;a=[6,11],[7,13]" }, + { statement: "o.p.d >>>= a[0][0]", expected: "o=0;a=[6,11],[7,13]" }, +])("Operator assignment to deep property statements (%p)", ({ statement, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: {d: 3}}; + let a = [[6,11], [7,13]]; + ${statement}; + return \`o=\${o.p.d};a=[\${a[0][0]},\${a[0][1]}],[\${a[1][0]},\${a[1][1]}]\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++of().p", "o=4;a=6") - @TestCase("of().p++", "o=4;a=6") - @TestCase("--of().p", "o=2;a=6") - @TestCase("of().p--", "o=2;a=6") - @TestCase("of().p += af()[i()]", "o=9;a=6") - @TestCase("of().p -= af()[i()]", "o=-3;a=6") - @TestCase("of().p *= af()[i()]", "o=18;a=6") - @TestCase("af()[i()] /= of().p", "o=3;a=2.0") - @TestCase("af()[i()] %= of().p", "o=3;a=0") - @TestCase("af()[i()] **= of().p", "o=3;a=216.0") - @TestCase("of().p |= af()[i()]", "o=7;a=6") - @TestCase("of().p &= af()[i()]", "o=2;a=6") - @TestCase("of().p ^= af()[i()]", "o=5;a=6") - @TestCase("of().p <<= af()[i()]", "o=192;a=6") - @TestCase("of().p >>>= af()[i()]", "o=0;a=6") - @Test("Operator assignment to complex property statements") - public opComplexPropAssignmentStatement(statement: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: 3}; - let a = [6]; - function of() { return o; } - function af() { return a; } - function i() { return 0; } - ${statement}; - return \`o=\${o.p};a=\${a[0]}\``); - Expect(result).toBe(expected); - } +test.each([ + { statement: "++of().p", expected: "o=4;a=6" }, + { statement: "of().p++", expected: "o=4;a=6" }, + { statement: "--of().p", expected: "o=2;a=6" }, + { statement: "of().p--", expected: "o=2;a=6" }, + { statement: "of().p += af()[i()]", expected: "o=9;a=6" }, + { statement: "of().p -= af()[i()]", expected: "o=-3;a=6" }, + { statement: "of().p *= af()[i()]", expected: "o=18;a=6" }, + { statement: "af()[i()] /= of().p", expected: "o=3;a=2.0" }, + { statement: "af()[i()] %= of().p", expected: "o=3;a=0" }, + { statement: "af()[i()] **= of().p", expected: "o=3;a=216.0" }, + { statement: "of().p |= af()[i()]", expected: "o=7;a=6" }, + { statement: "of().p &= af()[i()]", expected: "o=2;a=6" }, + { statement: "of().p ^= af()[i()]", expected: "o=5;a=6" }, + { statement: "of().p <<= af()[i()]", expected: "o=192;a=6" }, + { statement: "of().p >>>= af()[i()]", expected: "o=0;a=6" }, +])("Operator assignment to complex property statements (%p)", ({ statement, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: 3}; + let a = [6]; + function of() { return o; } + function af() { return a; } + function i() { return 0; } + ${statement}; + return \`o=\${o.p};a=\${a[0]}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++of().p.d", "o=4;a=[7,6],[11,13];i=0") - @TestCase("of().p.d++", "o=4;a=[7,6],[11,13];i=0") - @TestCase("--of().p.d", "o=2;a=[7,6],[11,13];i=0") - @TestCase("of().p.d--", "o=2;a=[7,6],[11,13];i=0") - @TestCase("of().p.d += af()[i()][i()]", "o=9;a=[7,6],[11,13];i=2") - @TestCase("of().p.d -= af()[i()][i()]", "o=-3;a=[7,6],[11,13];i=2") - @TestCase("of().p.d *= af()[i()][i()]", "o=18;a=[7,6],[11,13];i=2") - @TestCase("af()[i()][i()] /= of().p.d", "o=3;a=[7,2.0],[11,13];i=2") - @TestCase("af()[i()][i()] %= of().p.d", "o=3;a=[7,0],[11,13];i=2") - @TestCase("af()[i()][i()] **= of().p.d", "o=3;a=[7,216.0],[11,13];i=2") - @TestCase("of().p.d |= af()[i()][i()]", "o=7;a=[7,6],[11,13];i=2") - @TestCase("of().p.d &= af()[i()][i()]", "o=2;a=[7,6],[11,13];i=2") - @TestCase("of().p.d ^= af()[i()][i()]", "o=5;a=[7,6],[11,13];i=2") - @TestCase("of().p.d <<= af()[i()][i()]", "o=192;a=[7,6],[11,13];i=2") - @TestCase("of().p.d >>>= af()[i()][i()]", "o=0;a=[7,6],[11,13];i=2") - @Test("Operator assignment to complex deep property statements") - public opComplexDeepPropAssignmentStatement(statement: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: {d: 3}}; - let a = [[7, 6], [11, 13]]; - function of() { return o; } - function af() { return a; } - let _i = 0; - function i() { return _i++; } - ${statement}; - return \`o=\${o.p.d};a=[\${a[0][0]},\${a[0][1]}],[\${a[1][0]},\${a[1][1]}];i=\${_i}\``); - Expect(result).toBe(expected); - } +test.each([ + { statement: "++of().p.d", expected: "o=4;a=[7,6],[11,13];i=0" }, + { statement: "of().p.d++", expected: "o=4;a=[7,6],[11,13];i=0" }, + { statement: "--of().p.d", expected: "o=2;a=[7,6],[11,13];i=0" }, + { statement: "of().p.d--", expected: "o=2;a=[7,6],[11,13];i=0" }, + { statement: "of().p.d += af()[i()][i()]", expected: "o=9;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d -= af()[i()][i()]", expected: "o=-3;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d *= af()[i()][i()]", expected: "o=18;a=[7,6],[11,13];i=2" }, + { statement: "af()[i()][i()] /= of().p.d", expected: "o=3;a=[7,2.0],[11,13];i=2" }, + { statement: "af()[i()][i()] %= of().p.d", expected: "o=3;a=[7,0],[11,13];i=2" }, + { statement: "af()[i()][i()] **= of().p.d", expected: "o=3;a=[7,216.0],[11,13];i=2" }, + { statement: "of().p.d |= af()[i()][i()]", expected: "o=7;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d &= af()[i()][i()]", expected: "o=2;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d ^= af()[i()][i()]", expected: "o=5;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d <<= af()[i()][i()]", expected: "o=192;a=[7,6],[11,13];i=2" }, + { statement: "of().p.d >>>= af()[i()][i()]", expected: "o=0;a=[7,6],[11,13];i=2" }, +])("Operator assignment to complex deep property statements (%p)", ({ statement, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: {d: 3}}; + let a = [[7, 6], [11, 13]]; + function of() { return o; } + function af() { return a; } + let _i = 0; + function i() { return _i++; } + ${statement}; + return \`o=\${o.p.d};a=[\${a[0][0]},\${a[0][1]}],[\${a[1][0]},\${a[1][1]}];i=\${_i}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++x", "4;x=4;y=6") - @TestCase("x++", "3;x=4;y=6") - @TestCase("--x", "2;x=2;y=6") - @TestCase("x--", "3;x=2;y=6") - @TestCase("x += y", "9;x=9;y=6") - @TestCase("x -= y", "-3;x=-3;y=6") - @TestCase("x *= y", "18;x=18;y=6") - @TestCase("y /= x", "2.0;x=3;y=2.0") - @TestCase("y %= x", "0;x=3;y=0") - @TestCase("y **= x", "216.0;x=3;y=216.0") - @TestCase("x |= y", "7;x=7;y=6") - @TestCase("x &= y", "2;x=2;y=6") - @TestCase("x ^= y", "5;x=5;y=6") - @TestCase("x <<= y", "192;x=192;y=6") - @TestCase("x >>>= y", "0;x=0;y=6") - @TestCase("x + (y += 7)", "16;x=3;y=13") - @TestCase("x + (y += 7)", "16;x=3;y=13") - @TestCase("x++ + (y += 7)", "16;x=4;y=13") - @Test("Operator assignment expressions") - public opAssignmentExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `let x = 3; - let y = 6; - const r = ${expression}; - return \`\${r};x=\${x};y=\${y}\``); - Expect(result).toBe(expected); - } +test.each([ + { expression: "++x", expected: "4;x=4;y=6" }, + { expression: "x++", expected: "3;x=4;y=6" }, + { expression: "--x", expected: "2;x=2;y=6" }, + { expression: "x--", expected: "3;x=2;y=6" }, + { expression: "x += y", expected: "9;x=9;y=6" }, + { expression: "x -= y", expected: "-3;x=-3;y=6" }, + { expression: "x *= y", expected: "18;x=18;y=6" }, + { expression: "y /= x", expected: "2.0;x=3;y=2.0" }, + { expression: "y %= x", expected: "0;x=3;y=0" }, + { expression: "y **= x", expected: "216.0;x=3;y=216.0" }, + { expression: "x |= y", expected: "7;x=7;y=6" }, + { expression: "x &= y", expected: "2;x=2;y=6" }, + { expression: "x ^= y", expected: "5;x=5;y=6" }, + { expression: "x <<= y", expected: "192;x=192;y=6" }, + { expression: "x >>>= y", expected: "0;x=0;y=6" }, + { expression: "x + (y += 7)", expected: "16;x=3;y=13" }, + { expression: "x + (y += 7)", expected: "16;x=3;y=13" }, + { expression: "x++ + (y += 7)", expected: "16;x=4;y=13" }, +])("Operator assignment expressions (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `let x = 3; + let y = 6; + const r = ${expression}; + return \`\${r};x=\${x};y=\${y}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++o.p", "4;o=4;a=6") - @TestCase("o.p++", "3;o=4;a=6") - @TestCase("--o.p", "2;o=2;a=6") - @TestCase("o.p--", "3;o=2;a=6") - @TestCase("o.p += a[0]", "9;o=9;a=6") - @TestCase("o.p -= a[0]", "-3;o=-3;a=6") - @TestCase("o.p *= a[0]", "18;o=18;a=6") - @TestCase("a[0] /= o.p", "2.0;o=3;a=2.0") - @TestCase("a[0] %= o.p", "0;o=3;a=0") - @TestCase("a[0] **= o.p", "216.0;o=3;a=216.0") - @TestCase("o.p |= a[0]", "7;o=7;a=6") - @TestCase("o.p &= a[0]", "2;o=2;a=6") - @TestCase("o.p ^= a[0]", "5;o=5;a=6") - @TestCase("o.p <<= a[0]", "192;o=192;a=6") - @TestCase("o.p >>>= a[0]", "0;o=0;a=6") - @TestCase("o.p + (a[0] += 7)", "16;o=3;a=13") - @TestCase("o.p += (a[0] += 7)", "16;o=16;a=13") - @TestCase("o.p++ + (a[0] += 7)", "16;o=4;a=13") - @Test("Operator assignment to simple property expressions") - public opSimplePropAssignmentExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: 3}; - let a = [6]; - const r = ${expression}; - return \`\${r};o=\${o.p};a=\${a[0]}\``); - Expect(result).toBe(expected); - } +test.each([ + { expression: "++o.p", expected: "4;o=4;a=6" }, + { expression: "o.p++", expected: "3;o=4;a=6" }, + { expression: "--o.p", expected: "2;o=2;a=6" }, + { expression: "o.p--", expected: "3;o=2;a=6" }, + { expression: "o.p += a[0]", expected: "9;o=9;a=6" }, + { expression: "o.p -= a[0]", expected: "-3;o=-3;a=6" }, + { expression: "o.p *= a[0]", expected: "18;o=18;a=6" }, + { expression: "a[0] /= o.p", expected: "2.0;o=3;a=2.0" }, + { expression: "a[0] %= o.p", expected: "0;o=3;a=0" }, + { expression: "a[0] **= o.p", expected: "216.0;o=3;a=216.0" }, + { expression: "o.p |= a[0]", expected: "7;o=7;a=6" }, + { expression: "o.p &= a[0]", expected: "2;o=2;a=6" }, + { expression: "o.p ^= a[0]", expected: "5;o=5;a=6" }, + { expression: "o.p <<= a[0]", expected: "192;o=192;a=6" }, + { expression: "o.p >>>= a[0]", expected: "0;o=0;a=6" }, + { expression: "o.p + (a[0] += 7)", expected: "16;o=3;a=13" }, + { expression: "o.p += (a[0] += 7)", expected: "16;o=16;a=13" }, + { expression: "o.p++ + (a[0] += 7)", expected: "16;o=4;a=13" }, +])("Operator assignment to simple property expressions (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: 3}; + let a = [6]; + const r = ${expression}; + return \`\${r};o=\${o.p};a=\${a[0]}\``, + ); + expect(result).toBe(expected); +}); - @TestCase("++of().p", "4;o=4;a=6") - @TestCase("of().p++", "3;o=4;a=6") - @TestCase("--of().p", "2;o=2;a=6") - @TestCase("of().p--", "3;o=2;a=6") - @TestCase("of().p += af()[i()]", "9;o=9;a=6") - @TestCase("of().p -= af()[i()]", "-3;o=-3;a=6") - @TestCase("of().p *= af()[i()]", "18;o=18;a=6") - @TestCase("af()[i()] /= of().p", "2.0;o=3;a=2.0") - @TestCase("af()[i()] %= of().p", "0;o=3;a=0") - @TestCase("af()[i()] **= of().p", "216.0;o=3;a=216.0") - @TestCase("of().p |= af()[i()]", "7;o=7;a=6") - @TestCase("of().p &= af()[i()]", "2;o=2;a=6") - @TestCase("of().p ^= af()[i()]", "5;o=5;a=6") - @TestCase("of().p <<= af()[i()]", "192;o=192;a=6") - @TestCase("of().p >>>= af()[i()]", "0;o=0;a=6") - @TestCase("of().p + (af()[i()] += 7)", "16;o=3;a=13") - @TestCase("of().p += (af()[i()] += 7)", "16;o=16;a=13") - @TestCase("of().p++ + (af()[i()] += 7)", "16;o=4;a=13") - @Test("Operator assignment to complex property expressions") - public opComplexPropAssignmentExpression(expression: string, expected: string): void { - const result = util.transpileAndExecute( - `let o = {p: 3}; - let a = [6]; - function of() { return o; } - function af() { return a; } - function i() { return 0; } - const r = ${expression}; - return \`\${r};o=\${o.p};a=\${a[0]}\``); - Expect(result).toBe(expected); - } -} +test.each([ + { expression: "++of().p", expected: "4;o=4;a=6" }, + { expression: "of().p++", expected: "3;o=4;a=6" }, + { expression: "--of().p", expected: "2;o=2;a=6" }, + { expression: "of().p--", expected: "3;o=2;a=6" }, + { expression: "of().p += af()[i()]", expected: "9;o=9;a=6" }, + { expression: "of().p -= af()[i()]", expected: "-3;o=-3;a=6" }, + { expression: "of().p *= af()[i()]", expected: "18;o=18;a=6" }, + { expression: "af()[i()] /= of().p", expected: "2.0;o=3;a=2.0" }, + { expression: "af()[i()] %= of().p", expected: "0;o=3;a=0" }, + { expression: "af()[i()] **= of().p", expected: "216.0;o=3;a=216.0" }, + { expression: "of().p |= af()[i()]", expected: "7;o=7;a=6" }, + { expression: "of().p &= af()[i()]", expected: "2;o=2;a=6" }, + { expression: "of().p ^= af()[i()]", expected: "5;o=5;a=6" }, + { expression: "of().p <<= af()[i()]", expected: "192;o=192;a=6" }, + { expression: "of().p >>>= af()[i()]", expected: "0;o=0;a=6" }, + { expression: "of().p + (af()[i()] += 7)", expected: "16;o=3;a=13" }, + { expression: "of().p += (af()[i()] += 7)", expected: "16;o=16;a=13" }, + { expression: "of().p++ + (af()[i()] += 7)", expected: "16;o=4;a=13" }, +])("Operator assignment to complex property expressions (%p)", ({ expression, expected }) => { + const result = util.transpileAndExecute( + `let o = {p: 3}; + let a = [6]; + function of() { return o; } + function af() { return a; } + function i() { return 0; } + const r = ${expression}; + return \`\${r};o=\${o.p};a=\${a[0]}\``, + ); + expect(result).toBe(expected); +}); diff --git a/test/unit/modules.spec.ts b/test/unit/modules.spec.ts index 606e39985..878169eaf 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -1,78 +1,64 @@ -import { Expect, Test, TestCase } from "alsatian"; import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; +import * as util from "../util"; -import * as ts from "typescript"; -import * as util from "../src/util"; +test("defaultImport", () => { + expect(() => { + const lua = util.transpileString(`import TestClass from "test"`); + }).toThrowExactError( + new Error("Default Imports are not supported, please use named imports instead!"), + ); +}); -export class LuaModuleTests { +test("lualibRequire", () => { + const lua = util.transpileString(`let a = b instanceof c;`, { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.LuaJIT, + }); - @Test("defaultImport") - public defaultImport(): void { - Expect(() => { - const lua = util.transpileString(`import TestClass from "test"`); - }).toThrowError(Error, "Default Imports are not supported, please use named imports instead!"); - } + expect(lua.startsWith(`require("lualib_bundle")`)); +}); - @Test("lualibRequire") - public lualibRequire(): void { - // Transpile - const lua = util.transpileString(`let a = b instanceof c;`, - { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.LuaJIT }); +test("lualibRequireAlways", () => { + const lua = util.transpileString(``, { + luaLibImport: LuaLibImportKind.Always, + luaTarget: LuaTarget.LuaJIT, + }); - // Assert - Expect(lua.startsWith(`require("lualib_bundle")`)); - } + expect(lua).toBe(`require("lualib_bundle");`); +}); - @Test("lualibRequireAlways") - public lualibRequireAlways(): void { - // Transpile - const lua = util.transpileString(``, { luaLibImport: LuaLibImportKind.Always, luaTarget: LuaTarget.LuaJIT }); +test("Non-exported module", () => { + const result = util.transpileAndExecute( + "return g.test();", + undefined, + undefined, + "module g { export function test() { return 3; } }", + ); - // Assert - Expect(lua).toBe(`require("lualib_bundle");`); - } + expect(result).toBe(3); +}); - @Test("Non-exported module") - public nonExportedModule(): void { - const result = util.transpileAndExecute( - "return g.test();", - undefined, - undefined, - "module g { export function test() { return 3; } }" // Typescript header - ); - - Expect(result).toBe(3); - } - - @TestCase(LuaLibImportKind.Inline) - @TestCase(LuaLibImportKind.None) - @TestCase(LuaLibImportKind.Require) - @Test("LuaLib no uses? No code") - public lualibNoUsesNoCode(impKind: LuaLibImportKind): void { - // Transpile +test.each([LuaLibImportKind.Inline, LuaLibImportKind.None, LuaLibImportKind.Require])( + "LuaLib no uses? No code (%p)", + impKind => { const lua = util.transpileString(``, { luaLibImport: impKind }); - // Assert - Expect(lua).toBe(``); - } + expect(lua).toBe(``); + }, +); - @Test("Nested module with dot in name") - public nestedModuleWithDotInName(): void { - const code = - `module a.b { - export const foo = "foo"; - }`; - Expect(util.transpileAndExecute("return a.b.foo;", undefined, undefined, code)).toBe("foo"); - } +test("Nested module with dot in name", () => { + const code = `module a.b { + export const foo = "foo"; + }`; + expect(util.transpileAndExecute("return a.b.foo;", undefined, undefined, code)).toBe("foo"); +}); - @Test("Access this in module") - public accessThisInModule(): void { - const header = - `module M { - export const foo = "foo"; - export function bar() { return this.foo + "bar"; } - }`; - const code = `return M.bar();`; - Expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foobar"); - } -} +test("Access this in module", () => { + const header = `module M { + export const foo = "foo"; + export function bar() { return this.foo + "bar"; } + }`; + const code = `return M.bar();`; + expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foobar"); +}); diff --git a/test/unit/objectLiteral.spec.ts b/test/unit/objectLiteral.spec.ts index e3858fae6..21ae4abf0 100644 --- a/test/unit/objectLiteral.spec.ts +++ b/test/unit/objectLiteral.spec.ts @@ -1,34 +1,28 @@ -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; const fs = require("fs"); -export class ObjectLiteralTests { - - @TestCase(`{a:3,b:"4"}`, `{a = 3, b = "4"};`) - @TestCase(`{"a":3,b:"4"}`, `{a = 3, b = "4"};`) - @TestCase(`{["a"]:3,b:"4"}`, `{a = 3, b = "4"};`) - @TestCase(`{["a"+123]:3,b:"4"}`, `{["a" .. 123] = 3, b = "4"};`) - @TestCase(`{[myFunc()]:3,b:"4"}`, `{[myFunc(_G)] = 3, b = "4"};`) - @TestCase(`{x}`, `{x = x};`) - @Test("Object Literal") - public objectLiteral(inp: string, out: string): void { - const lua = util.transpileString(`const myvar = ${inp};`); - Expect(lua).toBe(`local myvar = ${out}`); - } +test.each([ + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"};` }, + { inp: `{"a":3,b:"4"}`, out: `{a = 3, b = "4"};` }, + { inp: `{["a"]:3,b:"4"}`, out: `{a = 3, b = "4"};` }, + { inp: `{["a"+123]:3,b:"4"}`, out: `{["a" .. 123] = 3, b = "4"};` }, + { inp: `{[myFunc()]:3,b:"4"}`, out: `{[myFunc(_G)] = 3, b = "4"};` }, + { inp: `{x}`, out: `{x = x};` }, +])("Object Literal (%p)", ({ inp, out }) => { + const lua = util.transpileString(`const myvar = ${inp};`); + expect(lua).toBe(`local myvar = ${out}`); +}); - @TestCase("3", 3) - @Test("Shorthand Property Assignment") - public ShorthandPropertyAssignment(input: string, expected: number): void { +test.each([{ input: "3", expected: 3 }])( + "Shorthand Property Assignment (%p)", + ({ input, expected }) => { const result = util.transpileAndExecute(`const x = ${input}; const o = {x}; return o.x;`); - Expect(result).toBe(expected); - } + expect(result).toBe(expected); + }, +); - @Test("undefined as object key") - public undefinedAsObjectKey(): void { - const code = - `const foo = {undefined: "foo"}; - return foo.undefined;`; - Expect(util.transpileAndExecute(code)).toBe("foo"); - } -} +test("undefined as object key", () => { + const code = `const foo = {undefined: "foo"}; + return foo.undefined;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); diff --git a/test/unit/overloads.spec.ts b/test/unit/overloads.spec.ts index 1b6d7e925..482cdd089 100644 --- a/test/unit/overloads.spec.ts +++ b/test/unit/overloads.spec.ts @@ -1,129 +1,119 @@ -import { Expect, Test, TestCase } from "alsatian"; +import * as util from "../util"; -import * as util from "../src/util"; +test("overload function1", () => { + const result = util.transpileAndExecute( + `function abc(def: number): string; + function abc(def: string): string; + function abc(def: number | string): string { + if (typeof def == "number") { + return "jkl" + (def * 3); + } else { + return def; + } + } + return abc(3);`, + ); + + expect(result).toBe("jkl9"); +}); + +test("overload function2", () => { + const result = util.transpileAndExecute( + `function abc(def: number): string; + function abc(def: string): string; + function abc(def: number | string): string { + if (typeof def == "number") { + return "jkl" + (def * 3); + } else { + return def; + } + } + return abc("ghj");`, + ); + + expect(result).toBe("ghj"); +}); -export class OverloadTests { - @Test("overload function1") - public overloadFunction1(): void - { - const result = util.transpileAndExecute( - `function abc(def: number): string; - function abc(def: string): string; - function abc(def: number | string): string { +test("overload method1", () => { + const result = util.transpileAndExecute( + `class myclass { + static abc(def: number): string; + static abc(def: string): string; + static abc(def: number | string): string { if (typeof def == "number") { return "jkl" + (def * 3); } else { return def; } } - return abc(3);`); + } + return myclass.abc(3);`, + ); - Expect(result).toBe("jkl9"); - } + expect(result).toBe("jkl9"); +}); - @Test("overload function2") - public overloadFunction2(): void - { - const result = util.transpileAndExecute( - `function abc(def: number): string; - function abc(def: string): string; - function abc(def: number | string): string { +test("overload method2", () => { + const result = util.transpileAndExecute( + `class myclass { + static abc(def: number): string; + static abc(def: string): string; + static abc(def: number | string): string { if (typeof def == "number") { return "jkl" + (def * 3); } else { return def; } } - return abc("ghj");`); + } + return myclass.abc("ghj");`, + ); - Expect(result).toBe("ghj"); - } + expect(result).toBe("ghj"); +}); - @Test("overload method1") - public overloadMethod1(): void - { - const result = util.transpileAndExecute( - `class myclass { - static abc(def: number): string; - static abc(def: string): string; - static abc(def: number | string): string { - if (typeof def == "number") { - return "jkl" + (def * 3); - } else { - return def; - } - } - } - return myclass.abc(3);`); +test("constructor1", () => { + const result = util.transpileAndExecute( + `class myclass { + num: number; + str: string; - Expect(result).toBe("jkl9"); - } - - @Test("overload method2") - public overloadMethod2(): void - { - const result = util.transpileAndExecute( - `class myclass { - static abc(def: number): string; - static abc(def: string): string; - static abc(def: number | string): string { - if (typeof def == "number") { - return "jkl" + (def * 3); - } else { - return def; - } - } - } - return myclass.abc("ghj");`); - - Expect(result).toBe("ghj"); - } - - @Test("constructor1") - public constructor1(): void - { - const result = util.transpileAndExecute( - `class myclass { - num: number; - str: string; - - constructor(def: number); - constructor(def: string); - constructor(def: number | string) { - if (typeof def == "number") { - this.num = def; - } else { - this.str = def; - } + constructor(def: number); + constructor(def: string); + constructor(def: number | string) { + if (typeof def == "number") { + this.num = def; + } else { + this.str = def; } } - const inst = new myclass(3); - return inst.num`); + } + const inst = new myclass(3); + return inst.num`, + ); - Expect(result).toBe(3); - } + expect(result).toBe(3); +}); - @Test("constructor2") - public constructor2(): void - { - const result = util.transpileAndExecute( - `class myclass { - num: number; - str: string; +test("constructor2", () => { + const result = util.transpileAndExecute( + `class myclass { + num: number; + str: string; - constructor(def: number); - constructor(def: string); - constructor(def: number | string) { - if (typeof def == "number") { - this.num = def; - } else { - this.str = def; - } + constructor(def: number); + constructor(def: string); + constructor(def: number | string) { + if (typeof def == "number") { + this.num = def; + } else { + this.str = def; } } - const inst = new myclass("ghj"); - return inst.str`); + } + const inst = new myclass("ghj"); + return inst.str`, + ); - Expect(result).toBe("ghj"); - } -} + expect(result).toBe("ghj"); +}); diff --git a/test/unit/require.spec.ts b/test/unit/require.spec.ts index 27c5a7432..010c89abf 100644 --- a/test/unit/require.spec.ts +++ b/test/unit/require.spec.ts @@ -1,48 +1,115 @@ -import { Expect, FocusTest, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; import * as path from "path"; import { CompilerOptions } from "../../src/CompilerOptions"; -export class RequireTests { - - @TestCase("file.ts", "./folder/Module", "folder.Module", { rootDir: "." }, false) - @TestCase("file.ts", "./folder/Module", "folder.Module", { rootDir: "./" }, false) - @TestCase("src/file.ts", "./folder/Module", "src.folder.Module", { rootDir: "." }, false) - @TestCase("file.ts", "folder/Module", "folder.Module", { rootDir: ".", baseUrl: "." }, false) - @TestCase("file.ts", "folder/Module", "folder.Module", { rootDir: "./", baseUrl: "." }, false) - @TestCase("src/file.ts", "./folder/Module", "folder.Module", { rootDir: "src" }, false) - @TestCase("src/file.ts", "./folder/Module", "folder.Module", { rootDir: "./src" }, false) - @TestCase("file.ts", "../Module", "", { rootDir: "./src" }, true) - @TestCase("src/dir/file.ts", "../Module", "Module", { rootDir: "./src" }, false) - @TestCase("src/dir/dir/file.ts", "../../dir/Module", "dir.Module", { rootDir: "./src" }, false) - @Test("require paths root from --baseUrl or --rootDir") - public testRequirePath( - filePath: string, - usedPath: string, - expectedPath: string, - options: CompilerOptions, - throwsError: boolean): void { +test.each([ + { + filePath: "file.ts", + usedPath: "./folder/Module", + expectedPath: "folder.Module", + options: { rootDir: "." }, + throwsError: false, + }, + { + filePath: "file.ts", + usedPath: "./folder/Module", + expectedPath: "folder.Module", + options: { rootDir: "./" }, + throwsError: false, + }, + { + filePath: "src/file.ts", + usedPath: "./folder/Module", + expectedPath: "src.folder.Module", + options: { rootDir: "." }, + throwsError: false, + }, + { + filePath: "file.ts", + usedPath: "folder/Module", + expectedPath: "folder.Module", + options: { rootDir: ".", baseUrl: "." }, + throwsError: false, + }, + { + filePath: "file.ts", + usedPath: "folder/Module", + expectedPath: "folder.Module", + options: { rootDir: "./", baseUrl: "." }, + throwsError: false, + }, + { + filePath: "src/file.ts", + usedPath: "./folder/Module", + expectedPath: "folder.Module", + options: { rootDir: "src" }, + throwsError: false, + }, + { + filePath: "src/file.ts", + usedPath: "./folder/Module", + expectedPath: "folder.Module", + options: { rootDir: "./src" }, + throwsError: false, + }, + { + filePath: "file.ts", + usedPath: "../Module", + expectedPath: "", + options: { rootDir: "./src" }, + throwsError: true, + }, + { + filePath: "src/dir/file.ts", + usedPath: "../Module", + expectedPath: "Module", + options: { rootDir: "./src" }, + throwsError: false, + }, + { + filePath: "src/dir/dir/file.ts", + usedPath: "../../dir/Module", + expectedPath: "dir.Module", + options: { rootDir: "./src" }, + throwsError: false, + }, +])( + "require paths root from --baseUrl or --rootDir (%p)", + ({ filePath, usedPath, expectedPath, options, throwsError }) => { if (throwsError) { - Expect(() => util.transpileString(`import * from "${usedPath}";`, options, true, filePath)).toThrow(); + expect(() => + util.transpileString(`import * from "${usedPath}";`, options, true, filePath), + ).toThrow(); } else { - const lua = util.transpileString(`import * from "${usedPath}";`, options, true, filePath); + const lua = util.transpileString( + `import * from "${usedPath}";`, + options, + true, + filePath, + ); const regex = /require\("(.*?)"\)/; const match = regex.exec(lua); - Expect(match[1]).toBe(expectedPath); + expect(match[1]).toBe(expectedPath); } - } + }, +); - @TestCase("", "src.fake") - @TestCase("/** @noResolution */", "fake") - @Test("noResolution on ambient modules causes no path alterations") - public testRequireModule(comment: string, expectedPath: string): void { - const lua = util.transpileString({ - "src/file.ts": `import * as fake from "fake";`, - "module.d.ts": `${comment} declare module "fake" {}`, - }, undefined, true, "src/file.ts"); +test.each([ + { comment: "", expectedPath: "src.fake" }, + { comment: "/** @noResolution */", expectedPath: "fake" }, +])( + "noResolution on ambient modules causes no path alterations (%p)", + ({ comment, expectedPath }) => { + const lua = util.transpileString( + { + "src/file.ts": `import * as fake from "fake";`, + "module.d.ts": `${comment} declare module "fake" {}`, + }, + undefined, + true, + "src/file.ts", + ); const regex = /require\("(.*?)"\)/; - Expect(regex.exec(lua)[1]).toBe(expectedPath); - } - -} \ No newline at end of file + expect(regex.exec(lua)[1]).toBe(expectedPath); + }, +); diff --git a/test/unit/spreadElement.spec.ts b/test/unit/spreadElement.spec.ts index 35249ce15..02b164ed1 100644 --- a/test/unit/spreadElement.spec.ts +++ b/test/unit/spreadElement.spec.ts @@ -1,49 +1,37 @@ -import { Expect, Test, TestCase } from "alsatian"; - import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; -import * as util from "../src/util"; - -export class SpreadElementTest { +import * as util from "../util"; - @TestCase([]) - @TestCase([1, 2, 3]) - @TestCase([1, "test", 3]) - @Test("Spread Element Push") - public spreadElementPush(inp: any[]): void - { - const result = util.transpileAndExecute(`return JSONStringify([].push(...${JSON.stringify(inp)}));`); - Expect(result).toBe([].push(...inp)); - } +test.each([{ inp: [] }, { inp: [1, 2, 3] }, { inp: [1, "test", 3] }])( + "Spread Element Push (%p)", + ({ inp }) => { + const result = util.transpileAndExecute( + `return JSONStringify([].push(...${JSON.stringify(inp)}));`, + ); + expect(result).toBe([].push(...inp)); + }, +); - @Test("Spread Element Lua 5.1") - public spreadElement51(): void - { - // Cant test functional because our VM doesn't run on 5.1 - const lua = util.transpileString(`[].push(...${JSON.stringify([1, 2, 3])});`, {luaTarget: LuaTarget.Lua51}); - Expect(lua).toBe("__TS__ArrayPush({}, unpack({1, 2, 3}));"); - } +test("Spread Element Lua 5.1", () => { + // Cant test functional because our VM doesn't run on 5.1 + const options = { luaTarget: LuaTarget.Lua51, luaLibImport: LuaLibImportKind.None }; + const lua = util.transpileString(`[].push(...${JSON.stringify([1, 2, 3])});`, options); + expect(lua).toBe("__TS__ArrayPush({}, unpack({1, 2, 3}));"); +}); - @Test("Spread Element Lua 5.2") - public spreadElement52(): void - { - const options = {luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None}; - const lua = util.transpileString(`[...[0, 1, 2]]`, options); - Expect(lua).toBe("{table.unpack({0, 1, 2})};"); - } +test("Spread Element Lua 5.2", () => { + const options = { luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None }; + const lua = util.transpileString(`[...[0, 1, 2]]`, options); + expect(lua).toBe("{table.unpack({0, 1, 2})};"); +}); - @Test("Spread Element Lua 5.3") - public spreadElement53(): void - { - const options = {luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None}; - const lua = util.transpileString(`[...[0, 1, 2]]`, options); - Expect(lua).toBe("{table.unpack({0, 1, 2})};"); - } +test("Spread Element Lua 5.3", () => { + const options = { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None }; + const lua = util.transpileString(`[...[0, 1, 2]]`, options); + expect(lua).toBe("{table.unpack({0, 1, 2})};"); +}); - @Test("Spread Element Lua JIT") - public spreadElementJIT(): void - { - const options = {luaTarget: "JiT" as LuaTarget, luaLibImport: LuaLibImportKind.None}; - const lua = util.transpileString(`[...[0, 1, 2]]`, options); - Expect(lua).toBe("{unpack({0, 1, 2})};"); - } -} +test("Spread Element Lua JIT", () => { + const options = { luaTarget: "JiT" as LuaTarget, luaLibImport: LuaLibImportKind.None }; + const lua = util.transpileString(`[...[0, 1, 2]]`, options); + expect(lua).toBe("{unpack({0, 1, 2})};"); +}); diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index d82fb0b9c..2e52f17d9 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -1,340 +1,254 @@ -import { Expect, Test, TestCase } from "alsatian"; import { TranspileError } from "../../src/TranspileError"; -import * as util from "../src/util"; - -export class StringTests -{ - @Test("Unsuported string function") - public stringUnsuportedFunction(): void { - // Assert - Expect(() => { - util.transpileString( - `return "test".testThisIsNoMember()` - ); - }).toThrowError(TranspileError, "Unsupported property on string: testThisIsNoMember"); - } - - @Test("Suported lua string function") - public stringSuportedLuaFunction(): void { - Expect(util.transpileAndExecute( - `return "test".upper()`, - undefined, - undefined, - `interface String { upper(): string; }` - ) - ).toBe("TEST"); - } - - @TestCase([]) - @TestCase([65]) - @TestCase([65, 66]) - @TestCase([65, 66, 67]) - @Test("String.fromCharCode") - public stringFromCharcode(inp: number[]): void - { - const result = util.transpileAndExecute( - `return String.fromCharCode(${inp.toString()})` - ); - - // Assert - Expect(result).toBe(String.fromCharCode(...inp)); - } - - @TestCase(12, 23, 43) - @TestCase("test", "hello", "bye") - @TestCase("test", 42, "bye") - @TestCase("test", 42, 12) - @Test("Template Strings") - public templateStrings(a: any, b: any, c: any): void { - // Transpile - const a1 = typeof(a) === "string" ? "'" + a + "'" : a; - const b1 = typeof(b) === "string" ? "'" + b + "'" : b; - const c1 = typeof(c) === "string" ? "'" + c + "'" : c; - - const result = util.transpileAndExecute( - "let a = " + a1 + "; let b = " + b1 + "; let c = " + c1 + "; return `${a} ${b} test ${c}`;" - ); - - // Assert - Expect(result).toBe(`${a} ${b} test ${c}`); - } - - @TestCase("hello test", "", "") - @TestCase("hello test", " ", "") - @TestCase("hello test", "hello", "") - @TestCase("hello test", "test", "") - @TestCase("hello test", "test", "world") - @Test("string.replace") - public replace(inp: string, searchValue: string, replaceValue: string): void - { - const result = util.transpileAndExecute( - `return "${inp}".replace("${searchValue}", "${replaceValue}");` - ); - - // Assert - Expect(result).toBe(inp.replace(searchValue, replaceValue)); - } - - @TestCase(["", ""], "") - @TestCase(["hello", "test"], "hellotest") - @TestCase(["hello", "test", "bye"], "hellotestbye") - @TestCase(["hello", 42], "hello42") - @TestCase([42, "hello"], "42hello") - @Test("string.concat[+]") - public concat(inp: any[], expected: string): void { - const concatStr = inp.map(elem => typeof(elem) === "string" ? `"${elem}"` : elem).join(" + "); - - // Transpile/Execute - const result = util.transpileAndExecute( - `return ${concatStr}` - ); - - // Assert - Expect(result).toBe(expected); - } - @TestCase("", ["", ""]) - @TestCase("hello", ["test"]) - @TestCase("hello", []) - @TestCase("hello", ["test", "bye"]) - @Test("string.concatFct") - public concatFct(str: string, param: string[]): void { - const paramStr = param.map(elem => `"${elem}"`).join(", "); - const result = util.transpileAndExecute( - `return "${str}".concat(${paramStr})` - ); - // Assert - Expect(result).toBe(str.concat(...param)); - } - @TestCase("hello test", "") - @TestCase("hello test", "t") - @TestCase("hello test", "h") - @TestCase("hello test", "invalid") - @Test("string.indexOf") - public indexOf(inp: string, searchValue: string): void - { - const result = util.transpileAndExecute(`return "${inp}".indexOf("${searchValue}")`); - - // Assert - Expect(result).toBe(inp.indexOf(searchValue)); - } - - @TestCase("hello test", "t", 5) - @TestCase("hello test", "t", 6) - @TestCase("hello test", "t", 7) - @TestCase("hello test", "h", 4) - @Test("string.indexOf with offset") - public indexOfOffset(inp: string, searchValue: string, offset: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".indexOf("${searchValue}", ${offset})` - ); - - // Assert - Expect(result).toBe(inp.indexOf(searchValue, offset)); - } - - @TestCase("hello test", "t", 4, 3) - @TestCase("hello test", "h", 3, 4) - @Test("string.indexOf with offset expression") - public indexOfOffsetWithExpression(inp: string, searchValue: string, x: number, y: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".indexOf("${searchValue}", 2 > 1 && ${x} || ${y})` - ); - - // Assert - Expect(result).toBe(inp.indexOf(searchValue, x)); - } - @TestCase("hello test") - @TestCase("hello test", 0) - @TestCase("hello test", 1) - @TestCase("hello test", 1, 2) - @TestCase("hello test", 1, 5) - @Test("string.slice") - public slice(inp: string, start?: number, end?: number): void - { - // Transpile/Execute - const paramStr = start? (end ? `${start}, ${end}` : `${start}`):''; - const result = util.transpileAndExecute( - `return "${inp}".slice(${paramStr})` - ); - - // Assert - Expect(result).toBe(inp.slice(start, end)); - } - @TestCase("hello test", 0) - @TestCase("hello test", 1) - @TestCase("hello test", 1, 2) - @TestCase("hello test", 1, 5) - @Test("string.substring") - public substring(inp: string, start: number, end?: number): void - { - // Transpile/Execute - const paramStr = end ? `${start}, ${end}` : `${start}`; - const result = util.transpileAndExecute( - `return "${inp}".substring(${paramStr})` - ); - - // Assert - Expect(result).toBe(inp.substring(start, end)); - } - - @TestCase("hello test", 1, 0) - @TestCase("hello test", 3, 0, 5) - @Test("string.substring with expression") - public substringWithExpression(inp: string, start: number, ignored: number, end?: number): void - { - // Transpile/Execute - const paramStr = `2 > 1 && ${start} || ${ignored}` + (end ? `, ${end}` : ""); - const result = util.transpileAndExecute( - `return "${inp}".substring(${paramStr})` - ); - - // Assert - Expect(result).toBe(inp.substring(start, end)); - } - - @TestCase("hello test", 0) - @TestCase("hello test", 1) - @TestCase("hello test", 1, 2) - @TestCase("hello test", 1, 5) - @Test("string.substr") - public substr(inp: string, start: number, end?: number): void - { - // Transpile/Execute - const paramStr = end ? `${start}, ${end}` : `${start}`; - const result = util.transpileAndExecute( - `return "${inp}".substr(${paramStr})` - ); - - // Assert - Expect(result).toBe(inp.substr(start, end)); - } - - @TestCase("hello test", 1, 0) - @TestCase("hello test", 3, 0, 2) - @Test("string.substr with expression") - public substrWithExpression(inp: string, start: number, ignored: number, end?: number): void - { - // Transpile/Execute - const paramStr = `2 > 1 && ${start} || ${ignored}` + (end ? `, ${end}` : ""); - const result = util.transpileAndExecute( - `return "${inp}".substr(${paramStr})` - ); - - // Assert - Expect(result).toBe(inp.substr(start, end)); - } - - @TestCase("", 0) - @TestCase("h", 1) - @TestCase("hello", 5) - @Test("string.length") - public length(inp: string, expected: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".length` - ); - - // Assert - Expect(result).toBe(inp.length); - } - - @TestCase("hello TEST") - @Test("string.toLowerCase") - public toLowerCase(inp: string): void - { - const result = util.transpileAndExecute( - `return "${inp}".toLowerCase()` - ); - - // Assert - Expect(result).toBe(inp.toLowerCase()); - } - - @TestCase("hello test") - @Test("string.toUpperCase") - public toUpperCase(inp: string): void - { - const result = util.transpileAndExecute( - `return "${inp}".toUpperCase()` - ); - - // Assert - Expect(result).toBe(inp.toUpperCase()); - } - - @TestCase("hello test", "") - @TestCase("hello test", " ") - @TestCase("hello test", "h") - @TestCase("hello test", "t") - @TestCase("hello test", "l") - @TestCase("hello test", "invalid") - @TestCase("hello test", "hello test") - @Test("string.split") - public split(inp: string, separator: string): void - { - const result = util.transpileAndExecute( - `return JSONStringify("${inp}".split("${separator}"))` - ); - - // Assert - Expect(result).toBe(JSON.stringify(inp.split(separator))); - } - - @TestCase("hello test", 1) - @TestCase("hello test", 2) - @TestCase("hello test", 3) - @TestCase("hello test", 99) - @Test("string.charAt") - public charAt(inp: string, index: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".charAt(${index})` - ); - - // Assert - Expect(result).toBe(inp.charAt(index)); - } - - @TestCase("hello test", 1) - @TestCase("hello test", 2) - @TestCase("hello test", 3) - @Test("string.charCodeAt") - public charCodeAt(inp: string, index: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".charCodeAt(${index})` - ); - - // Assert - Expect(result).toBe(inp.charCodeAt(index)); - } - - @TestCase("hello test", 1, 0) - @TestCase("hello test", 1, 2) - @TestCase("hello test", 3, 2) - @TestCase("hello test", 3, 99) - @Test("string.charAt with expression") - public charAtWithExpression(inp: string, index: number, ignored: number): void - { - const result = util.transpileAndExecute( - `return "${inp}".charAt(2 > 1 && ${index} || ${ignored})` - ); - - // Assert - Expect(result).toBe(inp.charAt(index)); - } - - @TestCase("abcd", 3) - @TestCase("abcde", 3) - @TestCase("abcde", 0) - @TestCase("a", 0) - @Test("string index") - public index(input: string, index: number): void - { - const result = util.transpileAndExecute(`return "${input}"[${index}];`); - - Expect(result).toBe(input[index]); - } -} +import * as util from "../util"; + +test("Unsuported string function", () => { + expect(() => { + util.transpileString(`return "test".testThisIsNoMember()`); + }).toThrowExactError(new TranspileError("Unsupported property on string: testThisIsNoMember")); +}); + +test("Suported lua string function", () => { + expect( + util.transpileAndExecute( + `return "test".upper()`, + undefined, + undefined, + `interface String { upper(): string; }`, + ), + ).toBe("TEST"); +}); + +test.each([{ inp: [] }, { inp: [65] }, { inp: [65, 66] }, { inp: [65, 66, 67] }])( + "String.fromCharCode (%p)", + ({ inp }) => { + const result = util.transpileAndExecute(`return String.fromCharCode(${inp.toString()})`); + + expect(result).toBe(String.fromCharCode(...inp)); + }, +); + +test.each([ + { a: 12, b: 23, c: 43 }, + { a: "test", b: "hello", c: "bye" }, + { a: "test", b: 42, c: "bye" }, + { a: "test", b: 42, c: 12 }, +])("Template Strings (%p)", ({ a, b, c }) => { + const a1 = typeof a === "string" ? "'" + a + "'" : a; + const b1 = typeof b === "string" ? "'" + b + "'" : b; + const c1 = typeof c === "string" ? "'" + c + "'" : c; + + const result = util.transpileAndExecute( + "let a = " + a1 + "; let b = " + b1 + "; let c = " + c1 + "; return `${a} ${b} test ${c}`;", + ); + + expect(result).toBe(`${a} ${b} test ${c}`); +}); + +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" }, +])("string.replace (%p)", ({ inp, searchValue, replaceValue }) => { + const result = util.transpileAndExecute( + `return "${inp}".replace("${searchValue}", "${replaceValue}");`, + ); + + expect(result).toBe(inp.replace(searchValue, replaceValue)); +}); + +test.each([ + { inp: ["", ""], expected: "" }, + { inp: ["hello", "test"], expected: "hellotest" }, + { inp: ["hello", "test", "bye"], expected: "hellotestbye" }, + { inp: ["hello", 42], expected: "hello42" }, + { inp: [42, "hello"], expected: "42hello" }, +])("string.concat[+] (%p)", ({ inp, expected }) => { + const concatStr = inp.map(elem => (typeof elem === "string" ? `"${elem}"` : elem)).join(" + "); + + const result = util.transpileAndExecute(`return ${concatStr}`); + + expect(result).toBe(expected); +}); + +test.each([ + { str: "", param: ["", ""] }, + { str: "hello", param: ["test"] }, + { str: "hello", param: [] }, + { str: "hello", param: ["test", "bye"] }, +])("string.concatFct (%p)", ({ str, param }) => { + const paramStr = param.map(elem => `"${elem}"`).join(", "); + const result = util.transpileAndExecute(`return "${str}".concat(${paramStr})`); + expect(result).toBe(str.concat(...param)); +}); + +test.each([ + { inp: "hello test", searchValue: "" }, + { inp: "hello test", searchValue: "t" }, + { inp: "hello test", searchValue: "h" }, + { inp: "hello test", searchValue: "invalid" }, +])("string.indexOf (%p)", ({ inp, searchValue }) => { + const result = util.transpileAndExecute(`return "${inp}".indexOf("${searchValue}")`); + + expect(result).toBe(inp.indexOf(searchValue)); +}); + +test.each([ + { inp: "hello test", searchValue: "t", offset: 5 }, + { inp: "hello test", searchValue: "t", offset: 6 }, + { inp: "hello test", searchValue: "t", offset: 7 }, + { inp: "hello test", searchValue: "h", offset: 4 }, +])("string.indexOf with offset (%p)", ({ inp, searchValue, offset }) => { + const result = util.transpileAndExecute(`return "${inp}".indexOf("${searchValue}", ${offset})`); + + expect(result).toBe(inp.indexOf(searchValue, offset)); +}); + +test.each([ + { inp: "hello test", searchValue: "t", x: 4, y: 3 }, + { inp: "hello test", searchValue: "h", x: 3, y: 4 }, +])("string.indexOf with offset expression (%p)", ({ inp, searchValue, x, y }) => { + const result = util.transpileAndExecute( + `return "${inp}".indexOf("${searchValue}", 2 > 1 && ${x} || ${y})`, + ); + + expect(result).toBe(inp.indexOf(searchValue, x)); +}); + +test.each([ + { inp: "hello test" }, + { inp: "hello test", start: 0 }, + { inp: "hello test", start: 1 }, + { inp: "hello test", start: 1, end: 2 }, + { inp: "hello test", start: 1, end: 5 }, +])("string.slice (%p)", ({ inp, start, end }) => { + const paramStr = start ? (end ? `${start}, ${end}` : `${start}`) : ""; + const result = util.transpileAndExecute(`return "${inp}".slice(${paramStr})`); + + expect(result).toBe(inp.slice(start, end)); +}); + +test.each([ + { inp: "hello test", start: 0 }, + { inp: "hello test", start: 1 }, + { inp: "hello test", start: 1, end: 2 }, + { inp: "hello test", start: 1, end: 5 }, +])("string.substring (%p)", ({ inp, start, end }) => { + const paramStr = end ? `${start}, ${end}` : `${start}`; + const result = util.transpileAndExecute(`return "${inp}".substring(${paramStr})`); + + expect(result).toBe(inp.substring(start, end)); +}); + +test.each([ + { inp: "hello test", start: 1, ignored: 0 }, + { inp: "hello test", start: 3, ignored: 0, end: 5 }, +])("string.substring with expression (%p)", ({ inp, start, ignored, end }) => { + const paramStr = `2 > 1 && ${start} || ${ignored}` + (end ? `, ${end}` : ""); + const result = util.transpileAndExecute(`return "${inp}".substring(${paramStr})`); + + expect(result).toBe(inp.substring(start, end)); +}); + +test.each([ + { inp: "hello test", start: 0 }, + { inp: "hello test", start: 1 }, + { inp: "hello test", start: 1, end: 2 }, + { inp: "hello test", start: 1, end: 5 }, +])("string.substr (%p)", ({ inp, start, end }) => { + const paramStr = end ? `${start}, ${end}` : `${start}`; + const result = util.transpileAndExecute(`return "${inp}".substr(${paramStr})`); + + expect(result).toBe(inp.substr(start, end)); +}); + +test.each([ + { inp: "hello test", start: 1, ignored: 0 }, + { inp: "hello test", start: 3, ignored: 0, end: 2 }, +])("string.substr with expression (%p)", ({ inp, start, ignored, end }) => { + const paramStr = `2 > 1 && ${start} || ${ignored}` + (end ? `, ${end}` : ""); + const result = util.transpileAndExecute(`return "${inp}".substr(${paramStr})`); + + expect(result).toBe(inp.substr(start, end)); +}); + +test.each([{ inp: "", expected: 0 }, { inp: "h", expected: 1 }, { inp: "hello", expected: 5 }])( + "string.length (%p)", + ({ inp, expected }) => { + const result = util.transpileAndExecute(`return "${inp}".length`); + + expect(result).toBe(inp.length); + }, +); + +test.each(["hello TEST"])("string.toLowerCase (%p)", inp => { + const result = util.transpileAndExecute(`return "${inp}".toLowerCase()`); + + expect(result).toBe(inp.toLowerCase()); +}); + +test.each(["hello test"])("string.toUpperCase (%p)", inp => { + const result = util.transpileAndExecute(`return "${inp}".toUpperCase()`); + + expect(result).toBe(inp.toUpperCase()); +}); + +test.each([ + { inp: "hello test", separator: "" }, + { inp: "hello test", separator: " " }, + { inp: "hello test", separator: "h" }, + { inp: "hello test", separator: "t" }, + { inp: "hello test", separator: "l" }, + { inp: "hello test", separator: "invalid" }, + { inp: "hello test", separator: "hello test" }, +])("string.split (%p)", ({ inp, separator }) => { + const result = util.transpileAndExecute(`return JSONStringify("${inp}".split("${separator}"))`); + + expect(result).toBe(JSON.stringify(inp.split(separator))); +}); + +test.each([ + { inp: "hello test", index: 1 }, + { inp: "hello test", index: 2 }, + { inp: "hello test", index: 3 }, + { inp: "hello test", index: 99 }, +])("string.charAt (%p)", ({ inp, index }) => { + const result = util.transpileAndExecute(`return "${inp}".charAt(${index})`); + + expect(result).toBe(inp.charAt(index)); +}); + +test.each([ + { inp: "hello test", index: 1 }, + { inp: "hello test", index: 2 }, + { inp: "hello test", index: 3 }, +])("string.charCodeAt (%p)", ({ inp, index }) => { + const result = util.transpileAndExecute(`return "${inp}".charCodeAt(${index})`); + + expect(result).toBe(inp.charCodeAt(index)); +}); + +test.each([ + { inp: "hello test", index: 1, ignored: 0 }, + { inp: "hello test", index: 1, ignored: 2 }, + { inp: "hello test", index: 3, ignored: 2 }, + { inp: "hello test", index: 3, ignored: 99 }, +])("string.charAt with expression (%p)", ({ inp, index, ignored }) => { + const result = util.transpileAndExecute( + `return "${inp}".charAt(2 > 1 && ${index} || ${ignored})`, + ); + + expect(result).toBe(inp.charAt(index)); +}); + +test.each([ + { input: "abcd", index: 3 }, + { input: "abcde", index: 3 }, + { input: "abcde", index: 0 }, + { input: "a", index: 0 }, +])("string index (%p)", ({ input, index }) => { + const result = util.transpileAndExecute(`return "${input}"[${index}];`); + + expect(result).toBe(input[index]); +}); diff --git a/test/unit/tshelper.spec.ts b/test/unit/tshelper.spec.ts index 408443d8e..85b6e98e0 100644 --- a/test/unit/tshelper.spec.ts +++ b/test/unit/tshelper.spec.ts @@ -1,8 +1,7 @@ -import { Expect, Test, TestCase } from "alsatian"; import { TSHelper as tsHelper } from "../../src/TSHelper"; import * as ts from "typescript"; -import * as util from "../src/util"; +import * as util from "../util"; import { DecoratorKind } from "../../src/Decorator"; @@ -12,149 +11,143 @@ enum TestEnum { testC = 4, } -export class TSHelperTests { - - @TestCase(TestEnum.testA, "testA") - @TestCase(-1, "unknown") - @TestCase(TestEnum.testA | TestEnum.testB, "unknown") - @Test("EnumName") - public testEnumName(inp, expected): void { - const result = tsHelper.enumName(inp, TestEnum); - - Expect(result).toEqual(expected); - } - - @TestCase(TestEnum.testA, ["testA"]) - @TestCase(-1, []) - @TestCase(TestEnum.testA | TestEnum.testC, ["testA", "testC"]) - @TestCase(TestEnum.testA | TestEnum.testB | TestEnum.testC, ["testA", "testB", "testC"]) - @Test("EnumNames") - public testEnumNames(inp, expected): void { - const result = tsHelper.enumNames(inp, TestEnum); - - Expect(result).toEqual(expected); - } - - @Test("IsFileModuleNull") - public isFileModuleNull(): void { - Expect(tsHelper.isFileModule(undefined)).toEqual(false); - } - - @Test("GetCustomDecorators single") - public GetCustomDecoratorsSingle(): void { - const source = `/** @compileMembersOnly */ - enum TestEnum { - val1 = 0, - val2 = 2, - val3, - val4 = "bye", - } - - const a = TestEnum.val1;`; - - const [sourceFile, typeChecker] = util.parseTypeScript(source); - const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); - const enumType = typeChecker.getTypeAtLocation(identifier); - - const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); - - Expect(decorators.size).toBe(1); - Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); - } - - @Test("GetCustomDecorators multiple") - public GetCustomDecoratorsMultiple(): void { - const source = `/** @compileMembersOnly - * @Phantom */ - enum TestEnum { - val1 = 0, - val2 = 2, - val3, - val4 = "bye", - } - - const a = TestEnum.val1;`; - - const [sourceFile, typeChecker] = util.parseTypeScript(source); - const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); - const enumType = typeChecker.getTypeAtLocation(identifier); - - const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); - - Expect(decorators.size).toBe(2); - Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); - Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); - } - - @Test("GetCustomDecorators single jsdoc") - public GetCustomDecoratorsSingleJSDoc(): void { - const source = `/** @compileMembersOnly */ - enum TestEnum { - val1 = 0, - val2 = 2, - val3, - val4 = "bye", - } - - const a = TestEnum.val1;`; - - const [sourceFile, typeChecker] = util.parseTypeScript(source); - const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); - const enumType = typeChecker.getTypeAtLocation(identifier); - - const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); - - Expect(decorators.size).toBe(1); - Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); - } - - @Test("GetCustomDecorators multiple jsdoc") - public GetCustomDecoratorsMultipleJSDoc(): void { - const source = `/** @phantom - * @CompileMembersOnly */ - enum TestEnum { - val1 = 0, - val2 = 2, - val3, - val4 = "bye", - } - - const a = TestEnum.val1;`; - - const [sourceFile, typeChecker] = util.parseTypeScript(source); - const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); - const enumType = typeChecker.getTypeAtLocation(identifier); - - const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); - - Expect(decorators.size).toBe(2); - Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); - Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); - } - - @Test("GetCustomDecorators multiple default jsdoc") - public GetCustomDecoratorsMultipleDefaultJSDoc(): void { - const source = `/** - * @description abc - * @phantom - * @compileMembersOnly */ - enum TestEnum { - val1 = 0, - val2 = 2, - val3, - val4 = "bye", - } - - const a = TestEnum.val1;`; - - const [sourceFile, typeChecker] = util.parseTypeScript(source); - const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); - const enumType = typeChecker.getTypeAtLocation(identifier); - - const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); - - Expect(decorators.size).toBe(2); - Expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); - Expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); - } -} +test.each([ + { inp: TestEnum.testA, expected: "testA" }, + { inp: -1, expected: "unknown" }, + { inp: TestEnum.testA | TestEnum.testB, expected: "unknown" }, +])("EnumName (%p)", ({ inp, expected }) => { + const result = tsHelper.enumName(inp, TestEnum); + + expect(result).toEqual(expected); +}); + +test.each([ + { inp: TestEnum.testA, expected: ["testA"] }, + { inp: -1, expected: [] }, + { inp: TestEnum.testA | TestEnum.testC, expected: ["testA", "testC"] }, + { + inp: TestEnum.testA | TestEnum.testB | TestEnum.testC, + expected: ["testA", "testB", "testC"], + }, +])("EnumNames (%p)", ({ inp, expected }) => { + const result = tsHelper.enumNames(inp, TestEnum); + + expect(result).toEqual(expected); +}); + +test("IsFileModuleNull", () => { + expect(tsHelper.isFileModule(undefined)).toEqual(false); +}); + +test("GetCustomDecorators single", () => { + const source = `/** @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + expect(decorators.size).toBe(1); + expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); +}); + +test("GetCustomDecorators multiple", () => { + const source = `/** @compileMembersOnly + * @Phantom */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + expect(decorators.size).toBe(2); + expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); + expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); +}); + +test("GetCustomDecorators single jsdoc", () => { + const source = `/** @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + expect(decorators.size).toBe(1); + expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); +}); + +test("GetCustomDecorators multiple jsdoc", () => { + const source = `/** @phantom + * @CompileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + expect(decorators.size).toBe(2); + expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); + expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); +}); + +test("GetCustomDecorators multiple default jsdoc", () => { + const source = `/** + * @description abc + * @phantom + * @compileMembersOnly */ + enum TestEnum { + val1 = 0, + val2 = 2, + val3, + val4 = "bye", + } + + const a = TestEnum.val1;`; + + const [sourceFile, typeChecker] = util.parseTypeScript(source); + const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); + const enumType = typeChecker.getTypeAtLocation(identifier); + + const decorators = tsHelper.getCustomDecorators(enumType, typeChecker); + + expect(decorators.size).toBe(2); + expect(decorators.has(DecoratorKind.Phantom)).toBeTruthy(); + expect(decorators.has(DecoratorKind.CompileMembersOnly)).toBeTruthy(); +}); diff --git a/test/unit/tuples.spec.ts b/test/unit/tuples.spec.ts index 796836c29..7016e44fb 100644 --- a/test/unit/tuples.spec.ts +++ b/test/unit/tuples.spec.ts @@ -1,257 +1,208 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; - -export class TupleTests { - @Test("Tuple loop") - public tupleLoop(): void - { - const result = util.transpileAndExecute( - `const tuple: [number, number, number] = [3,5,1]; - let count = 0; - for (const value of tuple) { count += value; } - return count;` - ); - - // Assert - Expect(result).toBe(9); - } - - @Test("Tuple foreach") - public tupleForEach(): void - { - const result = util.transpileAndExecute( - `const tuple: [number, number, number] = [3,5,1]; - let count = 0; - tuple.forEach(v => count += v); - return count;` - ); - - // Assert - Expect(result).toBe(9); - } - - @Test("Tuple access") - public tupleAccess(): void - { - const result = util.transpileAndExecute( - `const tuple: [number, number, number] = [3,5,1]; - return tuple[1];` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("Tuple union access") - public tupleUnionAccess(): void - { - const result = util.transpileAndExecute( - `function makeTuple(): [number, number, number] | [string, string, string] { return [3,5,1]; } - const tuple = makeTuple(); - return tuple[1];` - ); - Expect(result).toBe(5); - } - - @Test("Tuple intersection access") - public tupleIntersectionAccess(): void - { - const result = util.transpileAndExecute( - `type I = [number, number, number] & {foo: string}; - function makeTuple(): I { - let t = [3,5,1]; - (t as I).foo = "bar"; - return (t as I); - } - const tuple = makeTuple(); - return tuple[1];` - ); - Expect(result).toBe(5); - } - - @Test("Tuple Destruct") - public tupleDestruct(): void - { - const result = util.transpileAndExecute( - `function tuple(): [number, number, number] { return [3,5,1]; } - const [a,b,c] = tuple(); - return b;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("Tuple length") - public tupleLength(): void - { - const result = util.transpileAndExecute( - `const tuple: [number, number, number] = [3,5,1]; - return tuple.length;` - ); - - // Assert - Expect(result).toBe(3); - } - - @Test("Tuple Return Access") - public tupleReturnAccess(): void - { - const result = util.transpileAndExecute( - `/** @tupleReturn */ - function tuple(): [number, number, number] { return [3,5,1]; } - return tuple()[2];` - ); - - // Assert - Expect(result).toBe(1); - } - - @Test("Tuple Return Destruct Declaration") - public tupleReturnDestructDeclaration(): void - { - const result = util.transpileAndExecute( - `/** @tupleReturn */ - function tuple(): [number, number, number] { return [3,5,1]; } - const [a,b,c] = tuple(); - return b;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("Tuple Return Destruct Assignment") - public tupleReturnDestructAssignment(): void - { - const result = util.transpileAndExecute( - `/** @tupleReturn */ - function tuple(): [number, number] { return [3,6]; } - let [a,b] = [1,2]; - [b,a] = tuple(); - return a - b;` - ); - - // Assert - Expect(result).toBe(3); - } - - @Test("Tuple Static Method Return Destruct") - public tupleStaticMethodReturnDestruct(): void - { - const result = util.transpileAndExecute( - `class Test { - /** @tupleReturn */ - static tuple(): [number, number, number] { return [3,5,1]; } - } - const [a,b,c] = Test.tuple(); - return b;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("Tuple Non-Static Method Return Destruct") - public tupleMethodNonStaticReturnDestruct(): void - { - const result = util.transpileAndExecute( - `class Test { - /** @tupleReturn */ - tuple(): [number, number, number] { return [3,5,1]; } - } - const t = new Test(); - const [a,b,c] = t.tuple(); - return b;` - ); - - // Assert - Expect(result).toBe(5); - } - - @Test("Tuple Return on Arrow Function") - public tupleReturnOnArrowFunction(): void { - const code = - `const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; - const [a, b] = fn("foo"); - return a + b;`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return Inference") - public tupleReturnInference(): void { - const code = - `/** @tupleReturn */ interface Fn { (s: string): [string, string] } - const fn: Fn = s => [s, "bar"]; +import * as util from "../util"; + +test("Tuple loop", () => { + const result = util.transpileAndExecute( + `const tuple: [number, number, number] = [3,5,1]; + let count = 0; + for (const value of tuple) { count += value; } + return count;`, + ); + + expect(result).toBe(9); +}); + +test("Tuple foreach", () => { + const result = util.transpileAndExecute( + `const tuple: [number, number, number] = [3,5,1]; + let count = 0; + tuple.forEach(v => count += v); + return count;`, + ); + + expect(result).toBe(9); +}); + +test("Tuple access", () => { + const result = util.transpileAndExecute( + `const tuple: [number, number, number] = [3,5,1]; + return tuple[1];`, + ); + + expect(result).toBe(5); +}); + +test("Tuple union access", () => { + const result = util.transpileAndExecute( + `function makeTuple(): [number, number, number] | [string, string, string] { return [3,5,1]; } + const tuple = makeTuple(); + return tuple[1];`, + ); + expect(result).toBe(5); +}); + +test("Tuple intersection access", () => { + const result = util.transpileAndExecute( + `type I = [number, number, number] & {foo: string}; + function makeTuple(): I { + let t = [3,5,1]; + (t as I).foo = "bar"; + return (t as I); + } + const tuple = makeTuple(); + return tuple[1];`, + ); + expect(result).toBe(5); +}); + +test("Tuple Destruct", () => { + const result = util.transpileAndExecute( + `function tuple(): [number, number, number] { return [3,5,1]; } + const [a,b,c] = tuple(); + return b;`, + ); + + expect(result).toBe(5); +}); + +test("Tuple length", () => { + const result = util.transpileAndExecute( + `const tuple: [number, number, number] = [3,5,1]; + return tuple.length;`, + ); + + expect(result).toBe(3); +}); + +test("Tuple Return Access", () => { + const result = util.transpileAndExecute( + `/** @tupleReturn */ + function tuple(): [number, number, number] { return [3,5,1]; } + return tuple()[2];`, + ); + + expect(result).toBe(1); +}); + +test("Tuple Return Destruct Declaration", () => { + const result = util.transpileAndExecute( + `/** @tupleReturn */ + function tuple(): [number, number, number] { return [3,5,1]; } + const [a,b,c] = tuple(); + return b;`, + ); + + expect(result).toBe(5); +}); + +test("Tuple Return Destruct Assignment", () => { + const result = util.transpileAndExecute( + `/** @tupleReturn */ + function tuple(): [number, number] { return [3,6]; } + let [a,b] = [1,2]; + [b,a] = tuple(); + return a - b;`, + ); + + expect(result).toBe(3); +}); + +test("Tuple Static Method Return Destruct", () => { + const result = util.transpileAndExecute( + `class Test { + /** @tupleReturn */ + static tuple(): [number, number, number] { return [3,5,1]; } + } + const [a,b,c] = Test.tuple(); + return b;`, + ); + + expect(result).toBe(5); +}); + +test("Tuple Non-Static Method Return Destruct", () => { + const result = util.transpileAndExecute( + `class Test { + /** @tupleReturn */ + tuple(): [number, number, number] { return [3,5,1]; } + } + const t = new Test(); + const [a,b,c] = t.tuple(); + return b;`, + ); + + expect(result).toBe(5); +}); + +test("Tuple Return on Arrow Function", () => { + const code = `const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; + const [a, b] = fn("foo"); + return a + b;`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); + +test("Tuple Return Inference", () => { + const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + const fn: Fn = s => [s, "bar"]; + const [a, b] = fn("foo"); + return a + b;`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); + +test("Tuple Return Inference as Argument", () => { + const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + function foo(fn: Fn) { const [a, b] = fn("foo"); - return a + b;`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return Inference as Argument") - public tupleReturnInferenceAsArgument(): void { - const code = - `/** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(fn: Fn) { - const [a, b] = fn("foo"); - return a + b; - } - return foo(s => [s, "bar"]);`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return Inference as Elipsis Argument") - public tupleReturnInferenceAsElipsisArgument(): void { - const code = - `/** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(a: number, ...fn: Fn[]) { - const [a, b] = fn[0]("foo"); - return a + b; - } - return foo(7, s => [s, "bar"]);`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return Inference as Elipsis Tuple Argument") - public tupleReturnInferenceAsElipsisTupleArgument(): void { - const code = - `/** @tupleReturn */ interface Fn { (s: string): [string, string] } - function foo(a: number, ...fn: [number, Fn]) { - const [a, b] = fn[1]("foo"); - return a + b; - } - return foo(7, 17, s => [s, "bar"]);`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return in Spread") - public tupleReturnInSpread(): void { - const code = - `/** @tupleReturn */ function foo(): [string, string] { - return ["foo", "bar"]; - } - function bar(a: string, b: string) { - return a + b; - } - return bar(...foo());`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } -} + return a + b; + } + return foo(s => [s, "bar"]);`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); + +test("Tuple Return Inference as Elipsis Argument", () => { + const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + function foo(a: number, ...fn: Fn[]) { + const [a, b] = fn[0]("foo"); + return a + b; + } + return foo(7, s => [s, "bar"]);`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); + +test("Tuple Return Inference as Elipsis Tuple Argument", () => { + const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + function foo(a: number, ...fn: [number, Fn]) { + const [a, b] = fn[1]("foo"); + return a + b; + } + return foo(7, 17, s => [s, "bar"]);`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); + +test("Tuple Return in Spread", () => { + const code = `/** @tupleReturn */ function foo(): [string, string] { + return ["foo", "bar"]; + } + function bar(a: string, b: string) { + return a + b; + } + return bar(...foo());`; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("foobar"); +}); diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 533c0d3d0..0045be9d5 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -1,149 +1,112 @@ -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; +import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; -export class TypeCheckingTests { - @TestCase("0") - @TestCase("30") - @TestCase("30_000") - @TestCase("30.00") - @Test("typeof number") - public typeofNumberTest(inp: string): void - { - const result = util.transpileAndExecute(`return typeof ${inp};`); - - Expect(result).toBe("number"); - } - - @TestCase("\"abc\"") - @TestCase("`abc`") - @Test("typeof string") - public typeofStringTest(inp: string): void - { - const result = util.transpileAndExecute(`return typeof ${inp};`); - - Expect(result).toBe("string"); - } - - @TestCase("false") - @TestCase("true") - @Test("typeof boolean") - public typeofBooleanTest(inp: string): void - { - const result = util.transpileAndExecute(`return typeof ${inp};`); - - Expect(result).toBe("boolean"); - } - - @TestCase("{}") - @TestCase("[]") - @Test("typeof object literal") - public typeofObjectLiteral(inp: string): void - { - const result = util.transpileAndExecute(`return typeof ${inp};`); - - Expect(result).toBe("object"); - } - - @Test("typeof class instance") - public typeofClassInstance(): void - { - const result = util.transpileAndExecute(`class myClass {} let inst = new myClass(); return typeof inst;`); - - Expect(result).toBe("object"); - } - - @Test("typeof function") - public typeofFunction(): void - { - const result = util.transpileAndExecute(`return typeof (() => 3);`); - - Expect(result).toBe("function"); - } - - @TestCase("null") - @TestCase("undefined") - @Test("typeof undefined") - public typeofUndefinedTest(inp: string): void - { - const result = util.transpileAndExecute(`return typeof ${inp};`); - - Expect(result).toBe("nil"); - } - - @Test("instanceof") - public instanceOf(): void - { - const result = util.transpileAndExecute( - "class myClass {} let inst = new myClass(); return inst instanceof myClass;" - ); - - Expect(result).toBeTruthy(); - } - - @Test("instanceof inheritance") - public instanceOfInheritance(): void - { - const result = util.transpileAndExecute("class myClass {}\n" - + "class childClass extends myClass{}\n" - + "let inst = new childClass(); return inst instanceof myClass;"); - - Expect(result).toBeTruthy(); - } - - @Test("instanceof inheritance false") - public instanceOfInheritanceFalse(): void - { - const result = util.transpileAndExecute("class myClass {}\n" - + "class childClass extends myClass{}\n" - + "let inst = new myClass(); return inst instanceof childClass;"); - - Expect(result).toBe(false); - } - - @Test("null instanceof Object") - public nullInstanceOf(): void - { - const result = util.transpileAndExecute("return (null) instanceof Object;"); - - Expect(result).toBe(false); - } - - @Test("null instanceof Class") - public nullInstanceOfClass(): void - { - const result = util.transpileAndExecute("class myClass {} return (null) instanceof myClass;"); - - Expect(result).toBe(false); - } - - @TestCase("extension") - @TestCase("metaExtension") - @Test("instanceof extension") - public instanceOfExtension(extensionType: string): void { - const code = - `declare class A {} - /** @${extensionType} **/ - class B extends A {} - declare const foo: any; - const result = foo instanceof B;`; - Expect(() => util.transpileString(code)).toThrowError( - TranspileError, - "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'." - ); - } - - @Test("instanceof export") - public instanceOfExport(): void - { - const result = util.transpileExecuteAndReturnExport( - `export class myClass {} - let inst = new myClass(); - export const result = inst instanceof myClass;`, - "result" - ); - - Expect(result).toBeTruthy(); - } -} +test.each(["0", "30", "30_000", "30.00"])("typeof number (%p)", inp => { + const result = util.transpileAndExecute(`return typeof ${inp};`); + + expect(result).toBe("number"); +}); + +test.each(['"abc"', "`abc`"])("typeof string (%p)", inp => { + const result = util.transpileAndExecute(`return typeof ${inp};`); + + expect(result).toBe("string"); +}); + +test.each(["false", "true"])("typeof boolean (%p)", inp => { + const result = util.transpileAndExecute(`return typeof ${inp};`); + + expect(result).toBe("boolean"); +}); + +test.each(["{}", "[]"])("typeof object literal (%p)", inp => { + const result = util.transpileAndExecute(`return typeof ${inp};`); + + expect(result).toBe("object"); +}); + +test("typeof class instance", () => { + const result = util.transpileAndExecute( + `class myClass {} let inst = new myClass(); return typeof inst;`, + ); + + expect(result).toBe("object"); +}); + +test("typeof function", () => { + const result = util.transpileAndExecute(`return typeof (() => 3);`); + + expect(result).toBe("function"); +}); + +test.each(["null", "undefined"])("typeof undefined (%p)", inp => { + const result = util.transpileAndExecute(`return typeof ${inp};`); + + expect(result).toBe("nil"); +}); + +test("instanceof", () => { + const result = util.transpileAndExecute( + "class myClass {} let inst = new myClass(); return inst instanceof myClass;", + ); + + expect(result).toBeTruthy(); +}); + +test("instanceof inheritance", () => { + const result = util.transpileAndExecute( + "class myClass {}\n" + + "class childClass extends myClass{}\n" + + "let inst = new childClass(); return inst instanceof myClass;", + ); + + expect(result).toBeTruthy(); +}); + +test("instanceof inheritance false", () => { + const result = util.transpileAndExecute( + "class myClass {}\n" + + "class childClass extends myClass{}\n" + + "let inst = new myClass(); return inst instanceof childClass;", + ); + + expect(result).toBe(false); +}); + +test("null instanceof Object", () => { + const result = util.transpileAndExecute("return (null) instanceof Object;"); + + expect(result).toBe(false); +}); + +test("null instanceof Class", () => { + const result = util.transpileAndExecute( + "class myClass {} return (null) instanceof myClass;", + ); + + expect(result).toBe(false); +}); + +test.each(["extension", "metaExtension"])("instanceof extension (%p)", extensionType => { + const code = `declare class A {} + /** @${extensionType} **/ + class B extends A {} + declare const foo: any; + const result = foo instanceof B;`; + expect(() => util.transpileString(code)).toThrowExactError( + new TranspileError( + "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'.", + ), + ); +}); + +test("instanceof export", () => { + const result = util.transpileExecuteAndReturnExport( + `export class myClass {} + let inst = new myClass(); + export const result = inst instanceof myClass;`, + "result", + ); + + expect(result).toBeTruthy(); +}); diff --git a/test/src/util.ts b/test/util.ts similarity index 51% rename from test/src/util.ts rename to test/util.ts index ec3f0cf73..91eb03ef0 100644 --- a/test/src/util.ts +++ b/test/util.ts @@ -1,47 +1,84 @@ +import { lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari"; +import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; +import { + createStringCompilerProgram, + transpileString as compilerTranspileString, +} from "../src/Compiler"; +import { CompilerOptions, LuaLibImportKind, LuaTarget } from "../src/CompilerOptions"; +import { LuaTransformer } from "../src/LuaTransformer"; + +declare global { + namespace jest { + interface Matchers { + toThrowExactError(error: Error): void; + } + } +} -import { Expect } from "alsatian"; +expect.extend({ + toThrowExactError(actual: () => void, error: Error): { pass: boolean; message: () => string } { + if (this.isNot) { + return { pass: true, message: () => "Inverted toThrowExactError is not implemented" }; + } -import { transpileString as compilerTranspileString, createStringCompilerProgram } from "../../src/Compiler"; -import { CompilerOptions, LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; + let executionError: Error | undefined; + try { + actual(); + } catch (err) { + executionError = err; + } -import {lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari"; + expect(() => { + if (executionError) throw executionError; + }).toThrowError(error); + expect(() => { + if (executionError) throw executionError; + }).toThrowError(error.constructor as ErrorConstructor); -import * as fs from "fs"; -import { LuaTransformer } from "../../src/LuaTransformer"; + return { pass: true, message: () => "" }; + }, +}); export function transpileString( str: string | { [filename: string]: string }, - options?: CompilerOptions, + options: CompilerOptions = {}, ignoreDiagnostics = true, - filePath = "file.ts" -): string -{ - if (ignoreDiagnostics === false) { - ignoreDiagnostics = process.argv[2] === "--ignoreDiagnostics"; - } - if (options) { - if (options.noHeader === undefined) { - options.noHeader = true; - } - return compilerTranspileString(str, options, ignoreDiagnostics, filePath); - } else { - return compilerTranspileString( - str, - { - luaLibImport: LuaLibImportKind.Require, - luaTarget: LuaTarget.Lua53, - target: ts.ScriptTarget.ES2015, - noHeader: true, - }, - ignoreDiagnostics, - filePath - ); + filePath = "file.ts", +): string { + if (!ignoreDiagnostics) { + ignoreDiagnostics = Boolean(process.env.JEST_IGNORE_DIAGNOSTICS); } + + return compilerTranspileString( + str, + { + luaLibImport: LuaLibImportKind.Require, + luaTarget: LuaTarget.Lua53, + target: ts.ScriptTarget.ESNext, + lib: [ + "lib.es2015.d.ts", + "lib.es2016.d.ts", + "lib.es2017.d.ts", + "lib.es2018.d.ts", + "lib.esnext.d.ts", + ], + noHeader: true, + ...options, + }, + ignoreDiagnostics, + filePath, + ); } +const lualibContent = fs.readFileSync( + path.resolve(__dirname, "../dist/lualib/lualib_bundle.lua"), + "utf8", +); +const minimalTestLib = fs.readFileSync(path.join(__dirname, "json.lua"), "utf8") + "\n"; export function executeLua(luaStr: string, withLib = true): any { + luaStr = luaStr.replace(/require\("lualib_bundle"\)/g, lualibContent); if (withLib) { luaStr = minimalTestLib + luaStr; } @@ -61,7 +98,10 @@ export function executeLua(luaStr: string, withLib = true): any { } else if (lua.lua_isstring(L, -1)) { return lua.lua_tojsstring(L, -1); } else { - throw new Error("Unsupported lua return type: " + to_jsstring(lua.lua_typename(L, lua.lua_type(L, -1)))); + throw new Error( + "Unsupported lua return type: " + + to_jsstring(lua.lua_typename(L, lua.lua_type(L, -1))), + ); } } else { // If the lua VM did not terminate with status code LUA_OK an error occurred. @@ -72,21 +112,9 @@ export function executeLua(luaStr: string, withLib = true): any { } } -export function expectCodeEqual(code1: string, code2: string): void { - // Trim leading/trailing whitespace - let c1 = code1.trim(); - let c2 = code2.trim(); - - // Unify indentation - c1 = c1.replace(/\s+/g, " "); - c2 = c2.replace(/\s+/g, " "); - - Expect(c1).toBe(c2); -} - // Get a mock transformer to use for testing export function makeTestTransformer(target: LuaTarget = LuaTarget.Lua53): LuaTransformer { - const options = {luaTarget: target}; + const options = { luaTarget: target }; return new LuaTransformer(ts.createProgram([], options), options); } @@ -95,15 +123,14 @@ export function transpileAndExecute( compilerOptions?: CompilerOptions, luaHeader?: string, tsHeader?: string, - ignoreDiagnosticsOverride = process.argv[2] === "--ignoreDiagnostics" -): any -{ + ignoreDiagnostics = process.argv[2] === "--ignoreDiagnostics", +): any { const wrappedTsString = `${tsHeader ? tsHeader : ""} declare function JSONStringify(this: void, p: any): string; function __runTest(this: void): any {${tsStr}}`; const lua = `${luaHeader ? luaHeader : ""} - ${transpileString(wrappedTsString, compilerOptions, ignoreDiagnosticsOverride)} + ${transpileString(wrappedTsString, compilerOptions, ignoreDiagnostics)} return __runTest();`; return executeLua(lua); @@ -113,9 +140,8 @@ export function transpileExecuteAndReturnExport( tsStr: string, returnExport: string, compilerOptions?: CompilerOptions, - luaHeader?: string -): any -{ + luaHeader?: string, +): any { const wrappedTsString = `declare function JSONStringify(this: void, p: any): string; ${tsStr}`; @@ -127,13 +153,18 @@ export function transpileExecuteAndReturnExport( return executeLua(lua); } -export function parseTypeScript(typescript: string, target: LuaTarget = LuaTarget.Lua53) - : [ts.SourceFile, ts.TypeChecker] { +export function parseTypeScript( + typescript: string, + target: LuaTarget = LuaTarget.Lua53, +): [ts.SourceFile, ts.TypeChecker] { const program = createStringCompilerProgram(typescript, { luaTarget: target }); return [program.getSourceFile("file.ts"), program.getTypeChecker()]; } -export function findFirstChild(node: ts.Node, predicate: (node: ts.Node) => boolean): ts.Node | undefined { +export function findFirstChild( + node: ts.Node, + predicate: (node: ts.Node) => boolean, +): ts.Node | undefined { for (const child of node.getChildren()) { if (predicate(child)) { return child; @@ -146,7 +177,3 @@ export function findFirstChild(node: ts.Node, predicate: (node: ts.Node) => bool } return undefined; } - -const jsonlib = fs.readFileSync("test/src/json.lua") + "\n"; - -export const minimalTestLib = jsonlib; diff --git a/tsconfig.json b/tsconfig.json index f214f1bed..84d667105 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,11 @@ { "compilerOptions": { - "noImplicitThis" : true, - "alwaysStrict" : true, - "outDir": "./dist/", - "rootDir": "./src/", + "noImplicitThis": true, + "alwaysStrict": true, + "rootDir": "./src", + "outDir": "./dist", "declaration": true, "sourceMap": true, - "experimentalDecorators": true, "target": "es2017", "module": "commonjs" }, diff --git a/tslint.json b/tslint.json index b230c4203..3cba6a148 100644 --- a/tslint.json +++ b/tslint.json @@ -1,55 +1,12 @@ { - "defaultSeverity": "error", + "extends": "./__tests__/tslint.json", "rules": { - "array-type": [true, "array-simple"], "arrow-parens": [true, "ban-single-arg-parens"], - "arrow-return-shorthand": true, - "ban": [true, - {"name": "parseInt", "message": "tsstyle#type-coercion"}, - {"name": "parseFloat", "message": "tsstyle#type-coercion"}, - {"name": "Array", "message": "tsstyle#array-constructor"} - ], - "ban-types": [true, - ["Object", "Use {} instead."], - ["String", "Use 'string' instead."], - ["Number", "Use 'number' instead."], - ["Boolean", "Use 'boolean' instead."] - ], - "class-name": true, - "curly": [true, "ignore-same-line"], - "deprecation": true, - "forin": false, "import-spacing": true, - "interface-name": [true, "never-prefix"], - "jsdoc-format": true, - "label-position": true, - "max-classes-per-file": [true, 1], "max-line-length": [true, 120], - "member-access": true, "new-parens": true, - "no-angle-bracket-type-assertion": true, - "no-any": false, - "no-arg": true, - "no-conditional-assignment": true, - "no-construct": true, - "no-debugger": true, - "no-default-export": true, - "no-duplicate-switch-case": true, - "no-duplicate-variable": true, - "no-inferrable-types": true, - "no-namespace": [true, "allow-declarations"], - "no-null-keyword": true, - "no-reference": true, - "no-string-throw": true, "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-var-keyword": true, - "object-literal-shorthand": true, - "only-arrow-functions": [true, "allow-declarations", "allow-named-functions"], - "prefer-const": true, - "radix": true, "semicolon": [true, "always", "ignore-bound-class-methods"], - "switch-default": false, "trailing-comma": [ true, { @@ -62,21 +19,12 @@ "esSpecCompliant": true } ], - "triple-equals": [true, "allow-null-check"], - "typedef": [ + "whitespace": [ true, - "call-signature", - "property-declaration" - ], - "use-isnan": true, - "variable-name": [ - true, - "check-format", - "ban-keywords", - "allow-leading-underscore", - "allow-pascal-case" - ], - "whitespace": [true, "check-type-operator", "check-decl", "check-rest-spread", "check-typecast"] - }, - "rulesDirectory": [] + "check-type-operator", + "check-decl", + "check-rest-spread", + "check-typecast" + ] + } } From 21d6af416bfe5ddd80dccd2bdafc2c92c1d15880 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 17:34:52 +0500 Subject: [PATCH 02/24] Fix formatting of some code literals --- test/unit/conditionals.spec.ts | 44 ++-- test/unit/loops.spec.ts | 338 +++++++++++++++++-------------- test/unit/lualib/map.spec.ts | 6 +- test/unit/lualib/set.spec.ts | 16 +- test/unit/lualib/symbol.spec.ts | 8 +- test/unit/lualib/weakMap.spec.ts | 83 +++----- test/unit/lualib/weakSet.spec.ts | 48 ++--- 7 files changed, 273 insertions(+), 270 deletions(-) diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index cb0c2f446..d4ea0c9e4 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -19,11 +19,11 @@ test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 1 }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let input: number = ${inp}; - if (input === 0) { - return 0; - } else { - return 1; - }`, + if (input === 0) { + return 0; + } else { + return 1; + }`, ); expect(result).toBe(expected); @@ -214,23 +214,23 @@ test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 2 }, { inp: 2, expected: const result = util.transpileAndExecute( `let result: number = -1; - switch (${inp}) { - case 0: { - let x = 0; - result = 0; - break; - } - case 1: { - let x = 1; - result = x; - } - case 2: { - let x = 2; - result = x; - break; - } - } - return result;`, + switch (${inp}) { + case 0: { + let x = 0; + result = 0; + break; + } + case 1: { + let x = 1; + result = x; + } + case 2: { + let x = 2; + result = x; + break; + } + } + return result;`, ); expect(result).toBe(expected); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index a42e4292e..6c3850629 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -22,25 +22,25 @@ test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 1, 2, 1, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - while (i < arrTest.length) { - if (i % 2 == 0) { - i++; - continue; - } - let j = 2; - while (j > 0) { - if (j == 2) { - j-- - continue; + let i = 0; + while (i < arrTest.length) { + if (i % 2 == 0) { + i++; + continue; + } + let j = 2; + while (j > 0) { + if (j == 2) { + j-- + continue; + } + arrTest[i] = j; + j--; + } + + i++; } - arrTest[i] = j; - j--; - } - - i++; - } - return JSONStringify(arrTest);`, + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -52,25 +52,25 @@ test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 1, 2, 1, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - do { - if (i % 2 == 0) { - i++; - continue; - } - let j = 2; - do { - if (j == 2) { - j-- - continue; - } - arrTest[i] = j; - j--; - } while (j > 0) - - i++; - } while (i < arrTest.length) - return JSONStringify(arrTest);`, + let i = 0; + do { + if (i % 2 == 0) { + i++; + continue; + } + let j = 2; + do { + if (j == 2) { + j-- + continue; + } + arrTest[i] = j; + j--; + } while (j > 0) + + i++; + } while (i < arrTest.length) + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -93,11 +93,11 @@ test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i: number; - for (i = 0 * 1; i < arrTest.length; ++i) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);`, + let i: number; + for (i = 0 * 1; i < arrTest.length; ++i) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); }, @@ -108,20 +108,19 @@ test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 0, 2, 0, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; i < arrTest.length; i++) { - if (i % 2 == 0) { - continue; - } - - for (let j = 0; j < 2; j++) { - if (j == 1) { - continue; + for (let i = 0; i < arrTest.length; i++) { + if (i % 2 == 0) { + continue; + } + + for (let j = 0; j < 2; j++) { + if (j == 1) { + continue; + } + arrTest[i] = j; + } } - arrTest[i] = j; - } - } - return JSONStringify(arrTest); - `, + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -133,10 +132,10 @@ test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - for (let i = 0; arrTest.length > i; i++) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);`, + for (let i = 0; arrTest.length > i; i++) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -161,11 +160,11 @@ test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (; i < arrTest.length; ++i) { - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);`, + let i = 0; + for (; i < arrTest.length; ++i) { + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -177,15 +176,15 @@ test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (;; ++i) { - if (i >= arrTest.length) { - break; - } + let i = 0; + for (;; ++i) { + if (i >= arrTest.length) { + break; + } - arrTest[i] = arrTest[i] + 1; - } - return JSONStringify(arrTest);`, + arrTest[i] = arrTest[i] + 1; + } + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -197,17 +196,17 @@ test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; - let i = 0; - for (;;) { - if (i >= arrTest.length) { - break; - } + let i = 0; + for (;;) { + if (i >= arrTest.length) { + break; + } - arrTest[i] = arrTest[i] + 1; + arrTest[i] = arrTest[i] + 1; - i++; - } - return JSONStringify(arrTest);`, + i++; + } + return JSONStringify(arrTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -256,9 +255,11 @@ test.each([ }); test("for scope", () => { - const code = `let i = 42; + const code = ` + let i = 42; for (let i = 0; i < 10; ++i) {} - return i;`; + return i; + `; expect(util.transpileAndExecute(code)).toBe(42); }); @@ -297,15 +298,14 @@ test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 }, expected: { a: 0, b: 0, c: 2 ({ inp, expected }) => { const result = util.transpileAndExecute( `let obj = ${JSON.stringify(inp)}; - for (let i in obj) { - if (obj[i] % 2 == 0) { - continue; - } + for (let i in obj) { + if (obj[i] % 2 == 0) { + continue; + } - obj[i] = 0; - } - return JSONStringify(obj); - `, + obj[i] = 0; + } + return JSONStringify(obj);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -330,12 +330,12 @@ test.each([{ inp: [0, 1, 2], expected: [1, 2, 3] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - let value: number; - for (value of objTest) { - arrResultTest.push(value + 1) - } - return JSONStringify(arrResultTest);`, + let arrResultTest = []; + let value: number; + for (value of objTest) { + arrResultTest.push(value + 1) + } + return JSONStringify(arrResultTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -347,11 +347,11 @@ test.each([{ inp: [[1, 2], [2, 3], [3, 4]], expected: [3, 5, 7] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - for (let [a,b] of objTest) { - arrResultTest.push(a + b) - } - return JSONStringify(arrResultTest);`, + let arrResultTest = []; + for (let [a,b] of objTest) { + arrResultTest.push(a + b) + } + return JSONStringify(arrResultTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -363,13 +363,13 @@ test.each([{ inp: [[1, 2], [2, 3], [3, 4]], expected: [3, 5, 7] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let objTest = ${JSON.stringify(inp)}; - let arrResultTest = []; - let a: number; - let b: number; - for ([a,b] of objTest) { - arrResultTest.push(a + b) - } - return JSONStringify(arrResultTest);`, + let arrResultTest = []; + let a: number; + let b: number; + for ([a,b] of objTest) { + arrResultTest.push(a + b) + } + return JSONStringify(arrResultTest);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -381,22 +381,22 @@ test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 0, 2, 0, 4] }])( ({ inp, expected }) => { const result = util.transpileAndExecute( `let testArr = ${JSON.stringify(inp)}; - let a = 0; - for (let i of testArr) { - if (i % 2 == 0) { - a++; - continue; - } - - for (let j of [0, 1]) { - if (j == 1) { - continue; + let a = 0; + for (let i of testArr) { + if (i % 2 == 0) { + a++; + continue; + } + + for (let j of [0, 1]) { + if (j == 1) { + continue; + } + testArr[a] = j; + } + a++; } - testArr[a] = j; - } - a++; - } - return JSONStringify(testArr);`, + return JSONStringify(testArr);`, ); expect(result).toBe(JSON.stringify(expected)); @@ -404,7 +404,8 @@ test.each([{ inp: [0, 1, 2, 3, 4], expected: [0, 0, 2, 0, 4] }])( ); test("forof with iterator", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; function iter(): IterableIterator { let i = 0; return { @@ -416,7 +417,8 @@ test("forof with iterator", () => { for (let e of iter()) { result += e; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -427,7 +429,8 @@ test("forof with iterator", () => { }); test("forof with iterator and existing variable", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; function iter(): IterableIterator { let i = 0; return { @@ -440,7 +443,8 @@ test("forof with iterator and existing variable", () => { for (e of iter()) { result += e; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -451,7 +455,8 @@ test("forof with iterator and existing variable", () => { }); test("forof destructuring with iterator", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; function iter(): IterableIterator<[string, string]> { let i = 0; return { @@ -463,7 +468,8 @@ test("forof destructuring with iterator", () => { for (let [a, b] of iter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -474,7 +480,8 @@ test("forof destructuring with iterator", () => { }); test("forof destructuring with iterator and existing variables", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; function iter(): IterableIterator<[string, string]> { let i = 0; return { @@ -488,7 +495,8 @@ test("forof destructuring with iterator and existing variables", () => { for ([a, b] of iter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -499,7 +507,8 @@ test("forof destructuring with iterator and existing variables", () => { }); test("forof lua iterator", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Iterable {} function luaIter(): Iter { @@ -508,7 +517,8 @@ test("forof lua iterator", () => { } let result = ""; for (let e of luaIter()) { result += e; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -519,7 +529,8 @@ test("forof lua iterator", () => { }); test("forof array lua iterator", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Array {} function luaIter(): Iter { @@ -528,7 +539,8 @@ test("forof array lua iterator", () => { } let result = ""; for (let e of luaIter()) { result += e; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -539,7 +551,8 @@ test("forof array lua iterator", () => { }); test("forof lua iterator with existing variable", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Iterable {} function luaIter(): Iter { @@ -549,7 +562,8 @@ test("forof lua iterator with existing variable", () => { let result = ""; let e: string; for (e of luaIter()) { result += e; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -560,7 +574,8 @@ test("forof lua iterator with existing variable", () => { }); test("forof lua iterator destructuring", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Iterable<[string, string]> {} function luaIter(): Iter { @@ -569,7 +584,8 @@ test("forof lua iterator destructuring", () => { } let result = ""; for (let [a, b] of luaIter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -580,7 +596,8 @@ test("forof lua iterator destructuring", () => { }); test("forof lua iterator destructuring with existing variables", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Iterable<[string, string]> {} function luaIter(): Iter { @@ -591,7 +608,8 @@ test("forof lua iterator destructuring with existing variables", () => { let a: string; let b: string; for ([a, b] of luaIter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -602,7 +620,8 @@ test("forof lua iterator destructuring with existing variables", () => { }); test("forof lua iterator tuple-return", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ /** @tupleReturn */ interface Iter extends Iterable<[string, string]> {} @@ -614,7 +633,8 @@ test("forof lua iterator tuple-return", () => { } let result = ""; for (let [a, b] of luaIter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -625,7 +645,8 @@ test("forof lua iterator tuple-return", () => { }); test("forof lua iterator tuple-return with existing variables", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ /** @tupleReturn */ interface Iter extends Iterable<[string, string]> {} @@ -639,7 +660,8 @@ test("forof lua iterator tuple-return with existing variables", () => { let a: string; let b: string; for ([a, b] of luaIter()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -650,11 +672,13 @@ test("forof lua iterator tuple-return with existing variables", () => { }); test("forof lua iterator tuple-return single variable", () => { - const code = `/** @luaIterator */ + const code = ` + /** @luaIterator */ /** @tupleReturn */ interface Iter extends Iterable<[string, string]> {} declare function luaIter(): Iter; - for (let x of luaIter()) {}`; + for (let x of luaIter()) {} + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -670,12 +694,14 @@ test("forof lua iterator tuple-return single variable", () => { }); test("forof lua iterator tuple-return single existing variable", () => { - const code = `/** @luaIterator */ + const code = ` + /** @luaIterator */ /** @tupleReturn */ interface Iter extends Iterable<[string, string]> {} declare function luaIter(): Iter; let x: [string, string]; - for (x of luaIter()) {}`; + for (x of luaIter()) {} + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -691,7 +717,8 @@ test("forof lua iterator tuple-return single existing variable", () => { }); test("forof forwarded lua iterator", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ interface Iter extends Iterable {} function luaIter(): Iter { @@ -705,7 +732,8 @@ test("forof forwarded lua iterator", () => { } let result = ""; for (let a of forward()) { result += a; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, @@ -716,7 +744,8 @@ test("forof forwarded lua iterator", () => { }); test("forof forwarded lua iterator with tupleReturn", () => { - const code = `const arr = ["a", "b", "c"]; + const code = ` + const arr = ["a", "b", "c"]; /** @luaIterator */ /** @tupleReturn */ interface Iter extends Iterable<[string, string]> {} @@ -732,7 +761,8 @@ test("forof forwarded lua iterator with tupleReturn", () => { } let result = ""; for (let [a, b] of forward()) { result += a + b; } - return result;`; + return result; + `; const compilerOptions = { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, diff --git a/test/unit/lualib/map.spec.ts b/test/unit/lualib/map.spec.ts index 01b18028d..149ee258f 100644 --- a/test/unit/lualib/map.spec.ts +++ b/test/unit/lualib/map.spec.ts @@ -16,8 +16,10 @@ test("map iterable constructor", () => { }); test("map iterable constructor map", () => { - const result = util.transpileAndExecute(`let mymap = new Map(new Map([["a", "c"],["b", "d"]])); - return mymap.has("a") && mymap.has("b");`); + const result = util.transpileAndExecute(` + let mymap = new Map(new Map([["a", "c"],["b", "d"]])); + return mymap.has("a") && mymap.has("b"); + `); expect(result).toBe(true); }); diff --git a/test/unit/lualib/set.spec.ts b/test/unit/lualib/set.spec.ts index 61ffed054..1dcdb92c0 100644 --- a/test/unit/lualib/set.spec.ts +++ b/test/unit/lualib/set.spec.ts @@ -119,12 +119,12 @@ test("set values", () => { expect(result).toBe(18); }); -test("set size", () => { - expect(util.transpileAndExecute(`let m = new Set(); return m.size;`)).toBe(0); - expect(util.transpileAndExecute(`let m = new Set(); m.add(1); return m.size;`)).toBe(1); - expect(util.transpileAndExecute(`let m = new Set([1, 2]); return m.size;`)).toBe(2); - expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.clear(); return m.size;`)).toBe(0); - expect(util.transpileAndExecute(`let m = new Set([1, 2]); m.delete(2); return m.size;`)).toBe( - 1, - ); +test.each([ + { code: `let m = new Set(); return m.size;`, expected: 0 }, + { code: `let m = new Set(); m.add(1); return m.size;`, expected: 1 }, + { code: `let m = new Set([1, 2]); return m.size;`, expected: 2 }, + { code: `let m = new Set([1, 2]); m.clear(); return m.size;`, expected: 0 }, + { code: `let m = new Set([1, 2]); m.delete(2); return m.size;`, expected: 1 }, +])("set size", ({ code, expected }) => { + expect(util.transpileAndExecute(code)).toBe(expected); }); diff --git a/test/unit/lualib/symbol.spec.ts b/test/unit/lualib/symbol.spec.ts index a094c2ddb..51be6c70e 100644 --- a/test/unit/lualib/symbol.spec.ts +++ b/test/unit/lualib/symbol.spec.ts @@ -4,8 +4,8 @@ test.each([{}, { description: 1 }, { description: "name" }])( "symbol.toString() (%p)", ({ description }) => { const result = util.transpileAndExecute(` - return Symbol(${JSON.stringify(description)}).toString(); -`); + return Symbol(${JSON.stringify(description)}).toString(); + `); expect(result).toBe(`Symbol(${description || ""})`); }, @@ -15,8 +15,8 @@ test.each([{}, { description: 1 }, { description: "name" }])( "symbol.description (%p)", ({ description }) => { const result = util.transpileAndExecute(` - return Symbol(${JSON.stringify(description)}).description; -`); + return Symbol(${JSON.stringify(description)}).description; + `); expect(result).toBe(description); }, diff --git a/test/unit/lualib/weakMap.spec.ts b/test/unit/lualib/weakMap.spec.ts index e386b8370..af22dd96b 100644 --- a/test/unit/lualib/weakMap.spec.ts +++ b/test/unit/lualib/weakMap.spec.ts @@ -1,121 +1,104 @@ import * as util from "../../util"; -const initRefsTs = `let ref = {}; - let ref2 = () => {};`; +const initRefsTs = ` + let ref = {}; + let ref2 = () => {}; +`; test("weakMap constructor", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, 1]]); return mymap.get(ref); - `, - ); + `); expect(result).toBe(1); }); test("weakMap iterable constructor", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, 1], [ref2, 2]]); return mymap.has(ref) && mymap.has(ref2); - `, - ); + `); expect(result).toBe(true); }); test("weakMap iterable constructor map", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap(new Map([[ref, 1], [ref2, 2]])); return mymap.has(ref) && mymap.has(ref2); - `, - ); + `); expect(result).toBe(true); }); test("weakMap delete", () => { - const contains = util.transpileAndExecute( - initRefsTs + - ` + const contains = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, true], [ref2, true]]); mymap.delete(ref2); return mymap.has(ref) && !mymap.has(ref2); - `, - ); + `); expect(contains).toBe(true); }); test("weakMap get", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, 1], [{}, 2]]); return mymap.get(ref); - `, - ); + `); expect(result).toBe(1); }); test("weakMap get missing", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[{}, true]]); return mymap.get({}); - `, - ); + `); expect(result).toBe(undefined); }); test("weakMap has", () => { - const contains = util.transpileAndExecute( - initRefsTs + - ` + const contains = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, true]]); return mymap.has(ref); - `, - ); + `); expect(contains).toBe(true); }); test("weakMap has false", () => { - const contains = util.transpileAndExecute( - initRefsTs + - ` + const contains = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[ref, true]]); return mymap.has(ref2); - `, - ); + `); expect(contains).toBe(false); }); test("weakMap has null", () => { - const contains = util.transpileAndExecute( - initRefsTs + - ` + const contains = util.transpileAndExecute(` + ${initRefsTs} let mymap = new WeakMap([[{}, true]]); return mymap.has(null); - `, - ); + `); expect(contains).toBe(false); }); test("weakMap set", () => { - const init = - initRefsTs + - ` + const init = ` + ${initRefsTs} let mymap = new WeakMap(); mymap.set(ref, 5); `; diff --git a/test/unit/lualib/weakSet.spec.ts b/test/unit/lualib/weakSet.spec.ts index fbc462ea3..95089000e 100644 --- a/test/unit/lualib/weakSet.spec.ts +++ b/test/unit/lualib/weakSet.spec.ts @@ -4,76 +4,64 @@ const initRefsTs = `let ref = {}; let ref2 = () => {};`; test("weakSet constructor", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet([ref]); return myset.has(ref) - `, - ); + `); expect(result).toBe(true); }); test("weakSet iterable constructor", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet([ref, ref2]); return myset.has(ref) && myset.has(ref2); - `, - ); + `); expect(result).toBe(true); }); test("weakSet iterable constructor set", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet(new Set([ref, ref2])); return myset.has(ref) && myset.has(ref2); - `, - ); + `); expect(result).toBe(true); }); test("weakSet add", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet(); myset.add(ref); return myset.has(ref); - `, - ); + `); expect(result).toBe(true); }); test("weakSet add different references", () => { - const result = util.transpileAndExecute( - initRefsTs + - ` + const result = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet(); myset.add({}); return myset.has({}); - `, - ); + `); expect(result).toBe(false); }); test("weakSet delete", () => { - const contains = util.transpileAndExecute( - initRefsTs + - ` + const contains = util.transpileAndExecute(` + ${initRefsTs} let myset = new WeakSet([ref, ref2]); myset.delete(ref); return myset.has(ref2) && !myset.has(ref); - `, - ); + `); expect(contains).toBe(true); }); From e77fbf57165ef6fbee307e24d13446c36f3fcc41 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 17:50:04 +0500 Subject: [PATCH 03/24] Update contributing docs --- .editorconfig | 2 +- CONTRIBUTING.md | 20 ++++++++++++++++---- package.json | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 69fbfa8bc..ceeeb10cd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,5 +8,5 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.yml] +[*.{yml,md}] indent_size = 2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 130a8ed03..5d02f583c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,9 +29,21 @@ The tests for this project can be executed using the standard `npm test`. This r Due to the time required to run all tests, it is impractical to run every test while developing part of the transpiler. To speed up the test run you can: -- Use `npm test -- --watchAll` to start tests and rerun them on change -- Use `npm test name` or interactive watching interface to run tests that match a file name pattern -- Add `.only` to test definition to run a single test in the file +- Use `npm test name` to run tests that match a file name pattern + +- Use `npm test -- --watchAll [name]` to start tests and rerun them on change + +- Check out `Watch Usage` in the watching interface to get information about filtering tests without restarting CLI + +- Use `.only` and `.skip` to filter executed tests in the file + + ```ts + // Skipped + test("test", () => {}); + + // Executed + test.only("test", () => {}); + ``` ## Testing Guidelines When submitting a pull request with new functionality, we require some functional (transpile and execute Lua) to be added, to ensure the new functionality works as expected, and will continue to work that way. @@ -39,7 +51,7 @@ When submitting a pull request with new functionality, we require some functiona Translation tests are discouraged as in most cases as we do not really care about the exact Lua output, as long as executing it results in the correct result (which is tested by functional tests). ## Coding Conventions -Most coding conventions are enforced by the TSLint and Prettier. You can check your code locally by running `npm run lint`. CI process will fail if code does not pass the linter. You also might want to get extensions for your code editor to get immediate feedback. +Most coding conventions are enforced by the TSLint and Prettier. You can check your code locally by running `npm run lint`. The CI build will fail if your code does not pass the linter. For better experience, you can install extensions for your code editor for [TSLint](https://palantir.github.io/tslint/usage/third-party-tools/) and [Prettier](https://prettier.io/docs/en/editors.html). Some extra conventions worth mentioning: * Do not abbreviate variable names. The exception here are inline lambda arguments, if it is obvious what the argument is you can abbreviate to the first letter, e.g: `statements.filter(s => ts.VariableStatement(s))` diff --git a/package.json b/package.json index cb6292246..189c9b9d0 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "overrides": [ { "files": [ + "**/*.md", "**/*.yml", "**/.*.yml" ], From cc07dce87f7f554e9d490f8fd721fb9fa6e971a6 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 19:20:25 +0500 Subject: [PATCH 04/24] Load ts-node in the fork call in watchmode test --- test/compiler/watcher_proccess.js | 6 ------ test/compiler/watcher_proccess.ts | 5 +++++ test/compiler/watchmode.spec.ts | 5 ++++- 3 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 test/compiler/watcher_proccess.js create mode 100644 test/compiler/watcher_proccess.ts diff --git a/test/compiler/watcher_proccess.js b/test/compiler/watcher_proccess.js deleted file mode 100644 index 1f1336618..000000000 --- a/test/compiler/watcher_proccess.js +++ /dev/null @@ -1,6 +0,0 @@ -require("ts-node/register/transpile-only"); -const { compile } = require("../../src/Compiler"); - -process.on("message", args => { - compile(args); -}); diff --git a/test/compiler/watcher_proccess.ts b/test/compiler/watcher_proccess.ts new file mode 100644 index 000000000..25b4bd344 --- /dev/null +++ b/test/compiler/watcher_proccess.ts @@ -0,0 +1,5 @@ +import { compile } from "../../src/Compiler"; + +process.on("message", args => { + compile(args); +}); diff --git a/test/compiler/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index 899f2dcea..0a4cb8519 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -36,7 +36,10 @@ test.each([ const fileToChangeOut = fileToChange.replace(".ts", ".lua"); const originalTS = fs.readFileSync(fileToChange); - const child = fork(path.join(__dirname, "watcher_proccess.js"), [], { silent: true }); + const child = fork(path.join(__dirname, "watcher_proccess.ts"), [], { + silent: true, + execArgv: ["--require", "ts-node/register/transpile-only"], + }); testsCleanup.push(() => { try { From 7fe1921cdf1f1a8553b9599fe79f58d992955046 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 19:57:15 +0500 Subject: [PATCH 05/24] Change test directory in configs --- .prettierignore | 2 +- CONTRIBUTING.md | 6 +++--- jest.config.js | 8 +++++--- package.json | 2 +- tslint.json | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.prettierignore b/.prettierignore index 5048d1b5a..7b107d878 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,6 @@ /dist /coverage -/__tests__/compiler/testfiles/invalid_syntax.ts +/test/compiler/testfiles/invalid_syntax.ts /src *.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d02f583c..45935e825 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,11 +17,11 @@ To get familiar with the project structure, here is a short overview of each dir * *LuaTransformer.ts* - Main transpiler code, transforms a TypeScript AST to a Lua AST. * *LuaPrinter.ts* - Transforms a Lua AST to a string. * *TSHelper.ts* - Helper methods used during the transpilation process. -- `__tests__/` +- `test/` * This directory contains all testing code for the transpiler. - * `__tests__/unit/` + * `test/unit/` - Unit/Functional tests for the transpiler. Tests in here are grouped by functionality they are testing. Generally each of these tests uses the transpiler to transpile some TypeScript to Lua, then executes it using the Fengari Lua VM. Assertion is done on the result of the lua code. - * `__tests__/translation/` + * `test/translation/` - **[Obsolete]** Contains tests that only check the transpiled Lua String. We prefer adding unit/functional tests over translation tests. This directory will probably be removed at some point. ## Running Tests diff --git a/jest.config.js b/jest.config.js index 4ee118e9c..f55d00c5c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,8 +2,8 @@ const isCI = require("is-ci"); /** @type {Partial} */ -module.exports = { - testMatch: ["**/__tests__/**/*.test.ts"], +const config = { + testMatch: ["**/test/**/*.spec.ts"], collectCoverageFrom: ["/src/**/*", "!/src/lualib/**/*"], watchPathIgnorePatterns: ["/watch\\.ts$"], @@ -12,8 +12,10 @@ module.exports = { preset: "ts-jest", globals: { "ts-jest": { - tsConfig: "/__tests__/tsconfig.json", + tsConfig: "/test/tsconfig.json", diagnostics: { warnOnly: !isCI }, }, }, }; + +module.exports = config; diff --git a/package.json b/package.json index 189c9b9d0..10ab70633 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "test-fast": "cross-env JEST_IGNORE_DIAGNOSTICS=true jest", "lint": "npm run lint:tslint && npm run lint:prettier", "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", - "lint:tslint": "tslint -p . && tslint -p __tests__ && tslint src/lualib/*.ts", + "lint:tslint": "tslint -p . && tslint -p test && tslint src/lualib/*.ts", "release-major": "npm version major", "release-minor": "npm version minor", "release-patch": "npm version patch", diff --git a/tslint.json b/tslint.json index 3cba6a148..178f3066d 100644 --- a/tslint.json +++ b/tslint.json @@ -1,5 +1,5 @@ { - "extends": "./__tests__/tslint.json", + "extends": "./test/tslint.json", "rules": { "arrow-parens": [true, "ban-single-arg-parens"], "import-spacing": true, From 628069c8a8c6dcb1bdd3525f422d013d150439a5 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 22:00:38 +0500 Subject: [PATCH 06/24] Revisit toThrowExactError matcher --- src/TranspileError.ts | 2 +- test/unit/assignments.spec.ts | 51 ++++++++++---------- test/unit/class.spec.ts | 20 ++++---- test/unit/conditionals.spec.ts | 5 +- test/unit/decoratorCustomConstructor.spec.ts | 2 +- test/unit/decoratorMetaExtension.spec.ts | 10 ++-- test/unit/enum.spec.ts | 9 ++-- test/unit/error.spec.ts | 4 +- test/unit/expressions.spec.ts | 38 ++++++--------- test/unit/functions.spec.ts | 6 +-- test/unit/hoisting.spec.ts | 9 ++-- test/unit/importexport.spec.ts | 6 +-- test/unit/json.spec.ts | 2 +- test/unit/loops.spec.ts | 6 +-- test/unit/modules.spec.ts | 4 +- test/unit/string.spec.ts | 2 +- test/unit/typechecking.spec.ts | 7 ++- test/util.ts | 25 ++++++++-- 18 files changed, 102 insertions(+), 106 deletions(-) diff --git a/src/TranspileError.ts b/src/TranspileError.ts index 35ce051c3..dc64f3da6 100644 --- a/src/TranspileError.ts +++ b/src/TranspileError.ts @@ -2,7 +2,7 @@ import * as ts from "typescript"; export class TranspileError extends Error { public name = 'TranspileError'; - constructor(message: string, public node?: ts.Node) { + constructor(message: string, public node: ts.Node) { super(message); } } diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index ed3c49daf..9cfde22e1 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -473,8 +473,8 @@ test.each([ }); test("Ellipsis binding pattern", () => { - expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrowExactError( - new Error("Ellipsis destruction is not allowed."), + expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrow( + "Ellipsis destruction is not allowed.", ); }); @@ -578,8 +578,9 @@ test("TupleReturn in expression", () => { test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( "Keyword identifier error (%p)", identifier => { - expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowExactError( - new TranspileError(`Cannot use Lua keyword ${identifier} as identifier.`), + expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowWithMessage( + TranspileError, + `Cannot use Lua keyword ${identifier} as identifier.`, ); }, ); @@ -613,8 +614,8 @@ test.each(invalidTestFunctionAssignments)( const code = `${testFunction.definition || ""} const fn: ${functionType} = ${testFunction.value};`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -626,8 +627,8 @@ test.each(invalidTestFunctionAssignments)( let fn: ${functionType}; fn = ${testFunction.value};`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -651,8 +652,8 @@ test.each(invalidTestFunctionCasts)( let fn: typeof ${testFunction.value}; fn = ${castedFunction};`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -677,8 +678,8 @@ test.each(invalidTestFunctionAssignments)( declare function takesFunction(fn: ${functionType}); takesFunction(${testFunction.value});`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -696,7 +697,7 @@ test("Invalid lua lib function argument", () => { const code = `declare function foo(this: void, value: string): void; declare const a: string[]; a.forEach(foo);`; - const err = TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "callbackfn"); + const err = TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "callbackfn"); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }); @@ -720,8 +721,8 @@ test.each(invalidTestFunctionCasts)( declare function takesFunction(fn: typeof ${testFunction.value}); takesFunction(${castedFunction});`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -756,8 +757,8 @@ test.each(invalidTestFunctionAssignments)( declare function takesFunction(fn: T); takesFunction(${testFunction.value});`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -798,8 +799,8 @@ test.each(invalidTestFunctionAssignments)( return ${testFunction.value}; }`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -826,8 +827,8 @@ test.each(invalidTestFunctionCasts)( return ${castedFunction}; }`; const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }, ); @@ -862,7 +863,7 @@ test("Invalid function tuple assignment", () => { declare function getTuple(): [number, Meth]; let [i, f]: [number, Func] = getTuple();`; expect(() => util.transpileString(code)).toThrowExactError( - new TranspileError(TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined).message), + TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub), ); }); @@ -884,7 +885,7 @@ test("Invalid method tuple assignment", () => { declare function getTuple(): [number, Func]; let [i, f]: [number, Meth] = getTuple();`; expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedSelfFunctionConversion(undefined), + TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub), ); }); @@ -904,7 +905,7 @@ test("Invalid interface method assignment", () => { declare const a: A; const b: B = a;`; expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined, "fn"), + TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"), ); }); @@ -946,7 +947,7 @@ test.each([ declare const o: O; let f: ${assignType} = o;`; expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedOverloadAssignment(undefined), + TSTLErrors.UnsupportedOverloadAssignment(util.nodeStub), ); }); diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index b9c23546d..253a40f3d 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -500,9 +500,9 @@ test("methodDefaultParameters", () => { test("Class without name error", () => { const transformer = util.makeTestTransformer(); - expect(() => - transformer.transformClassDeclaration({} as ts.ClassDeclaration), - ).toThrowExactError(new Error("Class declarations must have a name.")); + expect(() => transformer.transformClassDeclaration({} as ts.ClassDeclaration)).toThrow( + "Class declarations must have a name.", + ); }); test("CallSuperMethodNoArgs", () => { @@ -713,10 +713,9 @@ test.each(["extension", "metaExtension"])("Class extends extension (%p)", extens /** @${extensionType} **/ class B extends A {} class C extends B {}`; - expect(() => util.transpileString(code)).toThrowExactError( - new TranspileError( - "Cannot extend classes with decorator '@extension' or '@metaExtension'.", - ), + expect(() => util.transpileString(code)).toThrowWithMessage( + TranspileError, + "Cannot extend classes with decorator '@extension' or '@metaExtension'.", ); }); @@ -725,10 +724,9 @@ test.each(["extension", "metaExtension"])("Class construct extension (%p)", exte /** @${extensionType} **/ class B extends A {} const b = new B();`; - expect(() => util.transpileString(code)).toThrowExactError( - new TranspileError( - "Cannot construct classes with decorator '@extension' or '@metaExtension'.", - ), + expect(() => util.transpileString(code)).toThrowWithMessage( + TranspileError, + "Cannot construct classes with decorator '@extension' or '@metaExtension'.", ); }); diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index d4ea0c9e4..d3b584369 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -374,7 +374,8 @@ test("switch dead code after return", () => { test("switch not allowed in 5.1", () => { expect(() => util.transpileString(`switch ("abc") {}`, { luaTarget: LuaTarget.Lua51 }), - ).toThrowExactError( - new TranspileError("Switch statements is/are not supported for target Lua 5.1."), + ).toThrowWithMessage( + TranspileError, + "Switch statements is/are not supported for target Lua 5.1.", ); }); diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index 87620b101..dce0e9fe4 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -39,5 +39,5 @@ test("IncorrectUsage", () => { return new Point2D(1, 2).x; `, ); - }).toThrowExactError(new TranspileError("!CustomConstructor expects 1 argument(s) but got 0.")); + }).toThrowWithMessage(TranspileError, "!CustomConstructor expects 1 argument(s) but got 0."); }); diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index abac8f233..9faaecfac 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -27,7 +27,6 @@ test("MetaExtension", () => { }); test("IncorrectUsage", () => { - const expectedMessage = TSTLErrors.MissingMetaExtension(undefined).message; expect(() => { util.transpileString( ` @@ -39,7 +38,7 @@ test("IncorrectUsage", () => { } `, ); - }).toThrowExactError(new TranspileError(expectedMessage)); + }).toThrowExactError(TSTLErrors.MissingMetaExtension(util.nodeStub)); }); test("DontAllowInstantiation", () => { @@ -53,9 +52,8 @@ test("DontAllowInstantiation", () => { const e = new Ext(); `, ); - }).toThrowExactError( - new TranspileError( - "Cannot construct classes with decorator '@extension' or '@metaExtension'.", - ), + }).toThrowWithMessage( + TranspileError, + "Cannot construct classes with decorator '@extension' or '@metaExtension'.", ); }); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index 7a2b07b66..0a9f95354 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -64,11 +64,10 @@ test("Invalid heterogeneous enum", () => { c, }`, ); - }).toThrowExactError( - new TranspileError( - "Invalid heterogeneous enum. Enums should either specify no " + - "member values, or specify values (of the same type) for all members.", - ), + }).toThrowWithMessage( + TranspileError, + "Invalid heterogeneous enum. Enums should either specify no " + + "member values, or specify values (of the same type) for all members.", ); }); diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 60a0adf10..ee0b31b23 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -10,9 +10,7 @@ test("throwString", () => { test("throwError", () => { expect(() => { const lua = util.transpileString(`throw Error("Some Error")`); - }).toThrowExactError( - new TranspileError("Invalid throw expression, only strings can be thrown."), - ); + }).toThrowWithMessage(TranspileError, "Invalid throw expression, only strings can be thrown."); }); test.each([{ i: 0, expected: "A" }, { i: 1, expected: "B" }, { i: 2, expected: "C" }])( diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 2cf2e6cb3..2501675d0 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -169,12 +169,10 @@ test.each(["a>>b", "a>>=b"])("Unsupported bitop 5.3 (%p)", input => { luaLibImport: LuaLibImportKind.None, }), ).toThrowExactError( - new TranspileError( - TSTLErrors.UnsupportedKind( - "right shift operator (use >>> instead)", - ts.SyntaxKind.GreaterThanGreaterThanToken, - undefined, - ).message, + TSTLErrors.UnsupportedKind( + "right shift operator (use >>> instead)", + ts.SyntaxKind.GreaterThanGreaterThanToken, + util.nodeStub, ), ); }); @@ -457,9 +455,7 @@ test("Unknown unary postfix error", () => { expect(() => transformer.transformPostfixUnaryExpression(mockExpression as ts.PostfixUnaryExpression), - ).toThrowExactError( - new TranspileError("Unsupported unary postfix operator kind: AsteriskToken"), - ); + ).toThrowWithMessage(TranspileError, "Unsupported unary postfix operator kind: AsteriskToken"); }); test("Unknown unary postfix error", () => { @@ -472,19 +468,16 @@ test("Unknown unary postfix error", () => { expect(() => transformer.transformPrefixUnaryExpression(mockExpression as ts.PrefixUnaryExpression), - ).toThrowExactError( - new TranspileError("Unsupported unary prefix operator kind: AsteriskToken"), - ); + ).toThrowWithMessage(TranspileError, "Unsupported unary prefix operator kind: AsteriskToken"); }); test("Incompatible fromCodePoint expression error", () => { const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); const identifier = ts.createIdentifier("fromCodePoint"); - expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( - new TranspileError( - "string property fromCodePoint is/are not supported for target Lua jit.", - ), + expect(() => transformer.transformStringExpression(identifier)).toThrowWithMessage( + TranspileError, + "string property fromCodePoint is/are not supported for target Lua jit.", ); }); @@ -492,8 +485,9 @@ test("Unknown string expression error", () => { const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); const identifier = ts.createIdentifier("abcd"); - expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( - new TranspileError("string property abcd is/are not supported for target Lua jit."), + expect(() => transformer.transformStringExpression(identifier)).toThrowWithMessage( + TranspileError, + "string property abcd is/are not supported for target Lua jit.", ); }); @@ -512,7 +506,7 @@ test("Unsupported array function error", () => { expect(() => transformer.transformArrayCallExpression(mockNode as ts.CallExpression), - ).toThrowExactError(new TranspileError("Unsupported property on array: unknownFunction")); + ).toThrowWithMessage(TranspileError, "Unsupported property on array: unknownFunction"); }); test("Unsupported math property error", () => { @@ -520,7 +514,7 @@ test("Unsupported math property error", () => { expect(() => transformer.transformMathExpression(ts.createIdentifier("unknownProperty")), - ).toThrowExactError(new TranspileError("Unsupported property on math: unknownProperty")); + ).toThrowWithMessage(TranspileError, "Unsupported property on math: unknownProperty"); }); test("Unsupported object literal element error", () => { @@ -537,7 +531,5 @@ test("Unsupported object literal element error", () => { expect(() => transformer.transformObjectLiteral(mockObject as ts.ObjectLiteralExpression), - ).toThrowExactError( - new TranspileError("Unsupported object literal element kind: FalseKeyword"), - ); + ).toThrowWithMessage(TranspileError, "Unsupported object literal element kind: FalseKeyword"); }); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index 5d1fb1763..ecd018b8c 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -195,9 +195,9 @@ test("Invalid property access call transpilation", () => { expression: ts.createLiteral("abc"), }; - expect(() => - transformer.transformPropertyCall(mockObject as ts.CallExpression), - ).toThrowExactError(new Error("Tried to transpile a non-property call as property call.")); + expect(() => transformer.transformPropertyCall(mockObject as ts.CallExpression)).toThrow( + "Tried to transpile a non-property call as property call.", + ); }); test("Function dead code after return", () => { diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index f570913cb..01855282c 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -204,10 +204,9 @@ test.each([ { code: `function makeFoo() { return new Foo(); } class Foo {}`, identifier: "Foo" }, { code: `function bar() { return E.A; } enum E { A = "foo" }`, identifier: "E" }, ])("No Hoisting (%p)", ({ code, identifier }) => { - expect(() => util.transpileString(code, { noHoisting: true })).toThrowExactError( - new TranspileError( - `Identifier "${identifier}" was referenced before it was declared. The declaration ` + - "must be moved before the identifier's use, or hoisting must be enabled.", - ), + expect(() => util.transpileString(code, { noHoisting: true })).toThrowWithMessage( + TranspileError, + `Identifier "${identifier}" was referenced before it was declared. The declaration ` + + "must be moved before the identifier's use, or hoisting must be enabled.", ); }); diff --git a/test/unit/importexport.spec.ts b/test/unit/importexport.spec.ts index f77be8e70..cd98b0b4f 100644 --- a/test/unit/importexport.spec.ts +++ b/test/unit/importexport.spec.ts @@ -1,14 +1,12 @@ -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; -import { TranspileError } from "../../src/TranspileError"; +import * as util from "../util"; test.each([ "export { default } from '...'", "export { x as default } from '...';", "export { default as x } from '...';", ])("Export default keyword disallowed (%p)", exportStatement => { - const expectedTest = TSTLErrors.UnsupportedDefaultExport(undefined).message; expect(() => util.transpileString(exportStatement)).toThrowExactError( - new TranspileError(expectedTest), + TSTLErrors.UnsupportedDefaultExport(util.nodeStub), ); }); diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index 03187e7fe..9c4009504 100644 --- a/test/unit/json.spec.ts +++ b/test/unit/json.spec.ts @@ -20,5 +20,5 @@ test.each(["0", '""', "[]", '[1, "2", []]', '{ "a": "b" }', '{ "a": { "b": "c" } test("Empty JSON", () => { expect(() => transpileString("", { resolveJsonModule: true, noHeader: true }, false, "file.json"), - ).toThrowExactError(new TranspileError("Invalid JSON file content")); + ).toThrowWithMessage(TranspileError, "Invalid JSON file content"); }); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 6c3850629..33921b5e5 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -288,7 +288,7 @@ test.each([{ inp: [1, 2, 3] }])("forin[Array] (%p)", ({ inp }) => { arrTest[key]++; }`, ), - ).toThrowExactError( + ).toThrowWithMessage( new TranspileError("Iterating over arrays with 'for ... in' is not allowed."), ); }); @@ -684,7 +684,7 @@ test("forof lua iterator tuple-return single variable", () => { luaTarget: LuaTarget.Lua53, target: ts.ScriptTarget.ES2015, }; - expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + expect(() => util.transpileString(code, compilerOptions)).toThrowWithMessage( new TranspileError( "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + "You must use a destructuring statement to catch results from a lua iterator with " + @@ -707,7 +707,7 @@ test("forof lua iterator tuple-return single existing variable", () => { luaTarget: LuaTarget.Lua53, target: ts.ScriptTarget.ES2015, }; - expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + expect(() => util.transpileString(code, compilerOptions)).toThrowWithMessage( new TranspileError( "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + "You must use a destructuring statement to catch results from a lua iterator with " + diff --git a/test/unit/modules.spec.ts b/test/unit/modules.spec.ts index 878169eaf..919f93ecd 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -4,9 +4,7 @@ import * as util from "../util"; test("defaultImport", () => { expect(() => { const lua = util.transpileString(`import TestClass from "test"`); - }).toThrowExactError( - new Error("Default Imports are not supported, please use named imports instead!"), - ); + }).toThrow("Default Imports are not supported, please use named imports instead!"); }); test("lualibRequire", () => { diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index 2e52f17d9..6a748c794 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -4,7 +4,7 @@ import * as util from "../util"; test("Unsuported string function", () => { expect(() => { util.transpileString(`return "test".testThisIsNoMember()`); - }).toThrowExactError(new TranspileError("Unsupported property on string: testThisIsNoMember")); + }).toThrowWithMessage(TranspileError, "Unsupported property on string: testThisIsNoMember"); }); test("Suported lua string function", () => { diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 0045be9d5..060b71380 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -93,10 +93,9 @@ test.each(["extension", "metaExtension"])("instanceof extension (%p)", extension class B extends A {} declare const foo: any; const result = foo instanceof B;`; - expect(() => util.transpileString(code)).toThrowExactError( - new TranspileError( - "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'.", - ), + expect(() => util.transpileString(code)).toThrowWithMessage( + TranspileError, + "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'.", ); }); diff --git a/test/util.ts b/test/util.ts index 91eb03ef0..4861baa88 100644 --- a/test/util.ts +++ b/test/util.ts @@ -9,36 +9,51 @@ import { import { CompilerOptions, LuaLibImportKind, LuaTarget } from "../src/CompilerOptions"; import { LuaTransformer } from "../src/LuaTransformer"; +export const nodeStub = ts.createNode(ts.SyntaxKind.Unknown); + declare global { namespace jest { interface Matchers { + toThrowWithMessage(type: new (...args: any[]) => Error, message: string): void; toThrowExactError(error: Error): void; } } } expect.extend({ - toThrowExactError(actual: () => void, error: Error): { pass: boolean; message: () => string } { + toThrowWithMessage( + callback: () => void, + type: new (...args: any[]) => Error, + message: string, + ): { pass: boolean; message: () => string } { if (this.isNot) { - return { pass: true, message: () => "Inverted toThrowExactError is not implemented" }; + return { pass: true, message: () => "Inverted toThrowWithMessage is not implemented" }; } let executionError: Error | undefined; try { - actual(); + callback(); } catch (err) { executionError = err; } expect(() => { if (executionError) throw executionError; - }).toThrowError(error); + }).toThrowError(type); expect(() => { if (executionError) throw executionError; - }).toThrowError(error.constructor as ErrorConstructor); + }).toThrowError(message); return { pass: true, message: () => "" }; }, + toThrowExactError( + callback: () => void, + error: Error, + ): { pass: boolean; message: () => string } { + const matchers = this.isNot ? expect(callback).not : expect(callback); + matchers.toThrowWithMessage(error.constructor as ErrorConstructor, error.message); + return { pass: true, message: () => "" }; + }, }); export function transpileString( From 2a8ff2feb004cfb68a9ed1c7a45181e470457131 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 22:24:46 +0500 Subject: [PATCH 07/24] Use toThrowExactError on TSTLErrors in tests --- src/LuaTransformer.ts | 2 +- test/unit/assignments.spec.ts | 10 ++--- test/unit/class.spec.ts | 17 ++++---- test/unit/conditionals.spec.ts | 6 +-- test/unit/decoratorCustomConstructor.spec.ts | 5 ++- test/unit/decoratorMetaExtension.spec.ts | 5 +-- test/unit/enum.spec.ts | 7 +--- test/unit/error.spec.ts | 3 +- test/unit/expressions.spec.ts | 42 +++++++++++++++----- test/unit/functions.spec.ts | 7 ++-- test/unit/hoisting.spec.ts | 8 ++-- test/unit/json.spec.ts | 3 +- test/unit/loops.spec.ts | 21 +++------- test/unit/modules.spec.ts | 3 +- test/unit/string.spec.ts | 5 ++- test/unit/typechecking.spec.ts | 6 +-- test/util.ts | 20 +++------- 17 files changed, 87 insertions(+), 83 deletions(-) diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 08ef605a4..554bf1bdb 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -3051,7 +3051,7 @@ export class LuaTransformer { if (classDecorators.has(DecoratorKind.CustomConstructor)) { const customDecorator = classDecorators.get(DecoratorKind.CustomConstructor); if (!customDecorator.args[0]) { - throw TSTLErrors.InvalidDecoratorArgumentNumber("!CustomConstructor", 0, 1, node); + throw TSTLErrors.InvalidDecoratorArgumentNumber("@customConstructor", 0, 1, node); } return tstl.createCallExpression( tstl.createIdentifier(customDecorator.args[0]), diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 9cfde22e1..80d6594f6 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -1,3 +1,4 @@ +import * as ts from "typescript"; import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; import * as util from "../util"; @@ -473,8 +474,8 @@ test.each([ }); test("Ellipsis binding pattern", () => { - expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrow( - "Ellipsis destruction is not allowed.", + expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrowExactError( + TSTLErrors.ForbiddenEllipsisDestruction(util.nodeStub), ); }); @@ -578,9 +579,8 @@ test("TupleReturn in expression", () => { test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( "Keyword identifier error (%p)", identifier => { - expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowWithMessage( - TranspileError, - `Cannot use Lua keyword ${identifier} as identifier.`, + expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowExactError( + TSTLErrors.KeywordIdentifier(ts.createIdentifier(identifier)), ); }, ); diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index 253a40f3d..4569b76aa 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -1,6 +1,7 @@ import * as ts from "typescript"; import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("ClassFieldInitializer", () => { const result = util.transpileAndExecute( @@ -500,9 +501,9 @@ test("methodDefaultParameters", () => { test("Class without name error", () => { const transformer = util.makeTestTransformer(); - expect(() => transformer.transformClassDeclaration({} as ts.ClassDeclaration)).toThrow( - "Class declarations must have a name.", - ); + expect(() => + transformer.transformClassDeclaration({} as ts.ClassDeclaration), + ).toThrowExactError(TSTLErrors.MissingClassName(util.nodeStub)); }); test("CallSuperMethodNoArgs", () => { @@ -713,9 +714,8 @@ test.each(["extension", "metaExtension"])("Class extends extension (%p)", extens /** @${extensionType} **/ class B extends A {} class C extends B {}`; - expect(() => util.transpileString(code)).toThrowWithMessage( - TranspileError, - "Cannot extend classes with decorator '@extension' or '@metaExtension'.", + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.InvalidExtendsExtension(util.nodeStub), ); }); @@ -724,9 +724,8 @@ test.each(["extension", "metaExtension"])("Class construct extension (%p)", exte /** @${extensionType} **/ class B extends A {} const b = new B();`; - expect(() => util.transpileString(code)).toThrowWithMessage( - TranspileError, - "Cannot construct classes with decorator '@extension' or '@metaExtension'.", + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub), ); }); diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index d3b584369..982c24b19 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,6 +1,7 @@ import { TranspileError } from "../../src/TranspileError"; import { LuaTarget } from "../../src/CompilerOptions"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 1 }])("if (%p)", ({ inp, expected }) => { const result = util.transpileAndExecute( @@ -374,8 +375,7 @@ test("switch dead code after return", () => { test("switch not allowed in 5.1", () => { expect(() => util.transpileString(`switch ("abc") {}`, { luaTarget: LuaTarget.Lua51 }), - ).toThrowWithMessage( - TranspileError, - "Switch statements is/are not supported for target Lua 5.1.", + ).toThrowExactError( + TSTLErrors.UnsupportedForTarget("Switch statements", LuaTarget.Lua51, util.nodeStub), ); }); diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index dce0e9fe4..443b28d6e 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -1,6 +1,7 @@ import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("CustomCreate", () => { const luaHeader = `function Point2DCreate(x, y) @@ -39,5 +40,7 @@ test("IncorrectUsage", () => { return new Point2D(1, 2).x; `, ); - }).toThrowWithMessage(TranspileError, "!CustomConstructor expects 1 argument(s) but got 0."); + }).toThrowExactError( + TSTLErrors.InvalidDecoratorArgumentNumber("@customConstructor", 0, 1, util.nodeStub), + ); }); diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index 9faaecfac..93424e54f 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -52,8 +52,5 @@ test("DontAllowInstantiation", () => { const e = new Ext(); `, ); - }).toThrowWithMessage( - TranspileError, - "Cannot construct classes with decorator '@extension' or '@metaExtension'.", - ); + }).toThrowExactError(TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub)); }); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index 0a9f95354..2652de9ff 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -1,6 +1,7 @@ import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("Declare const enum", () => { const testCode = ` @@ -64,11 +65,7 @@ test("Invalid heterogeneous enum", () => { c, }`, ); - }).toThrowWithMessage( - TranspileError, - "Invalid heterogeneous enum. Enums should either specify no " + - "member values, or specify values (of the same type) for all members.", - ); + }).toThrowExactError(TSTLErrors.HeterogeneousEnum(util.nodeStub)); }); test("String literal name in enum", () => { diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index ee0b31b23..e58d8553d 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,6 +1,7 @@ import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("throwString", () => { const lua = util.transpileString(`throw "Some Error"`); @@ -10,7 +11,7 @@ test("throwString", () => { test("throwError", () => { expect(() => { const lua = util.transpileString(`throw Error("Some Error")`); - }).toThrowWithMessage(TranspileError, "Invalid throw expression, only strings can be thrown."); + }).toThrowExactError(TSTLErrors.InvalidThrowExpression(util.nodeStub)); }); test.each([{ i: 0, expected: "A" }, { i: 1, expected: "B" }, { i: 2, expected: "C" }])( diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 2501675d0..ce4817e93 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -455,7 +455,13 @@ test("Unknown unary postfix error", () => { expect(() => transformer.transformPostfixUnaryExpression(mockExpression as ts.PostfixUnaryExpression), - ).toThrowWithMessage(TranspileError, "Unsupported unary postfix operator kind: AsteriskToken"); + ).toThrowExactError( + TSTLErrors.UnsupportedKind( + "unary postfix operator", + ts.SyntaxKind.AsteriskToken, + util.nodeStub, + ), + ); }); test("Unknown unary postfix error", () => { @@ -468,16 +474,25 @@ test("Unknown unary postfix error", () => { expect(() => transformer.transformPrefixUnaryExpression(mockExpression as ts.PrefixUnaryExpression), - ).toThrowWithMessage(TranspileError, "Unsupported unary prefix operator kind: AsteriskToken"); + ).toThrowExactError( + TSTLErrors.UnsupportedKind( + "unary prefix operator", + ts.SyntaxKind.AsteriskToken, + util.nodeStub, + ), + ); }); test("Incompatible fromCodePoint expression error", () => { const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); const identifier = ts.createIdentifier("fromCodePoint"); - expect(() => transformer.transformStringExpression(identifier)).toThrowWithMessage( - TranspileError, - "string property fromCodePoint is/are not supported for target Lua jit.", + expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( + TSTLErrors.UnsupportedForTarget( + "string property fromCodePoint", + LuaTarget.LuaJIT, + util.nodeStub, + ), ); }); @@ -485,9 +500,8 @@ test("Unknown string expression error", () => { const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); const identifier = ts.createIdentifier("abcd"); - expect(() => transformer.transformStringExpression(identifier)).toThrowWithMessage( - TranspileError, - "string property abcd is/are not supported for target Lua jit.", + expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( + TSTLErrors.UnsupportedForTarget("string property abcd", LuaTarget.LuaJIT, util.nodeStub), ); }); @@ -506,7 +520,7 @@ test("Unsupported array function error", () => { expect(() => transformer.transformArrayCallExpression(mockNode as ts.CallExpression), - ).toThrowWithMessage(TranspileError, "Unsupported property on array: unknownFunction"); + ).toThrowExactError(TSTLErrors.UnsupportedProperty("array", "unknownFunction", util.nodeStub)); }); test("Unsupported math property error", () => { @@ -514,7 +528,7 @@ test("Unsupported math property error", () => { expect(() => transformer.transformMathExpression(ts.createIdentifier("unknownProperty")), - ).toThrowWithMessage(TranspileError, "Unsupported property on math: unknownProperty"); + ).toThrowExactError(TSTLErrors.UnsupportedProperty("math", "unknownProperty", util.nodeStub)); }); test("Unsupported object literal element error", () => { @@ -531,5 +545,11 @@ test("Unsupported object literal element error", () => { expect(() => transformer.transformObjectLiteral(mockObject as ts.ObjectLiteralExpression), - ).toThrowWithMessage(TranspileError, "Unsupported object literal element kind: FalseKeyword"); + ).toThrowExactError( + TSTLErrors.UnsupportedKind( + "object literal element", + ts.SyntaxKind.FalseKeyword, + util.nodeStub, + ), + ); }); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index ecd018b8c..a5a0c9276 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -1,5 +1,6 @@ import * as ts from "typescript"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("Arrow Function Expression", () => { const result = util.transpileAndExecute(`let add = (a, b) => a+b; return add(1,2);`); @@ -195,9 +196,9 @@ test("Invalid property access call transpilation", () => { expression: ts.createLiteral("abc"), }; - expect(() => transformer.transformPropertyCall(mockObject as ts.CallExpression)).toThrow( - "Tried to transpile a non-property call as property call.", - ); + expect(() => + transformer.transformPropertyCall(mockObject as ts.CallExpression), + ).toThrowExactError(TSTLErrors.InvalidPropertyCall(util.nodeStub)); }); test("Function dead code after return", () => { diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index 01855282c..e0b2ad143 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -1,5 +1,7 @@ +import * as ts from "typescript"; import { TranspileError } from "../../src/TranspileError"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("Var Hoisting", () => { const code = `foo = "foo"; @@ -204,9 +206,7 @@ test.each([ { code: `function makeFoo() { return new Foo(); } class Foo {}`, identifier: "Foo" }, { code: `function bar() { return E.A; } enum E { A = "foo" }`, identifier: "E" }, ])("No Hoisting (%p)", ({ code, identifier }) => { - expect(() => util.transpileString(code, { noHoisting: true })).toThrowWithMessage( - TranspileError, - `Identifier "${identifier}" was referenced before it was declared. The declaration ` + - "must be moved before the identifier's use, or hoisting must be enabled.", + expect(() => util.transpileString(code, { noHoisting: true })).toThrowExactError( + TSTLErrors.ReferencedBeforeDeclaration(ts.createIdentifier(identifier)), ); }); diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index 9c4009504..7fab649c2 100644 --- a/test/unit/json.spec.ts +++ b/test/unit/json.spec.ts @@ -1,6 +1,7 @@ import { transpileString } from "../../src/Compiler"; import { TranspileError } from "../../src/TranspileError"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test.each(["0", '""', "[]", '[1, "2", []]', '{ "a": "b" }', '{ "a": { "b": "c" } }'])( "JSON (%p)", @@ -20,5 +21,5 @@ test.each(["0", '""', "[]", '[1, "2", []]', '{ "a": "b" }', '{ "a": { "b": "c" } test("Empty JSON", () => { expect(() => transpileString("", { resolveJsonModule: true, noHeader: true }, false, "file.json"), - ).toThrowWithMessage(TranspileError, "Invalid JSON file content"); + ).toThrowExactError(TSTLErrors.InvalidJsonFileContent(util.nodeStub)); }); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 33921b5e5..95ada5177 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -2,6 +2,7 @@ import * as ts from "typescript"; import { TranspileError } from "../../src/TranspileError"; import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("while (%p)", ({ inp, expected }) => { const result = util.transpileAndExecute( @@ -288,9 +289,7 @@ test.each([{ inp: [1, 2, 3] }])("forin[Array] (%p)", ({ inp }) => { arrTest[key]++; }`, ), - ).toThrowWithMessage( - new TranspileError("Iterating over arrays with 'for ... in' is not allowed."), - ); + ).toThrowExactError(TSTLErrors.ForbiddenForIn(util.nodeStub)); }); test.each([{ inp: { a: 0, b: 1, c: 2, d: 3, e: 4 }, expected: { a: 0, b: 0, c: 2, d: 0, e: 4 } }])( @@ -684,12 +683,8 @@ test("forof lua iterator tuple-return single variable", () => { luaTarget: LuaTarget.Lua53, target: ts.ScriptTarget.ES2015, }; - expect(() => util.transpileString(code, compilerOptions)).toThrowWithMessage( - new TranspileError( - "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + - "You must use a destructuring statement to catch results from a lua iterator with " + - "the TupleReturn decorator.", - ), + expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + TSTLErrors.UnsupportedNonDestructuringLuaIterator(util.nodeStub), ); }); @@ -707,12 +702,8 @@ test("forof lua iterator tuple-return single existing variable", () => { luaTarget: LuaTarget.Lua53, target: ts.ScriptTarget.ES2015, }; - expect(() => util.transpileString(code, compilerOptions)).toThrowWithMessage( - new TranspileError( - "Unsupported use of lua iterator with TupleReturn decorator in for...of statement. " + - "You must use a destructuring statement to catch results from a lua iterator with " + - "the TupleReturn decorator.", - ), + expect(() => util.transpileString(code, compilerOptions)).toThrowExactError( + TSTLErrors.UnsupportedNonDestructuringLuaIterator(util.nodeStub), ); }); diff --git a/test/unit/modules.spec.ts b/test/unit/modules.spec.ts index 919f93ecd..e30842ef3 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -1,10 +1,11 @@ import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("defaultImport", () => { expect(() => { const lua = util.transpileString(`import TestClass from "test"`); - }).toThrow("Default Imports are not supported, please use named imports instead!"); + }).toThrowExactError(TSTLErrors.DefaultImportsNotSupported(util.nodeStub)); }); test("lualibRequire", () => { diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index 6a748c794..7c26c0825 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -1,10 +1,13 @@ import { TranspileError } from "../../src/TranspileError"; import * as util from "../util"; +import { TSTLErrors } from "../../src/TSTLErrors"; test("Unsuported string function", () => { expect(() => { util.transpileString(`return "test".testThisIsNoMember()`); - }).toThrowWithMessage(TranspileError, "Unsupported property on string: testThisIsNoMember"); + }).toThrowExactError( + TSTLErrors.UnsupportedProperty("string", "testThisIsNoMember", util.nodeStub), + ); }); test("Suported lua string function", () => { diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 060b71380..51cd065a8 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -1,5 +1,6 @@ import * as util from "../util"; import { TranspileError } from "../../src/TranspileError"; +import { TSTLErrors } from "../../src/TSTLErrors"; test.each(["0", "30", "30_000", "30.00"])("typeof number (%p)", inp => { const result = util.transpileAndExecute(`return typeof ${inp};`); @@ -93,9 +94,8 @@ test.each(["extension", "metaExtension"])("instanceof extension (%p)", extension class B extends A {} declare const foo: any; const result = foo instanceof B;`; - expect(() => util.transpileString(code)).toThrowWithMessage( - TranspileError, - "Cannot use instanceof on classes with decorator '@extension' or '@metaExtension'.", + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.InvalidInstanceOfExtension(util.nodeStub), ); }); diff --git a/test/util.ts b/test/util.ts index 4861baa88..3330aa39f 100644 --- a/test/util.ts +++ b/test/util.ts @@ -14,20 +14,18 @@ export const nodeStub = ts.createNode(ts.SyntaxKind.Unknown); declare global { namespace jest { interface Matchers { - toThrowWithMessage(type: new (...args: any[]) => Error, message: string): void; toThrowExactError(error: Error): void; } } } expect.extend({ - toThrowWithMessage( + toThrowExactError( callback: () => void, - type: new (...args: any[]) => Error, - message: string, + error: Error, ): { pass: boolean; message: () => string } { if (this.isNot) { - return { pass: true, message: () => "Inverted toThrowWithMessage is not implemented" }; + return { pass: true, message: () => "Inverted toThrowExactError is not implemented" }; } let executionError: Error | undefined; @@ -39,21 +37,13 @@ expect.extend({ expect(() => { if (executionError) throw executionError; - }).toThrowError(type); + }).toThrowError(error.constructor as any); expect(() => { if (executionError) throw executionError; - }).toThrowError(message); + }).toThrowError(error); return { pass: true, message: () => "" }; }, - toThrowExactError( - callback: () => void, - error: Error, - ): { pass: boolean; message: () => string } { - const matchers = this.isNot ? expect(callback).not : expect(callback); - matchers.toThrowWithMessage(error.constructor as ErrorConstructor, error.message); - return { pass: true, message: () => "" }; - }, }); export function transpileString( From 2294863062c329dcd3db89ec6aabfda1298a151b Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 22:29:39 +0500 Subject: [PATCH 08/24] Increase timeout for watchmode test since it may fail sometimes --- test/compiler/watchmode.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/compiler/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index 0a4cb8519..35be54c8f 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -64,5 +64,5 @@ test.each([ expect(initialResultLua).not.toEqual(updatedResultLua); }, - 10000, + 20000, ); From 033873e9107ecb56dbf0a1cea6a5ce0248803b9c Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 22:38:16 +0500 Subject: [PATCH 09/24] Execute TypeScript's Opganize Imports command --- src/CommandLineParser.ts | 3 +-- src/Compiler.ts | 5 ++--- src/LuaPrinter.ts | 6 ++---- src/LuaTransformer.ts | 11 +++++------ src/LuaTranspiler.ts | 8 +++----- src/TSHelper.ts | 4 +--- src/TSTLErrors.ts | 5 ++--- src/index.ts | 10 +++++----- src/tstl.ts | 2 +- test/translation/builder.spec.ts | 3 +-- test/unit/assignmentDestructuring.spec.ts | 2 +- test/unit/assignments.spec.ts | 1 - test/unit/class.spec.ts | 3 +-- test/unit/commandLineParser.spec.ts | 2 +- test/unit/compiler/configuration/mixed/index.spec.ts | 3 +-- test/unit/compiler/configuration/options.spec.ts | 2 +- test/unit/conditionals.spec.ts | 3 +-- test/unit/decoratorCustomConstructor.spec.ts | 4 +--- test/unit/decoratorMetaExtension.spec.ts | 4 +--- test/unit/enum.spec.ts | 4 +--- test/unit/error.spec.ts | 4 +--- test/unit/expressions.spec.ts | 6 ++---- test/unit/functions.spec.ts | 2 +- test/unit/hoisting.spec.ts | 3 +-- test/unit/json.spec.ts | 3 +-- test/unit/loops.spec.ts | 3 +-- test/unit/lualib/inlining.spec.ts | 3 +-- test/unit/lualib/lualib.spec.ts | 2 -- test/unit/modules.spec.ts | 2 +- test/unit/require.spec.ts | 2 -- test/unit/spreadElement.spec.ts | 2 +- test/unit/string.spec.ts | 3 +-- test/unit/tshelper.spec.ts | 6 ++---- test/unit/typechecking.spec.ts | 3 +-- 34 files changed, 46 insertions(+), 83 deletions(-) diff --git a/src/CommandLineParser.ts b/src/CommandLineParser.ts index 2286bfae8..d2fdc9f0d 100644 --- a/src/CommandLineParser.ts +++ b/src/CommandLineParser.ts @@ -1,8 +1,7 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; - -import {CompilerOptions, LuaTarget, LuaLibImportKind} from "./CompilerOptions"; +import { CompilerOptions, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; export type CLIParseResult = ParseResult; diff --git a/src/Compiler.ts b/src/Compiler.ts index a92f1279b..642624347 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -1,10 +1,9 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; - import * as CommandLineParser from "./CommandLineParser"; -import {CompilerOptions, LuaLibImportKind, LuaTarget} from "./CompilerOptions"; -import {LuaTranspiler} from "./LuaTranspiler"; +import { CompilerOptions, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; +import { LuaTranspiler } from "./LuaTranspiler"; export function compile(argv: string[]): void { const parseResult = CommandLineParser.parseCommandLine(argv); diff --git a/src/LuaPrinter.ts b/src/LuaPrinter.ts index d4d1beefb..dca5d7eb2 100644 --- a/src/LuaPrinter.ts +++ b/src/LuaPrinter.ts @@ -1,9 +1,7 @@ +import { CompilerOptions, LuaLibImportKind } from "./CompilerOptions"; import * as tstl from "./LuaAST"; - +import { LuaLib, LuaLibFeature } from "./LuaLib"; import { TSHelper as tsHelper } from "./TSHelper"; -import { LuaLibFeature, LuaLib } from "./LuaLib"; -import { CompilerOptions } from "./CompilerOptions"; -import { LuaLibImportKind } from "./CompilerOptions"; export class LuaPrinter { /* tslint:disable:object-literal-sort-keys */ diff --git a/src/LuaTransformer.ts b/src/LuaTransformer.ts index 554bf1bdb..d2dcd903e 100644 --- a/src/LuaTransformer.ts +++ b/src/LuaTransformer.ts @@ -1,12 +1,11 @@ import * as path from "path"; import * as ts from "typescript"; - -import {CompilerOptions, LuaLibImportKind, LuaTarget} from "./CompilerOptions"; -import {DecoratorKind} from "./Decorator"; +import { CompilerOptions, LuaTarget } from "./CompilerOptions"; +import { DecoratorKind } from "./Decorator"; import * as tstl from "./LuaAST"; -import {LuaLib, LuaLibFeature} from "./LuaLib"; -import {ContextType, TSHelper as tsHelper} from "./TSHelper"; -import {TSTLErrors} from "./TSTLErrors"; +import { LuaLibFeature } from "./LuaLib"; +import { ContextType, TSHelper as tsHelper } from "./TSHelper"; +import { TSTLErrors } from "./TSTLErrors"; export type StatementVisitResult = tstl.Statement | tstl.Statement[] | undefined; export type ExpressionVisitResult = tstl.Expression | undefined; diff --git a/src/LuaTranspiler.ts b/src/LuaTranspiler.ts index dc96e9801..cd991f511 100644 --- a/src/LuaTranspiler.ts +++ b/src/LuaTranspiler.ts @@ -1,12 +1,10 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; - +import { CompilerOptions, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; import * as tstl from "./LuaAST"; - -import {CompilerOptions, LuaLibImportKind, LuaTarget} from "./CompilerOptions"; -import {LuaPrinter} from "./LuaPrinter"; -import {LuaTransformer} from "./LuaTransformer"; +import { LuaPrinter } from "./LuaPrinter"; +import { LuaTransformer } from "./LuaTransformer"; export class LuaTranspiler { private program: ts.Program; diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 62719cc34..05ed77a25 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -1,7 +1,5 @@ import * as ts from "typescript"; - -import {Decorator, DecoratorKind} from "./Decorator"; -import * as tstl from "./LuaAST"; +import { Decorator, DecoratorKind } from "./Decorator"; export enum ContextType { None, diff --git a/src/TSTLErrors.ts b/src/TSTLErrors.ts index f666c3abe..56ee4e73b 100644 --- a/src/TSTLErrors.ts +++ b/src/TSTLErrors.ts @@ -1,7 +1,6 @@ import * as ts from "typescript"; - -import {TranspileError} from "./TranspileError"; -import {TSHelper as tsHelper} from "./TSHelper"; +import { TranspileError } from "./TranspileError"; +import { TSHelper as tsHelper } from "./TSHelper"; export class TSTLErrors { public static CouldNotFindEnumMember = (enumDeclaration: ts.EnumDeclaration, enumMember: string, node: ts.Node) => diff --git a/src/index.ts b/src/index.ts index 7c9dec9ea..eb153d7bc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -export {parseCommandLine} from "./CommandLineParser"; -export {compile, compileFilesWithOptions, transpileString, watchWithOptions} from "./Compiler"; -export {CompilerOptions, LuaLibImportKind, LuaTarget,} from "./CompilerOptions"; -export {LuaLibFeature,} from "./LuaLib"; -export {LuaTranspiler,} from "./LuaTranspiler"; +export { parseCommandLine } from "./CommandLineParser"; +export { compile, compileFilesWithOptions, transpileString, watchWithOptions } from "./Compiler"; +export { CompilerOptions, LuaLibImportKind, LuaTarget } from "./CompilerOptions"; +export { LuaLibFeature } from "./LuaLib"; +export { LuaTranspiler } from "./LuaTranspiler"; diff --git a/src/tstl.ts b/src/tstl.ts index c4dd2be38..5055ec8aa 100644 --- a/src/tstl.ts +++ b/src/tstl.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import {compile} from "./Compiler"; +import { compile } from "./Compiler"; compile(process.argv.slice(2)); diff --git a/test/translation/builder.spec.ts b/test/translation/builder.spec.ts index 81a9fa3d1..e116b42ea 100644 --- a/test/translation/builder.spec.ts +++ b/test/translation/builder.spec.ts @@ -1,7 +1,6 @@ -import * as util from "../util"; - import * as fs from "fs"; import * as path from "path"; +import * as util from "../util"; const files: Array<{ ts: string; lua: string }> = []; const fileContents: { [key: string]: Buffer } = {}; diff --git a/test/unit/assignmentDestructuring.spec.ts b/test/unit/assignmentDestructuring.spec.ts index 2fa8fb07b..955c36f83 100644 --- a/test/unit/assignmentDestructuring.spec.ts +++ b/test/unit/assignmentDestructuring.spec.ts @@ -1,4 +1,4 @@ -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import * as util from "../util"; const assignmentDestruturingTs = ` diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 80d6594f6..bbc14eb6d 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -1,5 +1,4 @@ import * as ts from "typescript"; -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; import * as util from "../util"; diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index 4569b76aa..ef57866fa 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -1,7 +1,6 @@ import * as ts from "typescript"; -import * as util from "../util"; -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("ClassFieldInitializer", () => { const result = util.transpileAndExecute( diff --git a/test/unit/commandLineParser.spec.ts b/test/unit/commandLineParser.spec.ts index 8ec339310..2e4f8d1d2 100644 --- a/test/unit/commandLineParser.spec.ts +++ b/test/unit/commandLineParser.spec.ts @@ -1,5 +1,5 @@ import { findConfigFile, parseCommandLine, parseTsConfigString } from "../../src/CommandLineParser"; -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; test.each([ { args: [""], expected: LuaLibImportKind.Inline }, diff --git a/test/unit/compiler/configuration/mixed/index.spec.ts b/test/unit/compiler/configuration/mixed/index.spec.ts index 0ff2cec88..119a91365 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -1,9 +1,8 @@ import * as fs from "fs"; import * as path from "path"; import * as ts from "typescript"; - -import { CompilerOptions, LuaLibImportKind } from "../../../../../src/CompilerOptions"; import { parseCommandLine } from "../../../../../src/CommandLineParser"; +import { CompilerOptions, LuaLibImportKind } from "../../../../../src/CompilerOptions"; test("tsconfig.json mixed with cmd line args", () => { const rootPath = __dirname; diff --git a/test/unit/compiler/configuration/options.spec.ts b/test/unit/compiler/configuration/options.spec.ts index 9c6ba7306..47bf9bedf 100644 --- a/test/unit/compiler/configuration/options.spec.ts +++ b/test/unit/compiler/configuration/options.spec.ts @@ -1,5 +1,5 @@ +import { LuaLibImportKind, LuaTarget } from "../../../../src/CompilerOptions"; import * as util from "../../../util"; -import { LuaTarget, LuaLibImportKind } from "../../../../src/CompilerOptions"; test.each([LuaTarget.LuaJIT, "jit", "JiT"])("Options luaTarget case-insensitive (%p)", target => { const options = { luaTarget: target as LuaTarget }; diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index 982c24b19..6d79a37a8 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,7 +1,6 @@ -import { TranspileError } from "../../src/TranspileError"; import { LuaTarget } from "../../src/CompilerOptions"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test.each([{ inp: 0, expected: 0 }, { inp: 1, expected: 1 }])("if (%p)", ({ inp, expected }) => { const result = util.transpileAndExecute( diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index 443b28d6e..c32fb2214 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -1,7 +1,5 @@ -import * as util from "../util"; - -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("CustomCreate", () => { const luaHeader = `function Point2DCreate(x, y) diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index 93424e54f..f486b5e3f 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -1,7 +1,5 @@ -import * as util from "../util"; - -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("MetaExtension", () => { const tsHeader = ` diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index 2652de9ff..e0814988d 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -1,7 +1,5 @@ -import * as util from "../util"; - -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("Declare const enum", () => { const testCode = ` diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index e58d8553d..082e61eb9 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,7 +1,5 @@ -import * as util from "../util"; - -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("throwString", () => { const lua = util.transpileString(`throw "Some Error"`); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index ce4817e93..d5d653958 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,9 +1,7 @@ -import { TranspileError } from "../../src/TranspileError"; -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; - import * as ts from "typescript"; -import * as util from "../util"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test.each([ { input: "i++", lua: "i = i + 1;" }, diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index a5a0c9276..c165ca522 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("Arrow Function Expression", () => { const result = util.transpileAndExecute(`let add = (a, b) => a+b; return add(1,2);`); diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index e0b2ad143..5d5b204eb 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -1,7 +1,6 @@ import * as ts from "typescript"; -import { TranspileError } from "../../src/TranspileError"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("Var Hoisting", () => { const code = `foo = "foo"; diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index 7fab649c2..337e5676f 100644 --- a/test/unit/json.spec.ts +++ b/test/unit/json.spec.ts @@ -1,7 +1,6 @@ import { transpileString } from "../../src/Compiler"; -import { TranspileError } from "../../src/TranspileError"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test.each(["0", '""', "[]", '[1, "2", []]', '{ "a": "b" }', '{ "a": { "b": "c" } }'])( "JSON (%p)", diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 95ada5177..d87f019fd 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -1,8 +1,7 @@ import * as ts from "typescript"; -import { TranspileError } from "../../src/TranspileError"; import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("while (%p)", ({ inp, expected }) => { const result = util.transpileAndExecute( diff --git a/test/unit/lualib/inlining.spec.ts b/test/unit/lualib/inlining.spec.ts index ae54ebf42..f4a6e2b45 100644 --- a/test/unit/lualib/inlining.spec.ts +++ b/test/unit/lualib/inlining.spec.ts @@ -1,6 +1,5 @@ -import * as util from "../../util"; - import { LuaLibImportKind, LuaTarget } from "../../../src/CompilerOptions"; +import * as util from "../../util"; test("map constructor", () => { const result = util.transpileAndExecute(`let mymap = new Map(); return mymap.size;`, { diff --git a/test/unit/lualib/lualib.spec.ts b/test/unit/lualib/lualib.spec.ts index b6a0343b7..2fba27716 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -1,6 +1,4 @@ -import * as ts from "typescript"; import * as util from "../../util"; -import { LuaLibImportKind } from "../../../src/CompilerOptions"; test.each([{ inp: [0, 1, 2, 3], expected: [1, 2, 3, 4] }])("forEach (%p)", ({ inp, expected }) => { const result = util.transpileAndExecute( diff --git a/test/unit/modules.spec.ts b/test/unit/modules.spec.ts index e30842ef3..82e866f53 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -1,6 +1,6 @@ import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("defaultImport", () => { expect(() => { diff --git a/test/unit/require.spec.ts b/test/unit/require.spec.ts index 010c89abf..747ce7b7a 100644 --- a/test/unit/require.spec.ts +++ b/test/unit/require.spec.ts @@ -1,6 +1,4 @@ import * as util from "../util"; -import * as path from "path"; -import { CompilerOptions } from "../../src/CompilerOptions"; test.each([ { diff --git a/test/unit/spreadElement.spec.ts b/test/unit/spreadElement.spec.ts index 02b164ed1..3bb7ff981 100644 --- a/test/unit/spreadElement.spec.ts +++ b/test/unit/spreadElement.spec.ts @@ -1,4 +1,4 @@ -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; import * as util from "../util"; test.each([{ inp: [] }, { inp: [1, 2, 3] }, { inp: [1, "test", 3] }])( diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index 7c26c0825..2b7cd4362 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -1,6 +1,5 @@ -import { TranspileError } from "../../src/TranspileError"; -import * as util from "../util"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test("Unsuported string function", () => { expect(() => { diff --git a/test/unit/tshelper.spec.ts b/test/unit/tshelper.spec.ts index 85b6e98e0..ee314672c 100644 --- a/test/unit/tshelper.spec.ts +++ b/test/unit/tshelper.spec.ts @@ -1,9 +1,7 @@ -import { TSHelper as tsHelper } from "../../src/TSHelper"; - import * as ts from "typescript"; -import * as util from "../util"; - import { DecoratorKind } from "../../src/Decorator"; +import { TSHelper as tsHelper } from "../../src/TSHelper"; +import * as util from "../util"; enum TestEnum { testA = 1, diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 51cd065a8..108a79090 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -1,6 +1,5 @@ -import * as util from "../util"; -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; test.each(["0", "30", "30_000", "30.00"])("typeof number (%p)", inp => { const result = util.transpileAndExecute(`return typeof ${inp};`); From 56f6a17a25b1b9e17c34b4a065a7eea1e870424b Mon Sep 17 00:00:00 2001 From: ark120202 Date: Sun, 24 Mar 2019 23:14:30 +0500 Subject: [PATCH 10/24] Split assignments tests to improve parallel testing performance --- test/unit/assignments.spec.ts | 1274 ----------------- test/unit/assignments/assignments.spec.ts | 181 +++ .../functionExpressionTypeInference.spec.ts | 316 ++++ test/unit/assignments/functionPermutations.ts | 411 ++++++ .../invalidFunctionAssignments.spec.ts | 178 +++ .../validFunctionAssignments.spec.ts | 221 +++ 6 files changed, 1307 insertions(+), 1274 deletions(-) delete mode 100644 test/unit/assignments.spec.ts create mode 100644 test/unit/assignments/assignments.spec.ts create mode 100644 test/unit/assignments/functionExpressionTypeInference.spec.ts create mode 100644 test/unit/assignments/functionPermutations.ts create mode 100644 test/unit/assignments/invalidFunctionAssignments.spec.ts create mode 100644 test/unit/assignments/validFunctionAssignments.spec.ts diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts deleted file mode 100644 index bbc14eb6d..000000000 --- a/test/unit/assignments.spec.ts +++ /dev/null @@ -1,1274 +0,0 @@ -import * as ts from "typescript"; -import { TSTLErrors } from "../../src/TSTLErrors"; -import * as util from "../util"; - -interface TestFunction { - value: string; - definition?: string; -} - -const selfTestFunctions: TestFunction[] = [ - { - value: "selfFunc", - definition: `let selfFunc: {(this: any, s: string): string} = function(s) { return s; };`, - }, - { - value: "selfLambda", - definition: `let selfLambda: (this: any, s: string) => string = s => s;`, - }, - { - value: "anonFunc", - definition: `let anonFunc: {(s: string): string} = function(s) { return s; };`, - }, - { - value: "anonLambda", - definition: `let anonLambda: (s: string) => string = s => s;`, - }, - { - value: "methodClass.method", - definition: `class MethodClass { method(this: any, s: string): string { return s; } } - const methodClass = new MethodClass();`, - }, - { - value: "anonMethodClass.anonMethod", - definition: `class AnonMethodClass { anonMethod(s: string): string { return s; } } - const anonMethodClass = new AnonMethodClass();`, - }, - { - value: "funcPropClass.funcProp", - definition: `class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } - const funcPropClass = new FuncPropClass();`, - }, - { - value: "anonFuncPropClass.anonFuncProp", - definition: `class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } - const anonFuncPropClass = new AnonFuncPropClass();`, - }, - { - value: "StaticMethodClass.staticMethod", - definition: `class StaticMethodClass { - static staticMethod(this: any, s: string): string { return s; } - }`, - }, - { - value: "AnonStaticMethodClass.anonStaticMethod", - definition: `class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }`, - }, - { - value: "StaticFuncPropClass.staticFuncProp", - definition: `class StaticFuncPropClass { - static staticFuncProp: (this: any, s: string) => string = s => s; - }`, - }, - { - value: "AnonStaticFuncPropClass.anonStaticFuncProp", - definition: `class AnonStaticFuncPropClass { - static anonStaticFuncProp: (s: string) => string = s => s; - }`, - }, - { - value: "FuncNs.nsFunc", - definition: `namespace FuncNs { export function nsFunc(s: string) { return s; } }`, - }, - { - value: "FuncNestedNs.NestedNs.nestedNsFunc", - definition: `namespace FuncNestedNs { - export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } - }`, - }, - { - value: "LambdaNs.nsLambda", - definition: `namespace LambdaNs { - export let nsLambda: (s: string) => string = s => s; - }`, - }, - { - value: "LambdaNestedNs.NestedNs.nestedNsLambda", - definition: `namespace LambdaNestedNs { - export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } - }`, - }, - { - value: "methodInterface.method", - definition: `interface MethodInterface { method(this: any, s: string): string; } - const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }`, - }, - { - value: "anonMethodInterface.anonMethod", - definition: `interface AnonMethodInterface { anonMethod(s: string): string; } - const anonMethodInterface: AnonMethodInterface = { - anonMethod: function(this: any, s: string): string { return s; } - };`, - }, - { - value: "funcPropInterface.funcProp", - definition: `interface FuncPropInterface { funcProp: (this: any, s: string) => string; } - const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };`, - }, - { - value: "anonFuncPropInterface.anonFuncProp", - definition: `interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } - const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };`, - }, - { - value: "anonMethodClassInNoSelfNs.method", - definition: `/** @noSelf */ namespace AnonMethodClassInNoSelfNs { - export class MethodClass { - method(s: string): string { return s; } - } - } - const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();`, - }, - { - value: "anonMethodInterfaceInNoSelfNs.method", - definition: `/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { - export interface MethodInterface { - method(s: string): string; - } - } - const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { - method: function(s: string): string { return s; } - };`, - }, - { - value: "anonFunctionNestedInNoSelfClass", - definition: `/** @noSelf */ class AnonFunctionNestedInNoSelfClass { - method() { return function(s: string) { return s; } } - } - const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();`, - }, -]; - -const noSelfTestFunctions: TestFunction[] = [ - { - value: "voidFunc", - definition: `let voidFunc: {(this: void, s: string): string} = function(s) { return s; };`, - }, - { - value: "voidLambda", - definition: `let voidLambda: (this: void, s: string) => string = s => s;`, - }, - { - value: "voidMethodClass.voidMethod", - definition: `class VoidMethodClass { - voidMethod(this: void, s: string): string { return s; } - } - const voidMethodClass = new VoidMethodClass();`, - }, - { - value: "voidFuncPropClass.voidFuncProp", - definition: `class VoidFuncPropClass { - voidFuncProp: (this: void, s: string) => string = s => s; - } - const voidFuncPropClass = new VoidFuncPropClass();`, - }, - { - value: "StaticVoidMethodClass.staticVoidMethod", - definition: `class StaticVoidMethodClass { - static staticVoidMethod(this: void, s: string): string { return s; } - }`, - }, - { - value: "StaticVoidFuncPropClass.staticVoidFuncProp", - definition: `class StaticVoidFuncPropClass { - static staticVoidFuncProp: (this: void, s: string) => string = s => s; - }`, - }, - { - value: "NoSelfFuncNs.noSelfNsFunc", - definition: `/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }`, - }, - { - value: "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc", - definition: `/** @noSelf */ namespace NoSelfFuncNestedNs { - export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } - }`, - }, - { - value: "NoSelfLambdaNs.noSelfNsLambda", - definition: `/** @noSelf */ namespace NoSelfLambdaNs { - export let noSelfNsLambda: (s: string) => string = s => s; - }`, - }, - { - value: "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda", - definition: `/** @noSelf */ namespace NoSelfLambdaNestedNs { - export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } - }`, - }, - { - value: "noSelfMethodClass.noSelfMethod", - definition: `/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } - const noSelfMethodClass = new NoSelfMethodClass();`, - }, - { - value: "NoSelfStaticMethodClass.noSelfStaticMethod", - definition: `/** @noSelf */ class NoSelfStaticMethodClass { - static noSelfStaticMethod(s: string): string { return s; } - }`, - }, - { - value: "noSelfFuncPropClass.noSelfFuncProp", - definition: `/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } - const noSelfFuncPropClass = new NoSelfFuncPropClass();`, - }, - { - value: "NoSelfStaticFuncPropClass.noSelfStaticFuncProp", - definition: `/** @noSelf */ class NoSelfStaticFuncPropClass { - static noSelfStaticFuncProp: (s: string) => string = s => s; - }`, - }, - { - value: "voidMethodInterface.voidMethod", - definition: `interface VoidMethodInterface { - voidMethod(this: void, s: string): string; - } - const voidMethodInterface: VoidMethodInterface = { - voidMethod(this: void, s: string): string { return s; } - };`, - }, - { - value: "voidFuncPropInterface.voidFuncProp", - definition: `interface VoidFuncPropInterface { - voidFuncProp: (this: void, s: string) => string; - } - const voidFuncPropInterface: VoidFuncPropInterface = { - voidFuncProp: function(this: void, s: string): string { return s; } - };`, - }, - { - value: "noSelfMethodInterface.noSelfMethod", - definition: `/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } - const noSelfMethodInterface: NoSelfMethodInterface = { - noSelfMethod: function(s: string): string { return s; } - };`, - }, - { - value: "noSelfFuncPropInterface.noSelfFuncProp", - definition: `/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } - const noSelfFuncPropInterface: NoSelfFuncPropInterface = { - noSelfFuncProp: (s: string): string => s - };`, - }, - { - value: "noSelfMethodClassExpression.noSelfMethod", - definition: `/** @noSelf */ const NoSelfMethodClassExpression = class { - noSelfMethod(s: string): string { return s; } - } - const noSelfMethodClassExpression = new NoSelfMethodClassExpression();`, - }, - { - value: "anonFunctionNestedInClassInNoSelfNs", - definition: `/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { - export class AnonFunctionNestedInClass { - method() { return function(s: string) { return s; } } - } - } - const anonFunctionNestedInClassInNoSelfNs = - (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();`, - }, -]; - -const noSelfInFileTestFunctions: TestFunction[] = [ - { - value: "noSelfInFileFunc", - definition: `/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };`, - }, - { - value: "noSelfInFileLambda", - definition: `/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;`, - }, - { - value: "NoSelfInFileFuncNs.noSelfInFileNsFunc", - definition: `/** @noSelfInFile */ namespace NoSelfInFileFuncNs { - export function noSelfInFileNsFunc(s: string) { return s; } - }`, - }, - { - value: "NoSelfInFileLambdaNs.noSelfInFileNsLambda", - definition: `/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { - export let noSelfInFileNsLambda: (s: string) => string = s => s; - }`, - }, - { - value: "noSelfInFileFuncNestedInClass", - definition: `/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { - method() { return function(s: string) { return s; } } - } - const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();`, - }, -]; - -const anonTestFunctionExpressions: TestFunction[] = [ - { value: `s => s` }, - { value: `(s => s)` }, - { value: `function(s) { return s; }` }, - { value: `(function(s) { return s; })` }, -]; - -const selfTestFunctionExpressions: TestFunction[] = [ - { value: `function(this: any, s) { return s; }` }, - { value: `(function(this: any, s) { return s; })` }, -]; - -const noSelfTestFunctionExpressions: TestFunction[] = [ - { value: `function(this: void, s) { return s; }` }, - { value: `(function(this: void, s) { return s; })` }, -]; - -const anonTestFunctionType = "(s: string) => string"; -const selfTestFunctionType = "(this: any, s: string) => string"; -const noSelfTestFunctionType = "(this: void, s: string) => string"; - -type TestFunctionCast = [ - /*testFunction: */ TestFunction, - /*castedFunction: */ string, - /*isSelfConversion?: */ boolean? -]; -const validTestFunctionCasts: 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})`, - ], -]; -const invalidTestFunctionCasts: TestFunctionCast[] = [ - [noSelfTestFunctions[0], `<${anonTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], - [ - noSelfTestFunctions[0], - `(${noSelfTestFunctions[0].value}) as (${anonTestFunctionType})`, - false, - ], - [noSelfTestFunctions[0], `<${selfTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], - [ - noSelfTestFunctions[0], - `(${noSelfTestFunctions[0].value}) as (${selfTestFunctionType})`, - false, - ], - [ - noSelfInFileTestFunctions[0], - `<${selfTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`, - false, - ], - [ - noSelfInFileTestFunctions[0], - `(${noSelfInFileTestFunctions[0].value}) as (${selfTestFunctionType})`, - false, - ], - [selfTestFunctions[0], `<${noSelfTestFunctionType}>(${selfTestFunctions[0].value})`, true], - [selfTestFunctions[0], `(${selfTestFunctions[0].value}) as (${noSelfTestFunctionType})`, true], -]; - -type TestFunctionAssignment = [ - /*testFunction: */ TestFunction, - /*functionType: */ string, - /*isSelfConversion?: */ boolean? -]; -const validTestFunctionAssignments: 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]), - ...anonTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), - ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), - ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), - ...noSelfTestFunctionExpressions.map( - (f): TestFunctionAssignment => [f, noSelfTestFunctionType], - ), -]; -const invalidTestFunctionAssignments: TestFunctionAssignment[] = [ - ...selfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType, false]), - ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), - ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), - ...noSelfInFileTestFunctions.map( - (f): TestFunctionAssignment => [f, selfTestFunctionType, true], - ), - ...selfTestFunctionExpressions.map( - (f): TestFunctionAssignment => [f, noSelfTestFunctionType, false], - ), - ...noSelfTestFunctionExpressions.map( - (f): TestFunctionAssignment => [f, anonTestFunctionType, true], - ), - ...noSelfTestFunctionExpressions.map( - (f): TestFunctionAssignment => [f, selfTestFunctionType, true], - ), -]; - -test.each([ - { inp: `"abc"`, out: `"abc"` }, - { inp: "3", out: "3" }, - { inp: "[1,2,3]", out: "{1, 2, 3}" }, - { inp: "true", out: "true" }, - { inp: "false", out: "false" }, - { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, -])("Const assignment (%p)", ({ inp, out }) => { - const lua = util.transpileString(`const myvar = ${inp};`); - expect(lua).toBe(`local myvar = ${out};`); -}); - -test.each([ - { inp: `"abc"`, out: `"abc"` }, - { inp: "3", out: "3" }, - { inp: "[1,2,3]", out: "{1, 2, 3}" }, - { inp: "true", out: "true" }, - { inp: "false", out: "false" }, - { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, -])("Let assignment (%p)", ({ inp, out }) => { - const lua = util.transpileString(`let myvar = ${inp};`); - expect(lua).toBe(`local myvar = ${out};`); -}); - -test.each([ - { inp: `"abc"`, out: `"abc"` }, - { inp: "3", out: "3" }, - { inp: "[1,2,3]", out: "{1, 2, 3}" }, - { inp: "true", out: "true" }, - { inp: "false", out: "false" }, - { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, -])("Var assignment (%p)", ({ inp, out }) => { - const lua = util.transpileString(`var myvar = ${inp};`); - expect(lua).toBe(`myvar = ${out};`); -}); - -test.each(["var myvar;", "let myvar;", "const myvar = null;", "const myvar = undefined;"])( - "Null assignments (%p)", - declaration => { - const result = util.transpileAndExecute(declaration + " return myvar;"); - expect(result).toBe(undefined); - }, -); - -test.each([ - { input: ["a", "b"], values: ["e", "f"] }, - { input: ["a", "b"], values: ["e", "f", "g"] }, - { input: ["a", "b", "c"], values: ["e", "f", "g"] }, -])("Binding pattern assignment (%p)", ({ input, values }) => { - const pattern = input.join(","); - const initializer = values.map(v => `"${v}"`).join(","); - - const tsCode = `const [${pattern}] = [${initializer}]; return [${pattern}].join("-");`; - const result = util.transpileAndExecute(tsCode); - - expect(result).toBe(values.slice(0, input.length).join("-")); -}); - -test("Ellipsis binding pattern", () => { - expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrowExactError( - TSTLErrors.ForbiddenEllipsisDestruction(util.nodeStub), - ); -}); - -test("Tuple Assignment", () => { - const code = `function abc(): [number, number] { return [1, 2]; }; - let t: [number, number] = abc(); - return t[0] + t[1];`; - const result = util.transpileAndExecute(code); - expect(result).toBe(3); -}); - -test("TupleReturn assignment", () => { - const code = - `/** @tupleReturn */\n` + - `declare function abc(this: void): number[]\n` + - `let [a,b] = abc();`; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = abc();"); -}); - -test("TupleReturn Single assignment", () => { - const code = - `/** @tupleReturn */\n` + - `declare function abc(this: void): [number, string];\n` + - `let a = abc();` + - `a = abc();`; - - const lua = util.transpileString(code); - expect(lua).toBe("local a = ({abc()});\na = ({abc()});"); -}); - -test("TupleReturn interface assignment", () => { - const code = - `interface def {\n` + - `/** @tupleReturn */\n` + - `abc();\n` + - `} declare const jkl : def;\n` + - `let [a,b] = jkl.abc();`; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = jkl:abc();"); -}); - -test("TupleReturn namespace assignment", () => { - const code = - `declare namespace def {\n` + - `/** @tupleReturn */\n` + - `function abc(this: void) {}\n` + - `}\n` + - `let [a,b] = def.abc();`; - - const lua = util.transpileString(code); - expect(lua).toBe("local a, b = def.abc();"); -}); - -test("TupleReturn method assignment", () => { - const code = - `declare class def {\n` + - `/** @tupleReturn */\n` + - `abc() { return [1,2,3]; }\n` + - `} const jkl = new def();\n` + - `let [a,b] = jkl.abc();`; - - const lua = util.transpileString(code); - expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); -}); - -test("TupleReturn functional", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a;`; - - const result = util.transpileAndExecute(code); - - expect(result).toBe("a3"); -}); - -test("TupleReturn single", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length`; - - const result = util.transpileAndExecute(code); - - expect(result).toBe(2); -}); - -test("TupleReturn in expression", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0];`; - - const result = util.transpileAndExecute(code); - - expect(result).toBe("a3"); -}); - -test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( - "Keyword identifier error (%p)", - identifier => { - expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowExactError( - TSTLErrors.KeywordIdentifier(ts.createIdentifier(identifier)), - ); - }, -); - -test.each(validTestFunctionAssignments)( - "Valid function variable declaration (%p)", - (testFunction, functionType) => { - const code = `const fn: ${functionType} = ${testFunction.value}; - return fn("foobar");`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(validTestFunctionAssignments)( - "Valid function assignment (%p)", - (testFunction, functionType) => { - const code = `let fn: ${functionType}; - fn = ${testFunction.value}; - return fn("foobar");`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionAssignments)( - "Invalid function variable declaration (%p)", - (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - const fn: ${functionType} = ${testFunction.value};`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test.each(invalidTestFunctionAssignments)( - "Invalid function assignment (%p)", - (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - let fn: ${functionType}; - fn = ${testFunction.value};`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test.each(validTestFunctionCasts)( - "Valid function assignment with cast (%p)", - (testFunction, castedFunction) => { - const code = `let fn: typeof ${testFunction.value}; - fn = ${castedFunction}; - return fn("foobar");`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionCasts)( - "Invalid function assignment with cast (%p)", - (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - let fn: typeof ${testFunction.value}; - fn = ${castedFunction};`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test.each(validTestFunctionAssignments)( - "Valid function argument (%p)", - (testFunction, functionType) => { - const code = `function takesFunction(fn: ${functionType}) { - return fn("foobar"); - } - return takesFunction(${testFunction.value});`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionAssignments)( - "Invalid function argument (%p)", - (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: ${functionType}); - takesFunction(${testFunction.value});`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test("Valid lua lib function argument", () => { - const code = `let result = ""; - function foo(this: any, value: string) { result += value; } - const a = ['foo', 'bar']; - a.forEach(foo); - return result;`; - expect(util.transpileAndExecute(code)).toBe("foobar"); -}); - -test("Invalid lua lib function argument", () => { - const code = `declare function foo(this: void, value: string): void; - declare const a: string[]; - a.forEach(foo);`; - const err = TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "callbackfn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); -}); - -test.each(validTestFunctionCasts)( - "Valid function argument with cast (%p)", - (testFunction, castedFunction) => { - const code = `function takesFunction(fn: typeof ${testFunction.value}) { - return fn("foobar"); - } - return takesFunction(${castedFunction});`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionCasts)( - "Invalid function argument with cast (%p)", - (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: typeof ${testFunction.value}); - takesFunction(${castedFunction});`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -// TODO: Fix function expression inference with generic types. The following should work, but doesn't: -// function takesFunction string>(fn: T) { ... } -// takesFunction(s => s); // Error: cannot convert method to function -// @TestCases(validTestFunctionAssignments) // Use this instead of other TestCases when fixed -test.each([ - ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), - ...selfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), - ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), - ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), - ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), - ...noSelfTestFunctionExpressions.map( - (f): TestFunctionAssignment => [f, noSelfTestFunctionType], - ), -])("Valid function generic argument (%p)", (testFunction, functionType) => { - const code = `function takesFunction(fn: T) { - return fn("foobar"); - } - return takesFunction(${testFunction.value});`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); -}); - -test.each(invalidTestFunctionAssignments)( - "Invalid function generic argument (%p)", - (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: T); - takesFunction(${testFunction.value});`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test.each([ - ...anonTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), - ...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), - ...noSelfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]]), -])("Valid function expression argument with no signature (%p)", (testFunction, args) => { - const code = `const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { - return fn(...args); - } - return takesFunction(${testFunction.value}, ${args.join(", ")});`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); -}); - -test.each(validTestFunctionAssignments)( - "Valid function return (%p)", - (testFunction, functionType) => { - const code = `function returnsFunction(): ${functionType} { - return ${testFunction.value}; - } - const fn = returnsFunction(); - return fn("foobar");`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionAssignments)( - "Invalid function return (%p)", - (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - function returnsFunction(): ${functionType} { - return ${testFunction.value}; - }`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test.each(validTestFunctionCasts)( - "Valid function return with cast (%p)", - (testFunction, castedFunction) => { - const code = `function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - } - const fn = returnsFunction(); - return fn("foobar");`; - expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( - "foobar", - ); - }, -); - -test.each(invalidTestFunctionCasts)( - "Invalid function return with cast (%p)", - (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - }`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); - expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); - }, -); - -test("Interface method assignment", () => { - const code = `class Foo { - method(s: string): string { return s + "+method"; } - lambdaProp: (s: string) => string = s => s + "+lambdaProp"; - } - interface IFoo { - method: (s: string) => string; - lambdaProp(s: string): string; - } - const foo: IFoo = new Foo(); - return foo.method("foo") + "|" + foo.lambdaProp("bar");`; - const result = util.transpileAndExecute(code); - expect(result).toBe("foo+method|bar+lambdaProp"); -}); - -test("Valid function tuple assignment", () => { - const code = `interface Func { (this: void, s: string): string; } - function getTuple(): [number, Func] { return [1, s => s]; } - let [i, f]: [number, Func] = getTuple(); - return f("foo");`; - const result = util.transpileAndExecute(code); - expect(result).toBe("foo"); -}); - -test("Invalid function tuple assignment", () => { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Meth]; - let [i, f]: [number, Func] = getTuple();`; - expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub), - ); -}); - -test("Valid method tuple assignment", () => { - const code = `interface Foo { method(s: string): string; } - interface Meth { (this: Foo, s: string): string; } - let meth: Meth = s => s; - function getTuple(): [number, Meth] { return [1, meth]; } - let [i, f]: [number, Meth] = getTuple(); - let foo: Foo = {method: f}; - return foo.method("foo");`; - const result = util.transpileAndExecute(code); - expect(result).toBe("foo"); -}); - -test("Invalid method tuple assignment", () => { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Func]; - let [i, f]: [number, Meth] = getTuple();`; - expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub), - ); -}); - -test("Valid interface method assignment", () => { - const code = `interface A { fn(this: void, s: string): string; } - interface B { fn(this: void, s: string): string; } - const a: A = { fn(this: void, s) { return s; } }; - const b: B = a; - return b.fn("foo");`; - const result = util.transpileAndExecute(code); - expect(result).toBe("foo"); -}); - -test("Invalid interface method assignment", () => { - const code = `interface A { fn(s: string): string; } - interface B { fn(this: void, s: string): string; } - declare const a: A; - const b: B = a;`; - expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"), - ); -}); - -test.each([ - { assignType: "(this: any, s: string) => string", args: ["foo"], expectResult: "foobar" }, - { assignType: "{(this: any, s: string): string}", args: ["foo"], expectResult: "foobar" }, - { - assignType: "(this: any, s1: string, s2: string) => string", - args: ["foo", "baz"], - expectResult: "foobaz", - }, - { - assignType: "{(this: any, s1: string, s2: string): string}", - args: ["foo", "baz"], - expectResult: "foobaz", - }, -])("Valid function overload assignment (%p)", ({ assignType, args, expectResult }) => { - const code = `interface O { - (s1: string, s2: string): string; - (s: string): string; - } - const o: O = (s1: string, s2?: string) => s1 + (s2 || "bar"); - let f: ${assignType} = o; - return f(${args.map(a => '"' + a + '"').join(", ")});`; - const result = util.transpileAndExecute(code); - expect(result).toBe(expectResult); -}); - -test.each([ - "(this: void, s: string) => string", - "(this: void, s1: string, s2: string) => string", - "{(this: void, s: string): string}", - "{(this: any, s1: string, s2: string): string}", -])("Invalid function overload assignment (%p)", assignType => { - const code = `interface O { - (this: any, s1: string, s2: string): string; - (this: void, s: string): string; - } - declare const o: O; - let f: ${assignType} = o;`; - expect(() => util.transpileString(code)).toThrowExactError( - TSTLErrors.UnsupportedOverloadAssignment(util.nodeStub), - ); -}); - -test.each(["noSelf", "noSelfInFile"])("noSelf function method argument (%p)", noSelfTag => { - const header = `/** @${noSelfTag} */ namespace NS { - export class C { - method(fn: (s: string) => string) { return fn("foo"); } - } - } - function foo(this: void, s: string) { return s; }`; - const code = `const c = new NS.C(); - return c.method(foo);`; - expect(util.transpileAndExecute(code, undefined, undefined, header, false)).toBe("foo"); -}); - -test.each([ - "(this: void, s: string) => string", - "(this: any, s: string) => string", - "(s: string) => string", -])("Function expression type inference in binary operator (%p)", funcType => { - const header = `declare const undefinedFunc: ${funcType};`; - const code = `let func: ${funcType} = s => s; - func = undefinedFunc || (s => s); - return func("foo");`; - expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); -}); - -test.each(["s => s", "(s => s)", "function(s) { return s; }", "(function(s) { return s; })"])( - "Function expression type inference in class (%p)", - funcExp => { - const code = `class Foo { - func: (this: void, s: string) => string = ${funcExp}; - method: (s: string) => string = ${funcExp}; - static staticFunc: (this: void, s: string) => string = ${funcExp}; - static staticMethod: (s: string) => string = ${funcExp}; - } - const foo = new Foo(); - return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d");`; - expect(util.transpileAndExecute(code)).toBe("abcd"); - }, -); - -test.each([ - { assignTo: "const foo: Foo", funcExp: "s => s" }, - { assignTo: "const foo: Foo", funcExp: "(s => s)" }, - { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, - { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, - { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, - { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, - { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, - { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, -])("Function expression type inference in object literal (%p)", ({ assignTo, funcExp }) => { - const code = `interface Foo { - func(this: void, s: string): string; - method(this: this, s: string): string; - } - ${assignTo} = {func: ${funcExp}, method: ${funcExp}}; - return foo.method("foo") + foo.func("bar");`; - expect(util.transpileAndExecute(code)).toBe("foobar"); -}); - -test("Function expression type inference in object literal assigned to narrower type", () => { - const code = `let foo: {} = {bar: s => s}; - return (foo as {bar: (a: any) => any}).bar("foobar");`; - expect(util.transpileAndExecute(code)).toBe("foobar"); -}); - -test.each([ - { assignTo: "const foo: Foo", funcExp: "s => s" }, - { assignTo: "const foo: Foo", funcExp: "(s => s)" }, - { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, - { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, - { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, - { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, - { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, - { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, -])( - "Function expression type inference in object literal (generic key) (%p)", - ({ assignTo, funcExp }) => { - const code = `interface Foo { - [f: string]: (this: void, s: string) => string; - } - ${assignTo} = {func: ${funcExp}}; - return foo.func("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); - }, -); - -test.each([ - { - assignTo: "const funcs: [Func, Method]", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "s => s", - }, - { - assignTo: "const funcs: [Func, Method]", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "(s => s)", - }, - { - assignTo: "const funcs: [Func, Method]", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "function(s) { return s; }", - }, - { - assignTo: "const funcs: [Func, Method]", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "(function(s) { return s; })", - }, - { - assignTo: "let funcs: [Func, Method]; funcs", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "s => s", - }, - { - assignTo: "let funcs: [Func, Method]; funcs", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "(s => s)", - }, - { - assignTo: "let funcs: [Func, Method]; funcs", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "function(s) { return s; }", - }, - { - assignTo: "let funcs: [Func, Method]; funcs", - func: "funcs[0]", - method: "funcs[1]", - funcExp: "(function(s) { return s; })", - }, - { - assignTo: "const [func, meth]: [Func, Method]", - func: "func", - method: "meth", - funcExp: "s => s", - }, - { - assignTo: "const [func, meth]: [Func, Method]", - func: "func", - method: "meth", - funcExp: "(s => s)", - }, - { - assignTo: "const [func, meth]: [Func, Method]", - func: "func", - method: "meth", - funcExp: "function(s) { return s; }", - }, - { - assignTo: "const [func, meth]: [Func, Method]", - func: "func", - method: "meth", - funcExp: "(function(s) { return s; })", - }, - { - assignTo: "let func: Func; let meth: Method; [func, meth]", - func: "func", - method: "meth", - funcExp: "s => s", - }, - { - assignTo: "let func: Func; let meth: Method; [func, meth]", - func: "func", - method: "meth", - funcExp: "(s => s)", - }, - { - assignTo: "let func: Func; let meth: Method; [func, meth]", - func: "func", - method: "meth", - funcExp: "function(s) { return s; }", - }, - { - assignTo: "let func: Func; let meth: Method; [func, meth]", - func: "func", - method: "meth", - funcExp: "(function(s) { return s; })", - }, -])("Function expression type inference in tuple (%p)", ({ assignTo, func, method, funcExp }) => { - const code = `interface Foo { - method(s: string): string; - } - interface Func { - (this: void, s: string): string; - } - interface Method { - (this: Foo, s: string): string; - } - ${assignTo} = [${funcExp}, ${funcExp}]; - const foo: Foo = {method: ${method}}; - return foo.method("foo") + ${func}("bar");`; - expect(util.transpileAndExecute(code)).toBe("foobar"); -}); - -test.each([ - { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "s => s" }, - { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "(s => s)" }, - { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "function(s) { return s; }" }, - { - assignTo: "const meths: Method[]", - method: "meths[0]", - funcExp: "(function(s) { return s; })", - }, - { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "s => s" }, - { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "(s => s)" }, - { - assignTo: "let meths: Method[]; meths", - method: "meths[0]", - funcExp: "function(s) { return s; }", - }, - { - assignTo: "let meths: Method[]; meths", - method: "meths[0]", - funcExp: "(function(s) { return s; })", - }, - { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "s => s" }, - { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(s => s)" }, - { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "function(s) { return s; }" }, - { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(function(s) { return s; })" }, - { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "s => s" }, - { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "(s => s)" }, - { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "function(s) { return s; }" }, - { - assignTo: "let meth: Method; [meth]", - method: "meth", - funcExp: "(function(s) { return s; })", - }, -])("Function expression type inference in array (%p)", ({ assignTo, method, funcExp }) => { - const code = `interface Foo { - method(s: string): string; - } - interface Method { - (this: Foo, s: string): string; - } - ${assignTo} = [${funcExp}]; - const foo: Foo = {method: ${method}}; - return foo.method("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test.each([ - { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, - { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, - { funcType: "(s: string) => string", funcExp: "s => s" }, - { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, -])("Function expression type inference in union (%p)", ({ funcType, funcExp }) => { - const code = `type U = string | number | (${funcType}); - const u: U = ${funcExp}; - return (u as ${funcType})("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test.each([ - { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, - { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, - { funcType: "(s: string) => string", funcExp: "s => s" }, - { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, -])("Function expression type inference in union tuple (%p)", ({ funcType, funcExp }) => { - const code = `interface I { callback: ${funcType}; } - let a: I[] | number = [{ callback: ${funcExp} }]; - return a[0].callback("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test.each([ - { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, - { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, - { funcType: "(s: string) => string", funcExp: "s => s" }, - { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, -])("Function expression type inference in as cast (%p)", ({ funcType, funcExp }) => { - const code = `const fn: ${funcType} = (${funcExp}) as (${funcType}); - return fn("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test.each([ - { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, - { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, - { funcType: "(s: string) => string", funcExp: "s => s" }, - { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, -])("Function expression type inference in type assertion (%p)", ({ funcType, funcExp }) => { - const code = `const fn: ${funcType} = <${funcType}>(${funcExp}); - return fn("foo");`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test.each([ - { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, - { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, - { funcType: "(s: string) => string", funcExp: "s => s" }, - { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, - { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, -])("Function expression type inference in constructor (%p)", ({ funcType, funcExp }) => { - const code = `class C { - result: string; - constructor(fn: (s: string) => string) { this.result = fn("foo"); } - } - const c = new C(s => s); - return c.result;`; - expect(util.transpileAndExecute(code)).toBe("foo"); -}); - -test("String table access", () => { - const code = `const dict : {[key:string]:any} = {}; - dict["a b"] = 3; - return dict["a b"];`; - const result = util.transpileAndExecute(code); - expect(result).toBe(3); -}); diff --git a/test/unit/assignments/assignments.spec.ts b/test/unit/assignments/assignments.spec.ts new file mode 100644 index 000000000..aeaf6de4e --- /dev/null +++ b/test/unit/assignments/assignments.spec.ts @@ -0,0 +1,181 @@ +import * as ts from "typescript"; +import { TSTLErrors } from "../../../src/TSTLErrors"; +import * as util from "../../util"; + +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Const assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`const myvar = ${inp};`); + expect(lua).toBe(`local myvar = ${out};`); +}); + +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Let assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`let myvar = ${inp};`); + expect(lua).toBe(`local myvar = ${out};`); +}); + +test.each([ + { inp: `"abc"`, out: `"abc"` }, + { inp: "3", out: "3" }, + { inp: "[1,2,3]", out: "{1, 2, 3}" }, + { inp: "true", out: "true" }, + { inp: "false", out: "false" }, + { inp: `{a:3,b:"4"}`, out: `{a = 3, b = "4"}` }, +])("Var assignment (%p)", ({ inp, out }) => { + const lua = util.transpileString(`var myvar = ${inp};`); + expect(lua).toBe(`myvar = ${out};`); +}); + +test.each(["var myvar;", "let myvar;", "const myvar = null;", "const myvar = undefined;"])( + "Null assignments (%p)", + declaration => { + const result = util.transpileAndExecute(declaration + " return myvar;"); + expect(result).toBe(undefined); + }, +); + +test.each([ + { input: ["a", "b"], values: ["e", "f"] }, + { input: ["a", "b"], values: ["e", "f", "g"] }, + { input: ["a", "b", "c"], values: ["e", "f", "g"] }, +])("Binding pattern assignment (%p)", ({ input, values }) => { + const pattern = input.join(","); + const initializer = values.map(v => `"${v}"`).join(","); + + const tsCode = `const [${pattern}] = [${initializer}]; return [${pattern}].join("-");`; + const result = util.transpileAndExecute(tsCode); + + expect(result).toBe(values.slice(0, input.length).join("-")); +}); + +test("Ellipsis binding pattern", () => { + expect(() => util.transpileString("let [a,b,...c] = [1,2,3];")).toThrowExactError( + TSTLErrors.ForbiddenEllipsisDestruction(util.nodeStub), + ); +}); + +test("Tuple Assignment", () => { + const code = `function abc(): [number, number] { return [1, 2]; }; + let t: [number, number] = abc(); + return t[0] + t[1];`; + const result = util.transpileAndExecute(code); + expect(result).toBe(3); +}); + +test("TupleReturn assignment", () => { + const code = + `/** @tupleReturn */\n` + + `declare function abc(this: void): number[]\n` + + `let [a,b] = abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = abc();"); +}); + +test("TupleReturn Single assignment", () => { + const code = + `/** @tupleReturn */\n` + + `declare function abc(this: void): [number, string];\n` + + `let a = abc();` + + `a = abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a = ({abc()});\na = ({abc()});"); +}); + +test("TupleReturn interface assignment", () => { + const code = + `interface def {\n` + + `/** @tupleReturn */\n` + + `abc();\n` + + `} declare const jkl : def;\n` + + `let [a,b] = jkl.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = jkl:abc();"); +}); + +test("TupleReturn namespace assignment", () => { + const code = + `declare namespace def {\n` + + `/** @tupleReturn */\n` + + `function abc(this: void) {}\n` + + `}\n` + + `let [a,b] = def.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local a, b = def.abc();"); +}); + +test("TupleReturn method assignment", () => { + const code = + `declare class def {\n` + + `/** @tupleReturn */\n` + + `abc() { return [1,2,3]; }\n` + + `} const jkl = new def();\n` + + `let [a,b] = jkl.abc();`; + + const lua = util.transpileString(code); + expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); +}); + +test("TupleReturn functional", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const [a, b] = abc(); + return b + a;`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe("a3"); +}); + +test("TupleReturn single", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const res = abc(); + return res.length`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe(2); +}); + +test("TupleReturn in expression", () => { + const code = `/** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + return abc()[1] + abc()[0];`; + + const result = util.transpileAndExecute(code); + + expect(result).toBe("a3"); +}); + +test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( + "Keyword identifier error (%p)", + identifier => { + expect(() => util.transpileString(`const ${identifier} = 3;`)).toThrowExactError( + TSTLErrors.KeywordIdentifier(ts.createIdentifier(identifier)), + ); + }, +); + +test("String table access", () => { + const code = `const dict : {[key:string]:any} = {}; + dict["a b"] = 3; + return dict["a b"];`; + const result = util.transpileAndExecute(code); + expect(result).toBe(3); +}); diff --git a/test/unit/assignments/functionExpressionTypeInference.spec.ts b/test/unit/assignments/functionExpressionTypeInference.spec.ts new file mode 100644 index 000000000..7b9d7fb0a --- /dev/null +++ b/test/unit/assignments/functionExpressionTypeInference.spec.ts @@ -0,0 +1,316 @@ +import * as util from "../../util"; + +test.each(["noSelf", "noSelfInFile"])("noSelf function method argument (%p)", noSelfTag => { + const header = `/** @${noSelfTag} */ namespace NS { + export class C { + method(fn: (s: string) => string) { return fn("foo"); } + } + } + function foo(this: void, s: string) { return s; }`; + const code = `const c = new NS.C(); + return c.method(foo);`; + expect(util.transpileAndExecute(code, undefined, undefined, header, false)).toBe("foo"); +}); + +test.each([ + "(this: void, s: string) => string", + "(this: any, s: string) => string", + "(s: string) => string", +])("Function expression type inference in binary operator (%p)", funcType => { + const header = `declare const undefinedFunc: ${funcType};`; + const code = `let func: ${funcType} = s => s; + func = undefinedFunc || (s => s); + return func("foo");`; + expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); +}); + +test.each(["s => s", "(s => s)", "function(s) { return s; }", "(function(s) { return s; })"])( + "Function expression type inference in class (%p)", + funcExp => { + const code = `class Foo { + func: (this: void, s: string) => string = ${funcExp}; + method: (s: string) => string = ${funcExp}; + static staticFunc: (this: void, s: string) => string = ${funcExp}; + static staticMethod: (s: string) => string = ${funcExp}; + } + const foo = new Foo(); + return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d");`; + expect(util.transpileAndExecute(code)).toBe("abcd"); + }, +); + +test.each([ + { assignTo: "const foo: Foo", funcExp: "s => s" }, + { assignTo: "const foo: Foo", funcExp: "(s => s)" }, + { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, + { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, + { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, + { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, + { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, + { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, +])("Function expression type inference in object literal (%p)", ({ assignTo, funcExp }) => { + const code = `interface Foo { + func(this: void, s: string): string; + method(this: this, s: string): string; + } + ${assignTo} = {func: ${funcExp}, method: ${funcExp}}; + return foo.method("foo") + foo.func("bar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test("Function expression type inference in object literal assigned to narrower type", () => { + const code = `let foo: {} = {bar: s => s}; + return (foo as {bar: (a: any) => any}).bar("foobar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test.each([ + { assignTo: "const foo: Foo", funcExp: "s => s" }, + { assignTo: "const foo: Foo", funcExp: "(s => s)" }, + { assignTo: "const foo: Foo", funcExp: "function(s) { return s; }" }, + { assignTo: "const foo: Foo", funcExp: "(function(s) { return s; })" }, + { assignTo: "let foo: Foo; foo", funcExp: "s => s" }, + { assignTo: "let foo: Foo; foo", funcExp: "(s => s)" }, + { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, + { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, +])( + "Function expression type inference in object literal (generic key) (%p)", + ({ assignTo, funcExp }) => { + const code = `interface Foo { + [f: string]: (this: void, s: string) => string; + } + ${assignTo} = {func: ${funcExp}}; + return foo.func("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); + }, +); + +test.each([ + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "s => s", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(s => s)", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "const funcs: [Func, Method]", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "s => s", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(s => s)", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let funcs: [Func, Method]; funcs", + func: "funcs[0]", + method: "funcs[1]", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "s => s", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "(s => s)", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "const [func, meth]: [Func, Method]", + func: "func", + method: "meth", + funcExp: "(function(s) { return s; })", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "s => s", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "(s => s)", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let func: Func; let meth: Method; [func, meth]", + func: "func", + method: "meth", + funcExp: "(function(s) { return s; })", + }, +])("Function expression type inference in tuple (%p)", ({ assignTo, func, method, funcExp }) => { + const code = `interface Foo { + method(s: string): string; + } + interface Func { + (this: void, s: string): string; + } + interface Method { + (this: Foo, s: string): string; + } + ${assignTo} = [${funcExp}, ${funcExp}]; + const foo: Foo = {method: ${method}}; + return foo.method("foo") + ${func}("bar");`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test.each([ + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "s => s" }, + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "(s => s)" }, + { assignTo: "const meths: Method[]", method: "meths[0]", funcExp: "function(s) { return s; }" }, + { + assignTo: "const meths: Method[]", + method: "meths[0]", + funcExp: "(function(s) { return s; })", + }, + { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "s => s" }, + { assignTo: "let meths: Method[]; meths", method: "meths[0]", funcExp: "(s => s)" }, + { + assignTo: "let meths: Method[]; meths", + method: "meths[0]", + funcExp: "function(s) { return s; }", + }, + { + assignTo: "let meths: Method[]; meths", + method: "meths[0]", + funcExp: "(function(s) { return s; })", + }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "s => s" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(s => s)" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "function(s) { return s; }" }, + { assignTo: "const [meth]: Method[]", method: "meth", funcExp: "(function(s) { return s; })" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "s => s" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "(s => s)" }, + { assignTo: "let meth: Method; [meth]", method: "meth", funcExp: "function(s) { return s; }" }, + { + assignTo: "let meth: Method; [meth]", + method: "meth", + funcExp: "(function(s) { return s; })", + }, +])("Function expression type inference in array (%p)", ({ assignTo, method, funcExp }) => { + const code = `interface Foo { + method(s: string): string; + } + interface Method { + (this: Foo, s: string): string; + } + ${assignTo} = [${funcExp}]; + const foo: Foo = {method: ${method}}; + return foo.method("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in union (%p)", ({ funcType, funcExp }) => { + const code = `type U = string | number | (${funcType}); + const u: U = ${funcExp}; + return (u as ${funcType})("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in union tuple (%p)", ({ funcType, funcExp }) => { + const code = `interface I { callback: ${funcType}; } + let a: I[] | number = [{ callback: ${funcExp} }]; + return a[0].callback("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in as cast (%p)", ({ funcType, funcExp }) => { + const code = `const fn: ${funcType} = (${funcExp}) as (${funcType}); + return fn("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in type assertion (%p)", ({ funcType, funcExp }) => { + const code = `const fn: ${funcType} = <${funcType}>(${funcExp}); + return fn("foo");`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); + +test.each([ + { funcType: "(this: void, s: string) => string", funcExp: "s => s" }, + { funcType: "(this: any, s: string) => string", funcExp: "s => s" }, + { funcType: "(s: string) => string", funcExp: "s => s" }, + { funcType: "(this: void, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, + { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, +])("Function expression type inference in constructor (%p)", ({ funcType, funcExp }) => { + const code = `class C { + result: string; + constructor(fn: (s: string) => string) { this.result = fn("foo"); } + } + const c = new C(s => s); + return c.result;`; + expect(util.transpileAndExecute(code)).toBe("foo"); +}); diff --git a/test/unit/assignments/functionPermutations.ts b/test/unit/assignments/functionPermutations.ts new file mode 100644 index 000000000..45fbd52f1 --- /dev/null +++ b/test/unit/assignments/functionPermutations.ts @@ -0,0 +1,411 @@ +export interface TestFunction { + value: string; + definition?: string; +} + +export const selfTestFunctions: TestFunction[] = [ + { + value: "selfFunc", + definition: `let selfFunc: {(this: any, s: string): string} = function(s) { return s; };`, + }, + { + value: "selfLambda", + definition: `let selfLambda: (this: any, s: string) => string = s => s;`, + }, + { + value: "anonFunc", + definition: `let anonFunc: {(s: string): string} = function(s) { return s; };`, + }, + { + value: "anonLambda", + definition: `let anonLambda: (s: string) => string = s => s;`, + }, + { + value: "methodClass.method", + definition: `class MethodClass { method(this: any, s: string): string { return s; } } + const methodClass = new MethodClass();`, + }, + { + value: "anonMethodClass.anonMethod", + definition: `class AnonMethodClass { anonMethod(s: string): string { return s; } } + const anonMethodClass = new AnonMethodClass();`, + }, + { + value: "funcPropClass.funcProp", + definition: `class FuncPropClass { funcProp: (this: any, s: string) => string = s => s; } + const funcPropClass = new FuncPropClass();`, + }, + { + value: "anonFuncPropClass.anonFuncProp", + definition: `class AnonFuncPropClass { anonFuncProp: (s: string) => string = s => s; } + const anonFuncPropClass = new AnonFuncPropClass();`, + }, + { + value: "StaticMethodClass.staticMethod", + definition: `class StaticMethodClass { + static staticMethod(this: any, s: string): string { return s; } + }`, + }, + { + value: "AnonStaticMethodClass.anonStaticMethod", + definition: `class AnonStaticMethodClass { static anonStaticMethod(s: string): string { return s; } }`, + }, + { + value: "StaticFuncPropClass.staticFuncProp", + definition: `class StaticFuncPropClass { + static staticFuncProp: (this: any, s: string) => string = s => s; + }`, + }, + { + value: "AnonStaticFuncPropClass.anonStaticFuncProp", + definition: `class AnonStaticFuncPropClass { + static anonStaticFuncProp: (s: string) => string = s => s; + }`, + }, + { + value: "FuncNs.nsFunc", + definition: `namespace FuncNs { export function nsFunc(s: string) { return s; } }`, + }, + { + value: "FuncNestedNs.NestedNs.nestedNsFunc", + definition: `namespace FuncNestedNs { + export namespace NestedNs { export function nestedNsFunc(s: string) { return s; } } + }`, + }, + { + value: "LambdaNs.nsLambda", + definition: `namespace LambdaNs { + export let nsLambda: (s: string) => string = s => s; + }`, + }, + { + value: "LambdaNestedNs.NestedNs.nestedNsLambda", + definition: `namespace LambdaNestedNs { + export namespace NestedNs { export let nestedNsLambda: (s: string) => string = s => s } + }`, + }, + { + value: "methodInterface.method", + definition: `interface MethodInterface { method(this: any, s: string): string; } + const methodInterface: MethodInterface = { method: function(this: any, s: string): string { return s; } }`, + }, + { + value: "anonMethodInterface.anonMethod", + definition: `interface AnonMethodInterface { anonMethod(s: string): string; } + const anonMethodInterface: AnonMethodInterface = { + anonMethod: function(this: any, s: string): string { return s; } + };`, + }, + { + value: "funcPropInterface.funcProp", + definition: `interface FuncPropInterface { funcProp: (this: any, s: string) => string; } + const funcPropInterface: FuncPropInterface = { funcProp: function(this: any, s: string) { return s; } };`, + }, + { + value: "anonFuncPropInterface.anonFuncProp", + definition: `interface AnonFuncPropInterface { anonFuncProp: (s: string) => string; } + const anonFuncPropInterface: AnonFuncPropInterface = { anonFuncProp: (s: string): string => s };`, + }, + { + value: "anonMethodClassInNoSelfNs.method", + definition: `/** @noSelf */ namespace AnonMethodClassInNoSelfNs { + export class MethodClass { + method(s: string): string { return s; } + } + } + const anonMethodClassInNoSelfNs = new AnonMethodClassInNoSelfNs.MethodClass();`, + }, + { + value: "anonMethodInterfaceInNoSelfNs.method", + definition: `/** @noSelf */ namespace AnonMethodInterfaceInNoSelfNs { + export interface MethodInterface { + method(s: string): string; + } + } + const anonMethodInterfaceInNoSelfNs: AnonMethodInterfaceInNoSelfNs.MethodInterface = { + method: function(s: string): string { return s; } + };`, + }, + { + value: "anonFunctionNestedInNoSelfClass", + definition: `/** @noSelf */ class AnonFunctionNestedInNoSelfClass { + method() { return function(s: string) { return s; } } + } + const anonFunctionNestedInNoSelfClass = (new AnonFunctionNestedInNoSelfClass).method();`, + }, +]; + +export const noSelfTestFunctions: TestFunction[] = [ + { + value: "voidFunc", + definition: `let voidFunc: {(this: void, s: string): string} = function(s) { return s; };`, + }, + { + value: "voidLambda", + definition: `let voidLambda: (this: void, s: string) => string = s => s;`, + }, + { + value: "voidMethodClass.voidMethod", + definition: `class VoidMethodClass { + voidMethod(this: void, s: string): string { return s; } + } + const voidMethodClass = new VoidMethodClass();`, + }, + { + value: "voidFuncPropClass.voidFuncProp", + definition: `class VoidFuncPropClass { + voidFuncProp: (this: void, s: string) => string = s => s; + } + const voidFuncPropClass = new VoidFuncPropClass();`, + }, + { + value: "StaticVoidMethodClass.staticVoidMethod", + definition: `class StaticVoidMethodClass { + static staticVoidMethod(this: void, s: string): string { return s; } + }`, + }, + { + value: "StaticVoidFuncPropClass.staticVoidFuncProp", + definition: `class StaticVoidFuncPropClass { + static staticVoidFuncProp: (this: void, s: string) => string = s => s; + }`, + }, + { + value: "NoSelfFuncNs.noSelfNsFunc", + definition: `/** @noSelf */ namespace NoSelfFuncNs { export function noSelfNsFunc(s: string) { return s; } }`, + }, + { + value: "NoSelfFuncNestedNs.NestedNs.noSelfNestedNsFunc", + definition: `/** @noSelf */ namespace NoSelfFuncNestedNs { + export namespace NestedNs { export function noSelfNestedNsFunc(s: string) { return s; } } + }`, + }, + { + value: "NoSelfLambdaNs.noSelfNsLambda", + definition: `/** @noSelf */ namespace NoSelfLambdaNs { + export let noSelfNsLambda: (s: string) => string = s => s; + }`, + }, + { + value: "NoSelfLambdaNestedNs.NestedNs.noSelfNestedNsLambda", + definition: `/** @noSelf */ namespace NoSelfLambdaNestedNs { + export namespace NestedNs { export let noSelfNestedNsLambda: (s: string) => string = s => s } + }`, + }, + { + value: "noSelfMethodClass.noSelfMethod", + definition: `/** @noSelf */ class NoSelfMethodClass { noSelfMethod(s: string): string { return s; } } + const noSelfMethodClass = new NoSelfMethodClass();`, + }, + { + value: "NoSelfStaticMethodClass.noSelfStaticMethod", + definition: `/** @noSelf */ class NoSelfStaticMethodClass { + static noSelfStaticMethod(s: string): string { return s; } + }`, + }, + { + value: "noSelfFuncPropClass.noSelfFuncProp", + definition: `/** @noSelf */ class NoSelfFuncPropClass { noSelfFuncProp: (s: string) => string = s => s; } + const noSelfFuncPropClass = new NoSelfFuncPropClass();`, + }, + { + value: "NoSelfStaticFuncPropClass.noSelfStaticFuncProp", + definition: `/** @noSelf */ class NoSelfStaticFuncPropClass { + static noSelfStaticFuncProp: (s: string) => string = s => s; + }`, + }, + { + value: "voidMethodInterface.voidMethod", + definition: `interface VoidMethodInterface { + voidMethod(this: void, s: string): string; + } + const voidMethodInterface: VoidMethodInterface = { + voidMethod(this: void, s: string): string { return s; } + };`, + }, + { + value: "voidFuncPropInterface.voidFuncProp", + definition: `interface VoidFuncPropInterface { + voidFuncProp: (this: void, s: string) => string; + } + const voidFuncPropInterface: VoidFuncPropInterface = { + voidFuncProp: function(this: void, s: string): string { return s; } + };`, + }, + { + value: "noSelfMethodInterface.noSelfMethod", + definition: `/** @noSelf */ interface NoSelfMethodInterface { noSelfMethod(s: string): string; } + const noSelfMethodInterface: NoSelfMethodInterface = { + noSelfMethod: function(s: string): string { return s; } + };`, + }, + { + value: "noSelfFuncPropInterface.noSelfFuncProp", + definition: `/** @noSelf */ interface NoSelfFuncPropInterface { noSelfFuncProp(s: string): string; } + const noSelfFuncPropInterface: NoSelfFuncPropInterface = { + noSelfFuncProp: (s: string): string => s + };`, + }, + { + value: "noSelfMethodClassExpression.noSelfMethod", + definition: `/** @noSelf */ const NoSelfMethodClassExpression = class { + noSelfMethod(s: string): string { return s; } + } + const noSelfMethodClassExpression = new NoSelfMethodClassExpression();`, + }, + { + value: "anonFunctionNestedInClassInNoSelfNs", + definition: `/** @noSelf */ namespace AnonFunctionNestedInClassInNoSelfNs { + export class AnonFunctionNestedInClass { + method() { return function(s: string) { return s; } } + } + } + const anonFunctionNestedInClassInNoSelfNs = + (new AnonFunctionNestedInClassInNoSelfNs.AnonFunctionNestedInClass).method();`, + }, +]; + +const noSelfInFileTestFunctions: TestFunction[] = [ + { + value: "noSelfInFileFunc", + definition: `/** @noSelfInFile */ let noSelfInFileFunc: {(s: string): string} = function(s) { return s; };`, + }, + { + value: "noSelfInFileLambda", + definition: `/** @noSelfInFile */ let noSelfInFileLambda: (s: string) => string = s => s;`, + }, + { + value: "NoSelfInFileFuncNs.noSelfInFileNsFunc", + definition: `/** @noSelfInFile */ namespace NoSelfInFileFuncNs { + export function noSelfInFileNsFunc(s: string) { return s; } + }`, + }, + { + value: "NoSelfInFileLambdaNs.noSelfInFileNsLambda", + definition: `/** @noSelfInFile */ namespace NoSelfInFileLambdaNs { + export let noSelfInFileNsLambda: (s: string) => string = s => s; + }`, + }, + { + value: "noSelfInFileFuncNestedInClass", + definition: `/** @noSelfInFile */ class NoSelfInFileFuncNestedInClass { + method() { return function(s: string) { return s; } } + } + const noSelfInFileFuncNestedInClass = (new NoSelfInFileFuncNestedInClass).method();`, + }, +]; + +export const anonTestFunctionExpressions: TestFunction[] = [ + { value: `s => s` }, + { value: `(s => s)` }, + { value: `function(s) { return s; }` }, + { value: `(function(s) { return s; })` }, +]; + +export const selfTestFunctionExpressions: TestFunction[] = [ + { value: `function(this: any, s) { return s; }` }, + { value: `(function(this: any, s) { return s; })` }, +]; + +export const noSelfTestFunctionExpressions: TestFunction[] = [ + { value: `function(this: void, s) { return s; }` }, + { value: `(function(this: void, s) { return s; })` }, +]; + +export const anonTestFunctionType = "(s: string) => string"; +export const selfTestFunctionType = "(this: any, s: string) => string"; +export const noSelfTestFunctionType = "(this: void, s: string) => string"; + +type TestFunctionCast = [ + /*testFunction: */ TestFunction, + /*castedFunction: */ string, + /*isSelfConversion?: */ boolean? +]; +export const validTestFunctionCasts: 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 invalidTestFunctionCasts: TestFunctionCast[] = [ + [noSelfTestFunctions[0], `<${anonTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], + [ + noSelfTestFunctions[0], + `(${noSelfTestFunctions[0].value}) as (${anonTestFunctionType})`, + false, + ], + [noSelfTestFunctions[0], `<${selfTestFunctionType}>(${noSelfTestFunctions[0].value})`, false], + [ + noSelfTestFunctions[0], + `(${noSelfTestFunctions[0].value}) as (${selfTestFunctionType})`, + false, + ], + [ + noSelfInFileTestFunctions[0], + `<${selfTestFunctionType}>(${noSelfInFileTestFunctions[0].value})`, + false, + ], + [ + noSelfInFileTestFunctions[0], + `(${noSelfInFileTestFunctions[0].value}) as (${selfTestFunctionType})`, + false, + ], + [selfTestFunctions[0], `<${noSelfTestFunctionType}>(${selfTestFunctions[0].value})`, true], + [selfTestFunctions[0], `(${selfTestFunctions[0].value}) as (${noSelfTestFunctionType})`, true], +]; + +export type TestFunctionAssignment = [ + /*testFunction: */ TestFunction, + /*functionType: */ string, + /*isSelfConversion?: */ boolean? +]; +export const validTestFunctionAssignments: 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]), + ...anonTestFunctionExpressions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType], + ), +]; +export const invalidTestFunctionAssignments: TestFunctionAssignment[] = [ + ...selfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType, false]), + ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType, true]), + ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType, true]), + ...noSelfInFileTestFunctions.map( + (f): TestFunctionAssignment => [f, selfTestFunctionType, true], + ), + ...selfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType, false], + ), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, anonTestFunctionType, true], + ), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, selfTestFunctionType, true], + ), +]; diff --git a/test/unit/assignments/invalidFunctionAssignments.spec.ts b/test/unit/assignments/invalidFunctionAssignments.spec.ts new file mode 100644 index 000000000..a7484349e --- /dev/null +++ b/test/unit/assignments/invalidFunctionAssignments.spec.ts @@ -0,0 +1,178 @@ +import { TSTLErrors } from "../../../src/TSTLErrors"; +import * as util from "../../util"; +import { invalidTestFunctionAssignments, invalidTestFunctionCasts } from "./functionPermutations"; + +test.each(invalidTestFunctionAssignments)( + "Invalid function variable declaration (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + const fn: ${functionType} = ${testFunction.value};`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function assignment (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + let fn: ${functionType}; + fn = ${testFunction.value};`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionCasts)( + "Invalid function assignment with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + let fn: typeof ${testFunction.value}; + fn = ${castedFunction};`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function argument (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: ${functionType}); + takesFunction(${testFunction.value});`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test("Invalid lua lib function argument", () => { + const code = `declare function foo(this: void, value: string): void; + declare const a: string[]; + a.forEach(foo);`; + const err = TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "callbackfn"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); +}); + +test.each(invalidTestFunctionCasts)( + "Invalid function argument with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: typeof ${testFunction.value}); + takesFunction(${castedFunction});`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function generic argument (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + declare function takesFunction(fn: T); + takesFunction(${testFunction.value});`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionAssignments)( + "Invalid function return (%p)", + (testFunction, functionType, isSelfConversion) => { + const code = `${testFunction.definition || ""} + function returnsFunction(): ${functionType} { + return ${testFunction.value}; + }`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test.each(invalidTestFunctionCasts)( + "Invalid function return with cast (%p)", + (testFunction, castedFunction, isSelfConversion) => { + const code = `${testFunction.definition || ""} + function returnsFunction(): typeof ${testFunction.value} { + return ${castedFunction}; + }`; + const err = isSelfConversion + ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) + : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); + expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); + }, +); + +test("Interface method assignment", () => { + const code = `class Foo { + method(s: string): string { return s + "+method"; } + lambdaProp: (s: string) => string = s => s + "+lambdaProp"; + } + interface IFoo { + method: (s: string) => string; + lambdaProp(s: string): string; + } + const foo: IFoo = new Foo(); + return foo.method("foo") + "|" + foo.lambdaProp("bar");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo+method|bar+lambdaProp"); +}); + +test("Invalid function tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Meth]; + let [i, f]: [number, Func] = getTuple();`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub), + ); +}); + +test("Invalid method tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Func]; + let [i, f]: [number, Meth] = getTuple();`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub), + ); +}); + +test("Invalid interface method assignment", () => { + const code = `interface A { fn(s: string): string; } + interface B { fn(this: void, s: string): string; } + declare const a: A; + const b: B = a;`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"), + ); +}); + +test.each([ + "(this: void, s: string) => string", + "(this: void, s1: string, s2: string) => string", + "{(this: void, s: string): string}", + "{(this: any, s1: string, s2: string): string}", +])("Invalid function overload assignment (%p)", assignType => { + const code = `interface O { + (this: any, s1: string, s2: string): string; + (this: void, s: string): string; + } + declare const o: O; + let f: ${assignType} = o;`; + expect(() => util.transpileString(code)).toThrowExactError( + TSTLErrors.UnsupportedOverloadAssignment(util.nodeStub), + ); +}); diff --git a/test/unit/assignments/validFunctionAssignments.spec.ts b/test/unit/assignments/validFunctionAssignments.spec.ts new file mode 100644 index 000000000..a4e3501de --- /dev/null +++ b/test/unit/assignments/validFunctionAssignments.spec.ts @@ -0,0 +1,221 @@ +import * as util from "../../util"; +import { + validTestFunctionAssignments, + validTestFunctionCasts, + selfTestFunctions, + noSelfTestFunctions, + TestFunctionAssignment, + selfTestFunctionExpressions, + noSelfTestFunctionExpressions, + selfTestFunctionType, + anonTestFunctionType, + noSelfTestFunctionType, + anonTestFunctionExpressions, + TestFunction, +} from "./functionPermutations"; + +test.each(validTestFunctionAssignments)( + "Valid function variable declaration (%p)", + (testFunction, functionType) => { + const code = `const fn: ${functionType} = ${testFunction.value}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(validTestFunctionAssignments)( + "Valid function assignment (%p)", + (testFunction, functionType) => { + const code = `let fn: ${functionType}; + fn = ${testFunction.value}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(validTestFunctionCasts)( + "Valid function assignment with cast (%p)", + (testFunction, castedFunction) => { + const code = `let fn: typeof ${testFunction.value}; + fn = ${castedFunction}; + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(validTestFunctionAssignments)( + "Valid function argument (%p)", + (testFunction, functionType) => { + const code = `function takesFunction(fn: ${functionType}) { + return fn("foobar"); + } + return takesFunction(${testFunction.value});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test("Valid lua lib function argument", () => { + const code = `let result = ""; + function foo(this: any, value: string) { result += value; } + const a = ['foo', 'bar']; + a.forEach(foo); + return result;`; + expect(util.transpileAndExecute(code)).toBe("foobar"); +}); + +test.each(validTestFunctionCasts)( + "Valid function argument with cast (%p)", + (testFunction, castedFunction) => { + const code = `function takesFunction(fn: typeof ${testFunction.value}) { + return fn("foobar"); + } + return takesFunction(${castedFunction});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each([ + // TODO: Fix function expression inference with generic types. The following should work, but doesn't: + // function takesFunction string>(fn: T) { ... } + // takesFunction(s => s); // Error: cannot convert method to function + // ...validTestFunctionAssignments - Use this instead of other cases when fixed + ...selfTestFunctions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), + ...selfTestFunctions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), + ...noSelfTestFunctions.map((f): TestFunctionAssignment => [f, noSelfTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, anonTestFunctionType]), + ...selfTestFunctionExpressions.map((f): TestFunctionAssignment => [f, selfTestFunctionType]), + ...noSelfTestFunctionExpressions.map( + (f): TestFunctionAssignment => [f, noSelfTestFunctionType], + ), +])("Valid function generic argument (%p)", (testFunction, functionType) => { + const code = `function takesFunction(fn: T) { + return fn("foobar"); + } + return takesFunction(${testFunction.value});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); +}); + +test.each([ + ...anonTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), + ...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), + ...noSelfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]]), +])("Valid function expression argument with no signature (%p)", (testFunction, args) => { + const code = `const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { + return fn(...args); + } + return takesFunction(${testFunction.value}, ${args.join(", ")});`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); +}); + +test.each(validTestFunctionAssignments)( + "Valid function return (%p)", + (testFunction, functionType) => { + const code = `function returnsFunction(): ${functionType} { + return ${testFunction.value}; + } + const fn = returnsFunction(); + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test.each(validTestFunctionCasts)( + "Valid function return with cast (%p)", + (testFunction, castedFunction) => { + const code = `function returnsFunction(): typeof ${testFunction.value} { + return ${castedFunction}; + } + const fn = returnsFunction(); + return fn("foobar");`; + expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( + "foobar", + ); + }, +); + +test("Interface method assignment", () => { + const code = `class Foo { + method(s: string): string { return s + "+method"; } + lambdaProp: (s: string) => string = s => s + "+lambdaProp"; + } + interface IFoo { + method: (s: string) => string; + lambdaProp(s: string): string; + } + const foo: IFoo = new Foo(); + return foo.method("foo") + "|" + foo.lambdaProp("bar");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo+method|bar+lambdaProp"); +}); + +test("Valid function tuple assignment", () => { + const code = `interface Func { (this: void, s: string): string; } + function getTuple(): [number, Func] { return [1, s => s]; } + let [i, f]: [number, Func] = getTuple(); + return f("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Valid method tuple assignment", () => { + const code = `interface Foo { method(s: string): string; } + interface Meth { (this: Foo, s: string): string; } + let meth: Meth = s => s; + function getTuple(): [number, Meth] { return [1, meth]; } + let [i, f]: [number, Meth] = getTuple(); + let foo: Foo = {method: f}; + return foo.method("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test("Valid interface method assignment", () => { + const code = `interface A { fn(this: void, s: string): string; } + interface B { fn(this: void, s: string): string; } + const a: A = { fn(this: void, s) { return s; } }; + const b: B = a; + return b.fn("foo");`; + const result = util.transpileAndExecute(code); + expect(result).toBe("foo"); +}); + +test.each([ + { assignType: "(this: any, s: string) => string", args: ["foo"], expectResult: "foobar" }, + { assignType: "{(this: any, s: string): string}", args: ["foo"], expectResult: "foobar" }, + { + assignType: "(this: any, s1: string, s2: string) => string", + args: ["foo", "baz"], + expectResult: "foobaz", + }, + { + assignType: "{(this: any, s1: string, s2: string): string}", + args: ["foo", "baz"], + expectResult: "foobaz", + }, +])("Valid function overload assignment (%p)", ({ assignType, args, expectResult }) => { + const code = `interface O { + (s1: string, s2: string): string; + (s: string): string; + } + const o: O = (s1: string, s2?: string) => s1 + (s2 || "bar"); + let f: ${assignType} = o; + return f(${args.map(a => '"' + a + '"').join(", ")});`; + const result = util.transpileAndExecute(code); + expect(result).toBe(expectResult); +}); From 500f0828dc4995db0fc2a589424dd79bcd745a17 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 02:58:04 +0500 Subject: [PATCH 11/24] Add skipLibCheck flag to tests --- test/compiler/outfile.spec.ts | 2 ++ test/compiler/projects/baseurl/tsconfig.json | 3 ++- test/compiler/projects/basic/tsconfig.json | 3 ++- test/compiler/projects/watchmode/tsconfig.json | 3 ++- test/compiler/watchmode.spec.ts | 8 +++++++- test/util.ts | 3 ++- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/test/compiler/outfile.spec.ts b/test/compiler/outfile.spec.ts index 03ca23d9d..e82e7341b 100644 --- a/test/compiler/outfile.spec.ts +++ b/test/compiler/outfile.spec.ts @@ -22,6 +22,7 @@ test("Outfile absoulte path", () => { compile([ "--types", "node", + "--skipLibCheck", "--outFile", outFileAbsPath, path.join(__dirname, "./testfiles/out_file.ts"), @@ -34,6 +35,7 @@ test("Outfile relative path", () => { compile([ "--types", "node", + "--skipLibCheck", "--outDir", __dirname, "--outFile", diff --git a/test/compiler/projects/baseurl/tsconfig.json b/test/compiler/projects/baseurl/tsconfig.json index 8a0c35a68..299ae7cf8 100644 --- a/test/compiler/projects/baseurl/tsconfig.json +++ b/test/compiler/projects/baseurl/tsconfig.json @@ -4,6 +4,7 @@ "outDir": "./out_dir", "rootDir": ".", "baseUrl": "./test_src/test_lib", - "types": [] + "types": [], + "skipLibCheck": true } } diff --git a/test/compiler/projects/basic/tsconfig.json b/test/compiler/projects/basic/tsconfig.json index 40e0fb248..ec7262ddf 100644 --- a/test/compiler/projects/basic/tsconfig.json +++ b/test/compiler/projects/basic/tsconfig.json @@ -1,6 +1,7 @@ { "luaTarget": "JIT", "compilerOptions": { - "types": [] + "types": [], + "skipLibCheck": true } } diff --git a/test/compiler/projects/watchmode/tsconfig.json b/test/compiler/projects/watchmode/tsconfig.json index 40e0fb248..ec7262ddf 100644 --- a/test/compiler/projects/watchmode/tsconfig.json +++ b/test/compiler/projects/watchmode/tsconfig.json @@ -1,6 +1,7 @@ { "luaTarget": "JIT", "compilerOptions": { - "types": [] + "types": [], + "skipLibCheck": true } } diff --git a/test/compiler/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index 35be54c8f..2d695f698 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -23,7 +23,13 @@ function waitForFileExists(filePath: string): Promise { test.each([ { - args: ["-w", "--types", "node", path.join(__dirname, "./testfiles/watch.ts")], + args: [ + "--types", + "node", + "--skipLibCheck", + "-w", + path.join(__dirname, "./testfiles/watch.ts"), + ], fileToChange: path.join(__dirname, "./testfiles/watch.ts"), }, { diff --git a/test/util.ts b/test/util.ts index 3330aa39f..6f399a4e5 100644 --- a/test/util.ts +++ b/test/util.ts @@ -61,6 +61,8 @@ export function transpileString( { luaLibImport: LuaLibImportKind.Require, luaTarget: LuaTarget.Lua53, + noHeader: true, + skipLibCheck: true, target: ts.ScriptTarget.ESNext, lib: [ "lib.es2015.d.ts", @@ -69,7 +71,6 @@ export function transpileString( "lib.es2018.d.ts", "lib.esnext.d.ts", ], - noHeader: true, ...options, }, ignoreDiagnostics, From ca38b953db48a3a8b017cc0b7ac1ab3c412ccbb0 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 03:15:08 +0500 Subject: [PATCH 12/24] Inline lualib by default in tests --- test/translation/builder.spec.ts | 9 ++++++--- test/util.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/translation/builder.spec.ts b/test/translation/builder.spec.ts index e116b42ea..fb13a3fff 100644 --- a/test/translation/builder.spec.ts +++ b/test/translation/builder.spec.ts @@ -1,6 +1,7 @@ import * as fs from "fs"; import * as path from "path"; import * as util from "../util"; +import { LuaLibImportKind } from "../../src/CompilerOptions"; const files: Array<{ ts: string; lua: string }> = []; const fileContents: { [key: string]: Buffer } = {}; @@ -37,7 +38,9 @@ function BufferToTestString(b: Buffer): string { } test.each(files)("Transformation Tests (%p)", ({ ts, lua }) => { - expect(util.transpileString(BufferToTestString(fileContents[ts]))).toEqual( - BufferToTestString(fileContents[lua]), - ); + expect( + util.transpileString(BufferToTestString(fileContents[ts]), { + luaLibImport: LuaLibImportKind.Require, + }), + ).toEqual(BufferToTestString(fileContents[lua])); }); diff --git a/test/util.ts b/test/util.ts index 6f399a4e5..0e63f8fdd 100644 --- a/test/util.ts +++ b/test/util.ts @@ -59,7 +59,7 @@ export function transpileString( return compilerTranspileString( str, { - luaLibImport: LuaLibImportKind.Require, + luaLibImport: LuaLibImportKind.Inline, luaTarget: LuaTarget.Lua53, noHeader: true, skipLibCheck: true, From 637534fc912eab1535d3e2d2dc7105530fe234f0 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 03:37:57 +0500 Subject: [PATCH 13/24] Remove test-fast script --- package-lock.json | 10 ---------- package.json | 2 -- test/util.ts | 6 +----- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index e9985dd62..861f7a478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1411,16 +1411,6 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "cross-env": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", - "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.5", - "is-windows": "^1.0.0" - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", diff --git a/package.json b/package.json index 10ab70633..6df31f201 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "build": "tsc -p tsconfig.json && npm run build-lualib", "build-lualib": "ts-node ./build_lualib.ts", "test": "jest", - "test-fast": "cross-env JEST_IGNORE_DIAGNOSTICS=true jest", "lint": "npm run lint:tslint && npm run lint:prettier", "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", "lint:tslint": "tslint -p . && tslint -p test && tslint src/lualib/*.ts", @@ -62,7 +61,6 @@ "@types/glob": "^5.0.35", "@types/jest": "^24.0.11", "@types/node": "^9.6.23", - "cross-env": "^5.2.0", "fengari": "^0.1.2", "glob": "^7.1.2", "jest": "^24.5.0", diff --git a/test/util.ts b/test/util.ts index 0e63f8fdd..477424b24 100644 --- a/test/util.ts +++ b/test/util.ts @@ -52,10 +52,6 @@ export function transpileString( ignoreDiagnostics = true, filePath = "file.ts", ): string { - if (!ignoreDiagnostics) { - ignoreDiagnostics = Boolean(process.env.JEST_IGNORE_DIAGNOSTICS); - } - return compilerTranspileString( str, { @@ -129,7 +125,7 @@ export function transpileAndExecute( compilerOptions?: CompilerOptions, luaHeader?: string, tsHeader?: string, - ignoreDiagnostics = process.argv[2] === "--ignoreDiagnostics", + ignoreDiagnostics = false, ): any { const wrappedTsString = `${tsHeader ? tsHeader : ""} declare function JSONStringify(this: void, p: any): string; From 082cba3d45cb809df0ccdf934b15e3bfe3e605f0 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 03:41:25 +0500 Subject: [PATCH 14/24] Remove ignoreDiagnostics option from transpileAndExecute --- .../functionExpressionTypeInference.spec.ts | 2 +- test/unit/lualib/weakMap.spec.ts | 18 +++++++++--------- test/unit/lualib/weakSet.spec.ts | 18 +++++++++--------- test/util.ts | 3 +-- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/test/unit/assignments/functionExpressionTypeInference.spec.ts b/test/unit/assignments/functionExpressionTypeInference.spec.ts index 7b9d7fb0a..17eb9ab02 100644 --- a/test/unit/assignments/functionExpressionTypeInference.spec.ts +++ b/test/unit/assignments/functionExpressionTypeInference.spec.ts @@ -9,7 +9,7 @@ test.each(["noSelf", "noSelfInFile"])("noSelf function method argument (%p)", no function foo(this: void, s: string) { return s; }`; const code = `const c = new NS.C(); return c.method(foo);`; - expect(util.transpileAndExecute(code, undefined, undefined, header, false)).toBe("foo"); + expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); }); test.each([ diff --git a/test/unit/lualib/weakMap.spec.ts b/test/unit/lualib/weakMap.spec.ts index af22dd96b..51b5df8d8 100644 --- a/test/unit/lualib/weakMap.spec.ts +++ b/test/unit/lualib/weakMap.spec.ts @@ -110,13 +110,13 @@ test("weakMap set", () => { expect(value).toBe(5); }); -test("weakMap has no map features", () => { - const transpileAndExecute = (tsStr: string) => - util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); - expect(transpileAndExecute(`return new WeakMap().size`)).toBe(undefined); - expect(() => transpileAndExecute(`new WeakMap().clear()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakMap().keys()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakMap().values()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakMap().entries()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakMap().forEach(() => {})`)).toThrow(); +test("weakMap has no map features (size)", () => { + expect(util.transpileAndExecute(`return (new WeakMap() as any).size`)).toBe(undefined); }); + +test.each(["clear()", "keys()", "values()", "entries()", "forEach(() => {})"])( + "weakMap has no map features (%p)", + call => { + expect(() => util.transpileAndExecute(`(new WeakMap() as any).${call}`)).toThrow(); + }, +); diff --git a/test/unit/lualib/weakSet.spec.ts b/test/unit/lualib/weakSet.spec.ts index 95089000e..dd2e7df01 100644 --- a/test/unit/lualib/weakSet.spec.ts +++ b/test/unit/lualib/weakSet.spec.ts @@ -65,13 +65,13 @@ test("weakSet delete", () => { expect(contains).toBe(true); }); -test("weakSet has no set features", () => { - const transpileAndExecute = (tsStr: string) => - util.transpileAndExecute(tsStr, undefined, undefined, undefined, true); - expect(transpileAndExecute(`return new WeakSet().size`)).toBe(undefined); - expect(() => transpileAndExecute(`new WeakSet().clear()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakSet().keys()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakSet().values()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakSet().entries()`)).toThrow(); - expect(() => transpileAndExecute(`new WeakSet().forEach(() => {})`)).toThrow(); +test("weakSet has no set features (size)", () => { + expect(util.transpileAndExecute(`return (new WeakSet() as any).size`)).toBe(undefined); }); + +test.each(["clear()", "keys()", "values()", "entries()", "forEach(() => {})"])( + "weakSet has no set features (%p)", + call => { + expect(() => util.transpileAndExecute(`(new WeakSet() as any).${call}`)).toThrow(); + }, +); diff --git a/test/util.ts b/test/util.ts index 477424b24..73d338434 100644 --- a/test/util.ts +++ b/test/util.ts @@ -125,14 +125,13 @@ export function transpileAndExecute( compilerOptions?: CompilerOptions, luaHeader?: string, tsHeader?: string, - ignoreDiagnostics = false, ): any { const wrappedTsString = `${tsHeader ? tsHeader : ""} declare function JSONStringify(this: void, p: any): string; function __runTest(this: void): any {${tsStr}}`; const lua = `${luaHeader ? luaHeader : ""} - ${transpileString(wrappedTsString, compilerOptions, ignoreDiagnostics)} + ${transpileString(wrappedTsString, compilerOptions, false)} return __runTest();`; return executeLua(lua); From 0c330c5b8cd2da22d8467e42889a31045cf7e967 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 04:22:04 +0500 Subject: [PATCH 15/24] Remove @ts-check from jest config file --- jest.config.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jest.config.js b/jest.config.js index f55d00c5c..8afb70bd0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,8 +1,7 @@ -// @ts-check const isCI = require("is-ci"); /** @type {Partial} */ -const config = { +module.exports = { testMatch: ["**/test/**/*.spec.ts"], collectCoverageFrom: ["/src/**/*", "!/src/lualib/**/*"], watchPathIgnorePatterns: ["/watch\\.ts$"], @@ -17,5 +16,3 @@ const config = { }, }, }; - -module.exports = config; From ba7419a9fedc2690da005eb50762714e0697d51b Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 04:23:51 +0500 Subject: [PATCH 16/24] Add (%p) to set size test name --- test/unit/lualib/set.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/lualib/set.spec.ts b/test/unit/lualib/set.spec.ts index 1dcdb92c0..1fce6ceb7 100644 --- a/test/unit/lualib/set.spec.ts +++ b/test/unit/lualib/set.spec.ts @@ -125,6 +125,6 @@ test.each([ { code: `let m = new Set([1, 2]); return m.size;`, expected: 2 }, { code: `let m = new Set([1, 2]); m.clear(); return m.size;`, expected: 0 }, { code: `let m = new Set([1, 2]); m.delete(2); return m.size;`, expected: 1 }, -])("set size", ({ code, expected }) => { +])("set size (%p)", ({ code, expected }) => { expect(util.transpileAndExecute(code)).toBe(expected); }); From 1a3a65037aa0bf8ca9d9ef571acba62af6651970 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Mon, 25 Mar 2019 10:02:18 +0500 Subject: [PATCH 17/24] Format some code literals --- test/unit/accessors.spec.ts | 168 ++++++++---- test/unit/array.spec.ts | 12 +- test/unit/assignmentDestructuring.spec.ts | 6 +- test/unit/assignments/assignments.spec.ts | 103 ++++---- .../functionExpressionTypeInference.spec.ts | 102 +++++--- .../invalidFunctionAssignments.spec.ts | 138 ++++++---- .../validFunctionAssignments.spec.ts | 60 +++-- test/unit/bindingpatterns.spec.ts | 18 +- test/unit/class.spec.ts | 36 ++- test/unit/declarations.spec.ts | 18 +- test/unit/decoratorCustomConstructor.spec.ts | 19 +- test/unit/decoratorMetaExtension.spec.ts | 15 +- test/unit/enum.spec.ts | 14 +- test/unit/error.spec.ts | 48 ++-- test/unit/expressions.spec.ts | 101 ++++---- test/unit/functions.spec.ts | 244 ++++++++++-------- test/unit/hoisting.spec.ts | 102 +++++--- test/unit/lualib/lualib.spec.ts | 6 +- test/unit/lualib/weakSet.spec.ts | 6 +- test/unit/modules.spec.ts | 6 +- test/unit/tshelper.spec.ts | 30 ++- test/unit/tuples.spec.ts | 36 ++- test/unit/typechecking.spec.ts | 26 +- 23 files changed, 779 insertions(+), 535 deletions(-) diff --git a/test/unit/accessors.spec.ts b/test/unit/accessors.spec.ts index a29505278..fd63233df 100644 --- a/test/unit/accessors.spec.ts +++ b/test/unit/accessors.spec.ts @@ -1,28 +1,33 @@ import * as util from "../util"; test("get accessor", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } } const f = new Foo(); - return f.foo;`; + return f.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("get accessor in base class", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } } class Bar extends Foo {} const b = new Bar(); - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("get accessor override", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; foo = "foo"; } @@ -30,12 +35,14 @@ test("get accessor override", () => { get foo() { return this._foo + "bar"; } } const b = new Bar(); - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("get accessor overridden", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } } @@ -43,12 +50,14 @@ test("get accessor overridden", () => { foo = "bar"; } const b = new Bar(); - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("get accessor override accessor", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } } @@ -57,12 +66,14 @@ test("get accessor override accessor", () => { get foo() { return this._bar; } } const b = new Bar(); - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("get accessor from interface", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } } @@ -70,35 +81,41 @@ test("get accessor from interface", () => { readonly foo: string; } const b: Bar = new Foo(); - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("set accessor", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; set foo(val: string) { this._foo = val; } } const f = new Foo(); f.foo = "bar" - return f._foo;`; + return f._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("set accessor in base class", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; set foo(val: string) { this._foo = val; } } class Bar extends Foo {} const b = new Bar(); b.foo = "bar" - return b._foo;`; + return b._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("set accessor override", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; foo = "foo"; } @@ -107,12 +124,14 @@ test("set accessor override", () => { } const b = new Bar(); b.foo = "bar" - return b._foo;`; + return b._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("set accessor overridden", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "baz"; set foo(val: string) { this._foo = val; } } @@ -122,12 +141,14 @@ test("set accessor overridden", () => { const b = new Bar(); const fooOriginal = b._foo; b.foo = "bar" - return fooOriginal + b._foo;`; + return fooOriginal + b._foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("set accessor override accessor", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; set foo(val: string) { this._foo = "foo"; } } @@ -136,12 +157,14 @@ test("set accessor override accessor", () => { } const b = new Bar(); b.foo = "bar" - return b._foo;`; + return b._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("set accessor from interface", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; set foo(val: string) { this._foo = val; } } @@ -151,12 +174,14 @@ test("set accessor from interface", () => { } const b: Bar = new Foo(); b.foo = "bar" - return b._foo;`; + return b._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("get/set accessors", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } set foo(val: string) { this._foo = val; } @@ -164,12 +189,14 @@ test("get/set accessors", () => { const f = new Foo(); const fooOriginal = f.foo; f.foo = "bar"; - return fooOriginal + f.foo;`; + return fooOriginal + f.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("get/set accessors in base class", () => { - const code = `class Foo { + const code = ` + class Foo { _foo = "foo"; get foo() { return this._foo; } set foo(val: string) { this._foo = val; } @@ -178,55 +205,65 @@ test("get/set accessors in base class", () => { const b = new Bar(); const fooOriginal = b.foo; b.foo = "bar" - return fooOriginal + b.foo;`; + return fooOriginal + b.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("static get accessor", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } } - return Foo.foo;`; + return Foo.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("static get accessor in base class", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } } class Bar extends Foo {} - return Bar.foo;`; + return Bar.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("static get accessor override", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static foo = "foo"; } class Bar extends Foo { static get foo() { return this._foo + "bar"; } } - return Bar.foo;`; + return Bar.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("static get accessor overridden", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } } class Bar extends Foo { static foo = "bar"; } - return Bar.foo;`; + return Bar.foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static get accessor override accessor", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } } @@ -234,12 +271,14 @@ test("static get accessor override accessor", () => { static _bar = "bar"; static get foo() { return this._bar; } } - return Bar.foo;`; + return Bar.foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static get accessor from interface", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } } @@ -247,33 +286,39 @@ test("static get accessor from interface", () => { readonly foo: string; } const b: Bar = Foo; - return b.foo;`; + return b.foo; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); test("static set accessor", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static set foo(val: string) { this._foo = val; } } Foo.foo = "bar" - return Foo._foo;`; + return Foo._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static set accessor in base class", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static set foo(val: string) { this._foo = val; } } class Bar extends Foo {} Bar.foo = "bar" - return Bar._foo;`; + return Bar._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static set accessor override", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static foo = "foo"; } @@ -281,12 +326,14 @@ test("static set accessor override", () => { static set foo(val: string) { this._foo = val; } } Bar.foo = "bar" - return Bar._foo;`; + return Bar._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static set accessor overridden", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "baz"; static set foo(val: string) { this._foo = val; } } @@ -295,12 +342,14 @@ test("static set accessor overridden", () => { } const fooOriginal = Bar._foo; Bar.foo = "bar" - return fooOriginal + Bar._foo;`; + return fooOriginal + Bar._foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("static set accessor override accessor", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static set foo(val: string) { this._foo = "foo"; } } @@ -308,12 +357,14 @@ test("static set accessor override accessor", () => { static set foo(val: string) { this._foo = val; } } Bar.foo = "bar" - return Bar._foo;`; + return Bar._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static set accessor from interface", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static set foo(val: string) { this._foo = val; } } @@ -323,24 +374,28 @@ test("static set accessor from interface", () => { } const b: Bar = Foo; b.foo = "bar" - return b._foo;`; + return b._foo; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); test("static get/set accessors", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } static set foo(val: string) { this._foo = val; } } const fooOriginal = Foo.foo; Foo.foo = "bar"; - return fooOriginal + Foo.foo;`; + return fooOriginal + Foo.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("static get/set accessors in base class", () => { - const code = `class Foo { + const code = ` + class Foo { static _foo = "foo"; static get foo() { return this._foo; } static set foo(val: string) { this._foo = val; } @@ -348,6 +403,7 @@ test("static get/set accessors in base class", () => { class Bar extends Foo {} const fooOriginal = Bar.foo; Bar.foo = "bar" - return fooOriginal + Bar.foo;`; + return fooOriginal + Bar.foo; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); diff --git a/test/unit/array.spec.ts b/test/unit/array.spec.ts index 98e98e730..85dcb5dcb 100644 --- a/test/unit/array.spec.ts +++ b/test/unit/array.spec.ts @@ -77,11 +77,13 @@ test.each([ { member: "length", expected: 1 }, ])("Derived array access (%p)", ({ member, expected }) => { const luaHeader = `local arr = {name="array", firstElement=function(self) return self[1]; end};`; - const typeScriptHeader = `interface CustomArray extends Array{ + const typeScriptHeader = ` + interface CustomArray extends Array{ name:string, firstElement():number; }; - declare const arr: CustomArray;`; + declare const arr: CustomArray; + `; const result = util.transpileAndExecute( ` @@ -126,9 +128,11 @@ test("Array delete return false", () => { }); test("Array property access", () => { - const code = `type A = number[] & {foo?: string}; + const code = ` + type A = number[] & {foo?: string}; const a: A = [1,2,3]; a.foo = "bar"; - return \`\${a.foo}\${a[0]}\${a[1]}\${a[2]}\`;`; + return \`\${a.foo}\${a[0]}\${a[1]}\${a[2]}\`; + `; expect(util.transpileAndExecute(code)).toBe("bar123"); }); diff --git a/test/unit/assignmentDestructuring.spec.ts b/test/unit/assignmentDestructuring.spec.ts index 955c36f83..41fb9899b 100644 --- a/test/unit/assignmentDestructuring.spec.ts +++ b/test/unit/assignmentDestructuring.spec.ts @@ -43,9 +43,11 @@ test.each([ }); test("Union destructuring", () => { - const code = `function foo(): [string] | [] { return ["bar"]; } + const code = ` + function foo(): [string] | [] { return ["bar"]; } let x: string; [x] = foo(); - return x;`; + return x; + `; expect(util.transpileAndExecute(code)).toBe("bar"); }); diff --git a/test/unit/assignments/assignments.spec.ts b/test/unit/assignments/assignments.spec.ts index aeaf6de4e..4102b6d26 100644 --- a/test/unit/assignments/assignments.spec.ts +++ b/test/unit/assignments/assignments.spec.ts @@ -67,75 +67,84 @@ test("Ellipsis binding pattern", () => { }); test("Tuple Assignment", () => { - const code = `function abc(): [number, number] { return [1, 2]; }; - let t: [number, number] = abc(); - return t[0] + t[1];`; + const code = ` + function abc(): [number, number] { return [1, 2]; }; + let t: [number, number] = abc(); + return t[0] + t[1]; + `; const result = util.transpileAndExecute(code); expect(result).toBe(3); }); test("TupleReturn assignment", () => { - const code = - `/** @tupleReturn */\n` + - `declare function abc(this: void): number[]\n` + - `let [a,b] = abc();`; + const code = ` + /** @tupleReturn */ + declare function abc(this: void): number[] + let [a,b] = abc(); + `; const lua = util.transpileString(code); expect(lua).toBe("local a, b = abc();"); }); test("TupleReturn Single assignment", () => { - const code = - `/** @tupleReturn */\n` + - `declare function abc(this: void): [number, string];\n` + - `let a = abc();` + - `a = abc();`; + const code = ` + /** @tupleReturn */ + declare function abc(this: void): [number, string]; + let a = abc(); + a = abc(); + `; const lua = util.transpileString(code); expect(lua).toBe("local a = ({abc()});\na = ({abc()});"); }); test("TupleReturn interface assignment", () => { - const code = - `interface def {\n` + - `/** @tupleReturn */\n` + - `abc();\n` + - `} declare const jkl : def;\n` + - `let [a,b] = jkl.abc();`; + const code = ` + interface def { + /** @tupleReturn */ + abc(); + } declare const jkl : def; + let [a,b] = jkl.abc(); + `; const lua = util.transpileString(code); expect(lua).toBe("local a, b = jkl:abc();"); }); test("TupleReturn namespace assignment", () => { - const code = - `declare namespace def {\n` + - `/** @tupleReturn */\n` + - `function abc(this: void) {}\n` + - `}\n` + - `let [a,b] = def.abc();`; + const code = ` + declare namespace def { + /** @tupleReturn */ + function abc(this: void) {} + } + let [a,b] = def.abc(); + `; const lua = util.transpileString(code); expect(lua).toBe("local a, b = def.abc();"); }); test("TupleReturn method assignment", () => { - const code = - `declare class def {\n` + - `/** @tupleReturn */\n` + - `abc() { return [1,2,3]; }\n` + - `} const jkl = new def();\n` + - `let [a,b] = jkl.abc();`; + const code = ` + declare class def { + /** @tupleReturn */ + abc() { return [1,2,3]; } + } const jkl = new def(); + let [a,b] = jkl.abc(); + `; const lua = util.transpileString(code); expect(lua).toBe("local jkl = def.new();\nlocal a, b = jkl:abc();"); }); test("TupleReturn functional", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const [a, b] = abc(); - return b + a;`; + const code = ` + /** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const [a, b] = abc(); + return b + a; + `; const result = util.transpileAndExecute(code); @@ -143,10 +152,12 @@ test("TupleReturn functional", () => { }); test("TupleReturn single", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - const res = abc(); - return res.length`; + const code = ` + /** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + const res = abc(); + return res.length + `; const result = util.transpileAndExecute(code); @@ -154,9 +165,11 @@ test("TupleReturn single", () => { }); test("TupleReturn in expression", () => { - const code = `/** @tupleReturn */ - function abc(): [number, string] { return [3, "a"]; } - return abc()[1] + abc()[0];`; + const code = ` + /** @tupleReturn */ + function abc(): [number, string] { return [3, "a"]; } + return abc()[1] + abc()[0]; + `; const result = util.transpileAndExecute(code); @@ -173,9 +186,11 @@ test.each(["and", "local", "nil", "not", "or", "repeat", "then", "until"])( ); test("String table access", () => { - const code = `const dict : {[key:string]:any} = {}; - dict["a b"] = 3; - return dict["a b"];`; + const code = ` + const dict : {[key:string]:any} = {}; + dict["a b"] = 3; + return dict["a b"]; + `; const result = util.transpileAndExecute(code); expect(result).toBe(3); }); diff --git a/test/unit/assignments/functionExpressionTypeInference.spec.ts b/test/unit/assignments/functionExpressionTypeInference.spec.ts index 17eb9ab02..e393d477c 100644 --- a/test/unit/assignments/functionExpressionTypeInference.spec.ts +++ b/test/unit/assignments/functionExpressionTypeInference.spec.ts @@ -1,14 +1,18 @@ import * as util from "../../util"; test.each(["noSelf", "noSelfInFile"])("noSelf function method argument (%p)", noSelfTag => { - const header = `/** @${noSelfTag} */ namespace NS { + const header = ` + /** @${noSelfTag} */ namespace NS { export class C { method(fn: (s: string) => string) { return fn("foo"); } } } - function foo(this: void, s: string) { return s; }`; - const code = `const c = new NS.C(); - return c.method(foo);`; + function foo(this: void, s: string) { return s; } + `; + const code = ` + const c = new NS.C(); + return c.method(foo); + `; expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); }); @@ -18,23 +22,27 @@ test.each([ "(s: string) => string", ])("Function expression type inference in binary operator (%p)", funcType => { const header = `declare const undefinedFunc: ${funcType};`; - const code = `let func: ${funcType} = s => s; + const code = ` + let func: ${funcType} = s => s; func = undefinedFunc || (s => s); - return func("foo");`; + return func("foo"); + `; expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foo"); }); test.each(["s => s", "(s => s)", "function(s) { return s; }", "(function(s) { return s; })"])( "Function expression type inference in class (%p)", funcExp => { - const code = `class Foo { - func: (this: void, s: string) => string = ${funcExp}; - method: (s: string) => string = ${funcExp}; - static staticFunc: (this: void, s: string) => string = ${funcExp}; - static staticMethod: (s: string) => string = ${funcExp}; - } - const foo = new Foo(); - return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d");`; + const code = ` + class Foo { + func: (this: void, s: string) => string = ${funcExp}; + method: (s: string) => string = ${funcExp}; + static staticFunc: (this: void, s: string) => string = ${funcExp}; + static staticMethod: (s: string) => string = ${funcExp}; + } + const foo = new Foo(); + return foo.func("a") + foo.method("b") + Foo.staticFunc("c") + Foo.staticMethod("d"); + `; expect(util.transpileAndExecute(code)).toBe("abcd"); }, ); @@ -49,18 +57,22 @@ test.each([ { assignTo: "let foo: Foo; foo", funcExp: "function(s) { return s; }" }, { assignTo: "let foo: Foo; foo", funcExp: "(function(s) { return s; })" }, ])("Function expression type inference in object literal (%p)", ({ assignTo, funcExp }) => { - const code = `interface Foo { + const code = ` + interface Foo { func(this: void, s: string): string; method(this: this, s: string): string; } ${assignTo} = {func: ${funcExp}, method: ${funcExp}}; - return foo.method("foo") + foo.func("bar");`; + return foo.method("foo") + foo.func("bar"); + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); test("Function expression type inference in object literal assigned to narrower type", () => { - const code = `let foo: {} = {bar: s => s}; - return (foo as {bar: (a: any) => any}).bar("foobar");`; + const code = ` + let foo: {} = {bar: s => s}; + return (foo as {bar: (a: any) => any}).bar("foobar"); + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); @@ -76,11 +88,13 @@ test.each([ ])( "Function expression type inference in object literal (generic key) (%p)", ({ assignTo, funcExp }) => { - const code = `interface Foo { - [f: string]: (this: void, s: string) => string; - } - ${assignTo} = {func: ${funcExp}}; - return foo.func("foo");`; + const code = ` + interface Foo { + [f: string]: (this: void, s: string) => string; + } + ${assignTo} = {func: ${funcExp}}; + return foo.func("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }, ); @@ -183,7 +197,8 @@ test.each([ funcExp: "(function(s) { return s; })", }, ])("Function expression type inference in tuple (%p)", ({ assignTo, func, method, funcExp }) => { - const code = `interface Foo { + const code = ` + interface Foo { method(s: string): string; } interface Func { @@ -194,7 +209,8 @@ test.each([ } ${assignTo} = [${funcExp}, ${funcExp}]; const foo: Foo = {method: ${method}}; - return foo.method("foo") + ${func}("bar");`; + return foo.method("foo") + ${func}("bar"); + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); @@ -232,7 +248,8 @@ test.each([ funcExp: "(function(s) { return s; })", }, ])("Function expression type inference in array (%p)", ({ assignTo, method, funcExp }) => { - const code = `interface Foo { + const code = ` + interface Foo { method(s: string): string; } interface Method { @@ -240,7 +257,8 @@ test.each([ } ${assignTo} = [${funcExp}]; const foo: Foo = {method: ${method}}; - return foo.method("foo");`; + return foo.method("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); @@ -252,9 +270,11 @@ test.each([ { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, ])("Function expression type inference in union (%p)", ({ funcType, funcExp }) => { - const code = `type U = string | number | (${funcType}); + const code = ` + type U = string | number | (${funcType}); const u: U = ${funcExp}; - return (u as ${funcType})("foo");`; + return (u as ${funcType})("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); @@ -266,9 +286,11 @@ test.each([ { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, ])("Function expression type inference in union tuple (%p)", ({ funcType, funcExp }) => { - const code = `interface I { callback: ${funcType}; } + const code = ` + interface I { callback: ${funcType}; } let a: I[] | number = [{ callback: ${funcExp} }]; - return a[0].callback("foo");`; + return a[0].callback("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); @@ -280,8 +302,10 @@ test.each([ { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, ])("Function expression type inference in as cast (%p)", ({ funcType, funcExp }) => { - const code = `const fn: ${funcType} = (${funcExp}) as (${funcType}); - return fn("foo");`; + const code = ` + const fn: ${funcType} = (${funcExp}) as (${funcType}); + return fn("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); @@ -293,8 +317,10 @@ test.each([ { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, ])("Function expression type inference in type assertion (%p)", ({ funcType, funcExp }) => { - const code = `const fn: ${funcType} = <${funcType}>(${funcExp}); - return fn("foo");`; + const code = ` + const fn: ${funcType} = <${funcType}>(${funcExp}); + return fn("foo"); + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); @@ -306,11 +332,13 @@ test.each([ { funcType: "(this: any, s: string) => string", funcExp: "function(s) { return s; }" }, { funcType: "(s: string) => string", funcExp: "function(s) { return s; }" }, ])("Function expression type inference in constructor (%p)", ({ funcType, funcExp }) => { - const code = `class C { + const code = ` + class C { result: string; constructor(fn: (s: string) => string) { this.result = fn("foo"); } } const c = new C(s => s); - return c.result;`; + return c.result; + `; expect(util.transpileAndExecute(code)).toBe("foo"); }); diff --git a/test/unit/assignments/invalidFunctionAssignments.spec.ts b/test/unit/assignments/invalidFunctionAssignments.spec.ts index a7484349e..3c8108c18 100644 --- a/test/unit/assignments/invalidFunctionAssignments.spec.ts +++ b/test/unit/assignments/invalidFunctionAssignments.spec.ts @@ -5,8 +5,10 @@ import { invalidTestFunctionAssignments, invalidTestFunctionCasts } from "./func test.each(invalidTestFunctionAssignments)( "Invalid function variable declaration (%p)", (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - const fn: ${functionType} = ${testFunction.value};`; + const code = ` + ${testFunction.definition || ""} + const fn: ${functionType} = ${testFunction.value}; + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); @@ -17,9 +19,11 @@ test.each(invalidTestFunctionAssignments)( test.each(invalidTestFunctionAssignments)( "Invalid function assignment (%p)", (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - let fn: ${functionType}; - fn = ${testFunction.value};`; + const code = ` + ${testFunction.definition || ""} + let fn: ${functionType}; + fn = ${testFunction.value}; + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); @@ -30,9 +34,11 @@ test.each(invalidTestFunctionAssignments)( test.each(invalidTestFunctionCasts)( "Invalid function assignment with cast (%p)", (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - let fn: typeof ${testFunction.value}; - fn = ${castedFunction};`; + const code = ` + ${testFunction.definition || ""} + let fn: typeof ${testFunction.value}; + fn = ${castedFunction}; + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); @@ -43,9 +49,11 @@ test.each(invalidTestFunctionCasts)( test.each(invalidTestFunctionAssignments)( "Invalid function argument (%p)", (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: ${functionType}); - takesFunction(${testFunction.value});`; + const code = ` + ${testFunction.definition || ""} + declare function takesFunction(fn: ${functionType}); + takesFunction(${testFunction.value}); + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); @@ -54,9 +62,11 @@ test.each(invalidTestFunctionAssignments)( ); test("Invalid lua lib function argument", () => { - const code = `declare function foo(this: void, value: string): void; + const code = ` + declare function foo(this: void, value: string): void; declare const a: string[]; - a.forEach(foo);`; + a.forEach(foo); + `; const err = TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "callbackfn"); expect(() => util.transpileString(code, undefined, false)).toThrowExactError(err); }); @@ -64,9 +74,11 @@ test("Invalid lua lib function argument", () => { test.each(invalidTestFunctionCasts)( "Invalid function argument with cast (%p)", (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: typeof ${testFunction.value}); - takesFunction(${castedFunction});`; + const code = ` + ${testFunction.definition || ""} + declare function takesFunction(fn: typeof ${testFunction.value}); + takesFunction(${castedFunction}); + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); @@ -77,9 +89,11 @@ test.each(invalidTestFunctionCasts)( test.each(invalidTestFunctionAssignments)( "Invalid function generic argument (%p)", (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - declare function takesFunction(fn: T); - takesFunction(${testFunction.value});`; + const code = ` + ${testFunction.definition || ""} + declare function takesFunction(fn: T); + takesFunction(${testFunction.value}); + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub, "fn") : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"); @@ -90,10 +104,12 @@ test.each(invalidTestFunctionAssignments)( test.each(invalidTestFunctionAssignments)( "Invalid function return (%p)", (testFunction, functionType, isSelfConversion) => { - const code = `${testFunction.definition || ""} - function returnsFunction(): ${functionType} { - return ${testFunction.value}; - }`; + const code = ` + ${testFunction.definition || ""} + function returnsFunction(): ${functionType} { + return ${testFunction.value}; + } + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); @@ -104,10 +120,12 @@ test.each(invalidTestFunctionAssignments)( test.each(invalidTestFunctionCasts)( "Invalid function return with cast (%p)", (testFunction, castedFunction, isSelfConversion) => { - const code = `${testFunction.definition || ""} - function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - }`; + const code = ` + ${testFunction.definition || ""} + function returnsFunction(): typeof ${testFunction.value} { + return ${castedFunction}; + } + `; const err = isSelfConversion ? TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub) : TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub); @@ -116,45 +134,53 @@ test.each(invalidTestFunctionCasts)( ); test("Interface method assignment", () => { - const code = `class Foo { - method(s: string): string { return s + "+method"; } - lambdaProp: (s: string) => string = s => s + "+lambdaProp"; - } - interface IFoo { - method: (s: string) => string; - lambdaProp(s: string): string; - } - const foo: IFoo = new Foo(); - return foo.method("foo") + "|" + foo.lambdaProp("bar");`; + const code = ` + class Foo { + method(s: string): string { return s + "+method"; } + lambdaProp: (s: string) => string = s => s + "+lambdaProp"; + } + interface IFoo { + method: (s: string) => string; + lambdaProp(s: string): string; + } + const foo: IFoo = new Foo(); + return foo.method("foo") + "|" + foo.lambdaProp("bar"); + `; const result = util.transpileAndExecute(code); expect(result).toBe("foo+method|bar+lambdaProp"); }); test("Invalid function tuple assignment", () => { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Meth]; - let [i, f]: [number, Func] = getTuple();`; + const code = ` + interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Meth]; + let [i, f]: [number, Func] = getTuple(); + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub), ); }); test("Invalid method tuple assignment", () => { - const code = `interface Func { (this: void, s: string): string; } - interface Meth { (this: {}, s: string): string; } - declare function getTuple(): [number, Func]; - let [i, f]: [number, Meth] = getTuple();`; + const code = ` + interface Func { (this: void, s: string): string; } + interface Meth { (this: {}, s: string): string; } + declare function getTuple(): [number, Func]; + let [i, f]: [number, Meth] = getTuple(); + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.UnsupportedSelfFunctionConversion(util.nodeStub), ); }); test("Invalid interface method assignment", () => { - const code = `interface A { fn(s: string): string; } - interface B { fn(this: void, s: string): string; } - declare const a: A; - const b: B = a;`; + const code = ` + interface A { fn(s: string): string; } + interface B { fn(this: void, s: string): string; } + declare const a: A; + const b: B = a; + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.UnsupportedNoSelfFunctionConversion(util.nodeStub, "fn"), ); @@ -166,12 +192,14 @@ test.each([ "{(this: void, s: string): string}", "{(this: any, s1: string, s2: string): string}", ])("Invalid function overload assignment (%p)", assignType => { - const code = `interface O { - (this: any, s1: string, s2: string): string; - (this: void, s: string): string; - } - declare const o: O; - let f: ${assignType} = o;`; + const code = ` + interface O { + (this: any, s1: string, s2: string): string; + (this: void, s: string): string; + } + declare const o: O; + let f: ${assignType} = o; + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.UnsupportedOverloadAssignment(util.nodeStub), ); diff --git a/test/unit/assignments/validFunctionAssignments.spec.ts b/test/unit/assignments/validFunctionAssignments.spec.ts index a4e3501de..86b4ce230 100644 --- a/test/unit/assignments/validFunctionAssignments.spec.ts +++ b/test/unit/assignments/validFunctionAssignments.spec.ts @@ -40,9 +40,11 @@ test.each(validTestFunctionAssignments)( test.each(validTestFunctionCasts)( "Valid function assignment with cast (%p)", (testFunction, castedFunction) => { - const code = `let fn: typeof ${testFunction.value}; - fn = ${castedFunction}; - return fn("foobar");`; + const code = ` + let fn: typeof ${testFunction.value}; + fn = ${castedFunction}; + return fn("foobar"); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -52,10 +54,12 @@ test.each(validTestFunctionCasts)( test.each(validTestFunctionAssignments)( "Valid function argument (%p)", (testFunction, functionType) => { - const code = `function takesFunction(fn: ${functionType}) { - return fn("foobar"); - } - return takesFunction(${testFunction.value});`; + const code = ` + function takesFunction(fn: ${functionType}) { + return fn("foobar"); + } + return takesFunction(${testFunction.value}); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -74,10 +78,12 @@ test("Valid lua lib function argument", () => { test.each(validTestFunctionCasts)( "Valid function argument with cast (%p)", (testFunction, castedFunction) => { - const code = `function takesFunction(fn: typeof ${testFunction.value}) { - return fn("foobar"); - } - return takesFunction(${castedFunction});`; + const code = ` + function takesFunction(fn: typeof ${testFunction.value}) { + return fn("foobar"); + } + return takesFunction(${castedFunction}); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -98,10 +104,12 @@ test.each([ (f): TestFunctionAssignment => [f, noSelfTestFunctionType], ), ])("Valid function generic argument (%p)", (testFunction, functionType) => { - const code = `function takesFunction(fn: T) { + const code = ` + function takesFunction(fn: T) { return fn("foobar"); } - return takesFunction(${testFunction.value});`; + return takesFunction(${testFunction.value}); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -112,10 +120,12 @@ test.each([ ...selfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["0", "'foobar'"]]), ...noSelfTestFunctionExpressions.map((f): [TestFunction, string[]] => [f, ["'foobar'"]]), ])("Valid function expression argument with no signature (%p)", (testFunction, args) => { - const code = `const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { + const code = ` + const takesFunction: any = (fn: (this: void, ...args: any[]) => any, ...args: any[]) => { return fn(...args); } - return takesFunction(${testFunction.value}, ${args.join(", ")});`; + return takesFunction(${testFunction.value}, ${args.join(", ")}); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -124,11 +134,13 @@ test.each([ test.each(validTestFunctionAssignments)( "Valid function return (%p)", (testFunction, functionType) => { - const code = `function returnsFunction(): ${functionType} { - return ${testFunction.value}; - } - const fn = returnsFunction(); - return fn("foobar");`; + const code = ` + function returnsFunction(): ${functionType} { + return ${testFunction.value}; + } + const fn = returnsFunction(); + return fn("foobar"); + `; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); @@ -139,10 +151,10 @@ test.each(validTestFunctionCasts)( "Valid function return with cast (%p)", (testFunction, castedFunction) => { const code = `function returnsFunction(): typeof ${testFunction.value} { - return ${castedFunction}; - } - const fn = returnsFunction(); - return fn("foobar");`; + return ${castedFunction}; + } + const fn = returnsFunction(); + return fn("foobar");`; expect(util.transpileAndExecute(code, undefined, undefined, testFunction.definition)).toBe( "foobar", ); diff --git a/test/unit/bindingpatterns.spec.ts b/test/unit/bindingpatterns.spec.ts index e17d5de92..6cc1b5bc3 100644 --- a/test/unit/bindingpatterns.spec.ts +++ b/test/unit/bindingpatterns.spec.ts @@ -59,9 +59,9 @@ test.each([...testCases, ...testCasesDefault])( "testBindingPatternDeclarations (%p)", ({ bindingString, objectString, returnVariable }) => { const result = util.transpileAndExecute(` - let ${bindingString} = ${objectString}; - return ${returnVariable}; -`); + let ${bindingString} = ${objectString}; + return ${returnVariable}; + `); expect(result).toBe(true); }, ); @@ -81,12 +81,12 @@ test.each(testCases)( "Object bindings with call expressions (%p)", ({ bindingString, objectString, returnVariable }) => { const result = util.transpileAndExecute(` - function call() { - return ${objectString}; - } - let ${bindingString} = call(); - return ${returnVariable}; -`); + function call() { + return ${objectString}; + } + let ${bindingString} = call(); + return ${returnVariable}; + `); expect(result).toBe(true); }, ); diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index ef57866fa..f8f305ea0 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -683,7 +683,8 @@ test("Class Method Runtime Override", () => { }); test("Exported class super call", () => { - const code = `export class Foo { + const code = ` + export class Foo { prop: string; constructor(prop: string) { this.prop = prop; } } @@ -692,47 +693,56 @@ test("Exported class super call", () => { super("bar"); } } - export const baz = (new Bar()).prop;`; + export const baz = (new Bar()).prop; + `; expect(util.transpileExecuteAndReturnExport(code, "baz")).toBe("bar"); }); test.each([{ input: "(new Foo())", expectResult: "foo" }, { input: "Foo", expectResult: "bar" }])( "Class method name collision (%p)", ({ input, expectResult }) => { - const code = `class Foo { - public method() { return "foo"; } - public static method() { return "bar"; } - } - return ${input}.method();`; + const code = ` + class Foo { + public method() { return "foo"; } + public static method() { return "bar"; } + } + return ${input}.method(); + `; expect(util.transpileAndExecute(code)).toBe(expectResult); }, ); test.each(["extension", "metaExtension"])("Class extends extension (%p)", extensionType => { - const code = `declare class A {} + const code = ` + declare class A {} /** @${extensionType} **/ class B extends A {} - class C extends B {}`; + class C extends B {} + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.InvalidExtendsExtension(util.nodeStub), ); }); test.each(["extension", "metaExtension"])("Class construct extension (%p)", extensionType => { - const code = `declare class A {} + const code = ` + declare class A {} /** @${extensionType} **/ class B extends A {} - const b = new B();`; + const b = new B(); + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub), ); }); test("Class static instance of self", () => { - const code = `class Foo { + const code = ` + class Foo { bar = "foobar"; static instance = new Foo(); } - return Foo.instance.bar;`; + return Foo.instance.bar; + `; expect(util.transpileAndExecute(code)).toBe("foobar"); }); diff --git a/test/unit/declarations.spec.ts b/test/unit/declarations.spec.ts index 1751d621c..a4181b009 100644 --- a/test/unit/declarations.spec.ts +++ b/test/unit/declarations.spec.ts @@ -16,12 +16,14 @@ test("Declaration function call tupleReturn", () => { const tsHeader = ` /** @tupleReturn */ - declare function declaredFunction(this: void, x: number): [number, number];`; + declare function declaredFunction(this: void, x: number): [number, number]; + `; const source = ` const tuple = declaredFunction(3); const [destructedLeft, destructedRight] = declaredFunction(2); - return \`\${tuple[0] + destructedLeft},\${tuple[1] + destructedRight}\`;`; + return \`\${tuple[0] + destructedLeft},\${tuple[1] + destructedRight}\`; + `; const result = util.transpileAndExecute(source, undefined, libLua, tsHeader); expect(result).toBe("5,12"); @@ -52,7 +54,8 @@ test("Declaration interface function call", () => { declare interface MyInterface { declaredFunction(x: number): number; } - declare var myInterfaceInstance: MyInterface;`; + declare var myInterfaceInstance: MyInterface; + `; const source = `return myInterfaceInstance.declaredFunction(3);`; @@ -74,12 +77,15 @@ test("Declaration instance function callback", () => { const libLua = ` myInstance = {} myInstance.x = 10 - function myInstance:declaredFunction(callback) return callback(self.x) end`; + function myInstance:declaredFunction(callback) return callback(self.x) end + `; - const tsHeader = `declare interface MyInterface { + const tsHeader = ` + declare interface MyInterface { declaredFunction(callback: (this: void, x: number) => number): number; } - declare var myInstance: MyInterface;`; + declare var myInstance: MyInterface; + `; const source = `return myInstance.declaredFunction(x => 2 * x);`; diff --git a/test/unit/decoratorCustomConstructor.spec.ts b/test/unit/decoratorCustomConstructor.spec.ts index c32fb2214..9ff43c51d 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -2,18 +2,22 @@ import { TSTLErrors } from "../../src/TSTLErrors"; import * as util from "../util"; test("CustomCreate", () => { - const luaHeader = `function Point2DCreate(x, y) + const luaHeader = ` + function Point2DCreate(x, y) return {x = x, y = y} - end`; + end + `; - const tsHeader = `/** @customConstructor Point2DCreate */ + const tsHeader = ` + /** @customConstructor Point2DCreate */ class Point2D { public x: number; public y: number; constructor(x: number, y: number) { // No values assigned } - }`; + } + `; const result = util.transpileAndExecute( `return new Point2D(1, 2).x;`, @@ -27,8 +31,8 @@ test("CustomCreate", () => { test("IncorrectUsage", () => { expect(() => { - util.transpileString( - `/** @customConstructor */ + util.transpileString(` + /** @customConstructor */ class Point2D { constructor( public x: number, @@ -36,8 +40,7 @@ test("IncorrectUsage", () => { ) {} } return new Point2D(1, 2).x; - `, - ); + `); }).toThrowExactError( TSTLErrors.InvalidDecoratorArgumentNumber("@customConstructor", 0, 1, util.nodeStub), ); diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index f486b5e3f..eb574cc62 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -12,7 +12,8 @@ test("MetaExtension", () => { public static test() { return 5; } - }`; + } + `; const result = util.transpileAndExecute( `return debug.getregistry()["_LOADED"].test();`, @@ -26,29 +27,25 @@ test("MetaExtension", () => { test("IncorrectUsage", () => { expect(() => { - util.transpileString( - ` + util.transpileString(` /** @metaExtension */ class LoadedExt { public static test() { return 5; } } - `, - ); + `); }).toThrowExactError(TSTLErrors.MissingMetaExtension(util.nodeStub)); }); test("DontAllowInstantiation", () => { expect(() => { - util.transpileString( - ` + util.transpileString(` declare class _LOADED {} /** @metaExtension */ class Ext extends _LOADED { } const e = new Ext(); - `, - ); + `); }).toThrowExactError(TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub)); }); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index e0814988d..cbb0fbe15 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -56,21 +56,23 @@ test("Const enum without initializer in some values", () => { test("Invalid heterogeneous enum", () => { expect(() => { - const lua = util.transpileString( - `enum TestEnum { + util.transpileString(` + enum TestEnum { a, b = "ok", c, - }`, - ); + } + `); }).toThrowExactError(TSTLErrors.HeterogeneousEnum(util.nodeStub)); }); test("String literal name in enum", () => { - const code = `enum TestEnum { + const code = ` + enum TestEnum { ["name"] = "foo" } - return TestEnum["name"];`; + return TestEnum["name"]; + `; const result = util.transpileAndExecute(code); expect(result).toBe("foo"); }); diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 082e61eb9..f91a22269 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -15,36 +15,39 @@ test("throwError", () => { test.each([{ i: 0, expected: "A" }, { i: 1, expected: "B" }, { i: 2, expected: "C" }])( "re-throw (%p)", ({ i, expected }) => { - const source = `const i: number = ${i}; - function foo() { - try { + const source = ` + const i: number = ${i}; + 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"; + } + } + let result: string = "x"; try { - if (i === 0) { throw "z"; } + foo(); } catch (e) { - throw "a"; - } finally { - if (i === 1) { throw "b"; } + result = (e as string)[(e as string).length - 1]; } - } catch (e) { - throw (e as string).toUpperCase(); - } finally { - throw "C"; - } - } - let result: string = "x"; - try { - foo(); - } catch (e) { - result = (e as string)[(e as string).length - 1]; - } - return result;`; + return result; + `; const result = util.transpileAndExecute(source); expect(result).toBe(expected); }, ); test("re-throw (no catch var)", () => { - const source = `let result = "x"; + const source = ` + let result = "x"; try { try { throw "y"; @@ -54,7 +57,8 @@ test("re-throw (no catch var)", () => { } catch (e) { result = (e as string)[(e as string).length - 1]; } - return result;`; + return result; + `; const result = util.transpileAndExecute(source); expect(result).toBe("z"); }); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index d5d653958..e1acbfa18 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -198,9 +198,11 @@ test.each([ }); test("Binary Comma Statement in For Loop", () => { - const code = `let x: number, y: number; + const code = ` + let x: number, y: number; for (x = 0, y = 17; x < 5; ++x, --y) {} - return y;`; + return y; + `; expect(util.transpileAndExecute(code)).toBe(12); }); @@ -262,17 +264,16 @@ test.each([ { expression: "inst.field = 3", expected: 3 }, { expression: `"abc" + inst.field`, expected: "abc8" }, ])("Get accessor expression (%p)", ({ expression, expected }) => { - const source = - `class MyClass {` + - ` public _field: number;` + - ` public get field(): number { return this._field + 4; }` + - ` public set field(v: number) { this._field = v; }` + - `}` + - `var inst = new MyClass();` + - `inst._field = 4;` + - `return ${expression};`; - - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(` + class MyClass { + public _field: number; + public get field(): number { return this._field + 4; } + public set field(v: number) { this._field = v; } + } + var inst = new MyClass(); + inst._field = 4; + return ${expression}; + `); expect(result).toBe(expected); }); @@ -288,17 +289,16 @@ test.each([ { expression: "<<= 3", expected: (4 << 3) + 4 }, { expression: ">>>= 3", expected: (4 >> 3) + 4 }, ])("Set accessorExpression (%p)", ({ expression, expected }) => { - const source = - `class MyClass {` + - ` public _field: number = 4;` + - ` public get field(): number { return this._field; }` + - ` public set field(v: number) { this._field = v + 4; }` + - `}` + - `var inst = new MyClass();` + - `inst.field ${expression};` + - `return inst._field;`; - - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(` + class MyClass { + public _field: number = 4; + public get field(): number { return this._field; } + public set field(v: number) { this._field = v + 4; } + } + var inst = new MyClass(); + inst.field ${expression}; + return inst._field; + `); expect(result).toBe(expected); }); @@ -309,30 +309,29 @@ test.each([ { expression: "inst.superField", expected: 5 }, { expression: "inst.superBaseField", expected: 4 }, ])("Inherited accessors (%p)", ({ expression, expected }) => { - const source = - `class MyBaseClass {` + - ` public _baseField: number;` + - ` public get baseField(): number { return this._baseField + 6; }` + - ` public set baseField(v: number) { this._baseField = v; }` + - `}` + - `class MyClass extends MyBaseClass {` + - ` public _field: number;` + - ` public get field(): number { return this._field + 4; }` + - ` public set field(v: number) { this._field = v; }` + - `}` + - `class MySuperClass extends MyClass {` + - ` public _superField: number;` + - ` public get superField(): number { return this._superField + 2; }` + - ` public set superField(v: number) { this._superField = v; }` + - ` public get superBaseField() { return this.baseField - 3; }` + - `}` + - `var inst = new MySuperClass();` + - `inst.baseField = 1;` + - `inst.field = 2;` + - `inst.superField = 3;` + - `return ${expression};`; - - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(` + class MyBaseClass { + public _baseField: number; + public get baseField(): number { return this._baseField + 6; } + public set baseField(v: number) { this._baseField = v; } + } + class MyClass extends MyBaseClass { + public _field: number; + public get field(): number { return this._field + 4; } + public set field(v: number) { this._field = v; } + } + class MySuperClass extends MyClass { + public _superField: number; + public get superField(): number { return this._superField + 2; } + public set superField(v: number) { this._superField = v; } + public get superBaseField() { return this.baseField - 3; } + } + var inst = new MySuperClass(); + inst.baseField = 1; + inst.field = 2; + inst.superField = 3; + return ${expression} + `); expect(result).toBe(expected); }); @@ -437,9 +436,11 @@ test("Block expression", () => { }); test("Non-null expression", () => { - const result = util.transpileAndExecute(`function abc(): number | undefined { return 3; } + const result = util.transpileAndExecute(` + function abc(): number | undefined { return 3; } const a: number = abc()!; - return a;`); + return a; + `); expect(result).toBe(3); }); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index c165ca522..d36dddcdf 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -264,37 +264,41 @@ test.each([ { args: ["bar"], expectResult: "foobar" }, { args: ["baz", "bar"], expectResult: "bazbar" }, ])("Function overload (%p)", ({ args, expectResult }) => { - const code = `class O { - prop = "foo"; - method(s: string): string; - method(this: void, s1: string, s2: string): string; - method(s1: string) { - if (typeof this === "string") { - return this + s1; - } - return this.prop + s1; - } - }; - const o = new O(); - return o.method(${args.map(a => '"' + a + '"').join(", ")});`; + const code = ` + class O { + prop = "foo"; + method(s: string): string; + method(this: void, s1: string, s2: string): string; + method(s1: string) { + if (typeof this === "string") { + return this + s1; + } + return this.prop + s1; + } + }; + const o = new O(); + return o.method(${args.map(a => '"' + a + '"').join(", ")}); + `; const result = util.transpileAndExecute(code); expect(result).toBe(expectResult); }); test("Nested Function", () => { - const code = `class C { - private prop = "bar"; - public outer() { - const o = { - prop: "foo", - innerFunc: function() { return this.prop; }, - innerArrow: () => this.prop - }; - return o.innerFunc() + o.innerArrow(); - } - } - let c = new C(); - return c.outer();`; + const code = ` + class C { + private prop = "bar"; + public outer() { + const o = { + prop: "foo", + innerFunc: function() { return this.prop; }, + innerArrow: () => this.prop + }; + return o.innerFunc() + o.innerArrow(); + } + } + let c = new C(); + return c.outer(); + `; const result = util.transpileAndExecute(code); expect(result).toBe("foobar"); }); @@ -302,79 +306,84 @@ test("Nested Function", () => { test.each([{ s1: "abc", s2: "abc" }, { s1: "abc", s2: "def" }])( "Dot vs Colon method call (%p)", ({ s1, s2 }) => { - const result = util.transpileAndExecute( - `class MyClass { - dotMethod(this: void, s: string) { - return s; - } - colonMethod(s: string) { - return s; - } - } - const inst = new MyClass(); - return inst.dotMethod("${s1}") == inst.colonMethod("${s2}");`, - ); + const result = util.transpileAndExecute(` + class MyClass { + dotMethod(this: void, s: string) { + return s; + } + colonMethod(s: string) { + return s; + } + } + const inst = new MyClass(); + return inst.dotMethod("${s1}") == inst.colonMethod("${s2}"); + `); expect(result).toBe(s1 === s2); }, ); test("Element access call", () => { - const code = `class C { - prop = "bar"; - method(s: string) { return s + this.prop; } - } - const c = new C(); - return c['method']("foo"); + const code = ` + class C { + prop = "bar"; + method(s: string) { return s + this.prop; } + } + const c = new C(); + return c['method']("foo"); `; const result = util.transpileAndExecute(code); expect(result).toBe("foobar"); }); test("Element access call no args", () => { - const code = `class C { - prop = "bar"; - method() { return this.prop; } - } - const c = new C(); - return c['method'](); + const code = ` + class C { + prop = "bar"; + method() { return this.prop; } + } + const c = new C(); + return c['method'](); `; const result = util.transpileAndExecute(code); expect(result).toBe("bar"); }); test("Complex element access call", () => { - const code = `class C { - prop = "bar"; - method(s: string) { return s + this.prop; } - } - function getC() { return new C(); } - return getC()['method']("foo"); + const code = ` + class C { + prop = "bar"; + method(s: string) { return s + this.prop; } + } + function getC() { return new C(); } + return getC()['method']("foo"); `; const result = util.transpileAndExecute(code); expect(result).toBe("foobar"); }); test("Complex element access call no args", () => { - const code = `class C { - prop = "bar"; - method() { return this.prop; } - } - function getC() { return new C(); } - return getC()['method'](); + const code = ` + class C { + prop = "bar"; + method() { return this.prop; } + } + function getC() { return new C(); } + return getC()['method'](); `; const result = util.transpileAndExecute(code); expect(result).toBe("bar"); }); test("Complex element access call statement", () => { - const code = `let foo: string; - class C { - prop = "bar"; - method(s: string) { foo = s + this.prop; } - } - function getC() { return new C(); } - getC()['method']("foo"); - return foo; + const code = ` + let foo: string; + class C { + prop = "bar"; + method(s: string) { foo = s + this.prop; } + } + function getC() { return new C(); } + getC()['method']("foo"); + return foo; `; const result = util.transpileAndExecute(code); expect(result).toBe("foobar"); @@ -383,18 +392,19 @@ test("Complex element access call statement", () => { test.each([{ iterations: 1, expectedResult: 1 }, { iterations: 2, expectedResult: 42 }])( "Generator functions value (%p)", ({ iterations, expectedResult }) => { - const code = `function* seq(value: number) { - let a = yield value + 1; - return 42; -} -const gen = seq(0); -let ret: number; -for(let i = 0; i < ${iterations}; ++i) -{ - ret = gen.next(i).value; -} -return ret; -`; + const code = ` + function* seq(value: number) { + let a = yield value + 1; + return 42; + } + const gen = seq(0); + let ret: number; + for(let i = 0; i < ${iterations}; ++i) + { + ret = gen.next(i).value; + } + return ret; + `; const result = util.transpileAndExecute(code); expect(result).toBe(expectedResult); }, @@ -403,65 +413,71 @@ return ret; test.each([{ iterations: 1, expectedResult: false }, { iterations: 2, expectedResult: true }])( "Generator functions done (%p)", ({ iterations, expectedResult }) => { - const code = `function* seq(value: number) { - let a = yield value + 1; - return 42; -} -const gen = seq(0); -let ret: boolean; -for(let i = 0; i < ${iterations}; ++i) -{ - ret = gen.next(i).done; -} -return ret; -`; + const code = ` + function* seq(value: number) { + let a = yield value + 1; + return 42; + } + const gen = seq(0); + let ret: boolean; + for(let i = 0; i < ${iterations}; ++i) + { + ret = gen.next(i).done; + } + return ret; + `; const result = util.transpileAndExecute(code); expect(result).toBe(expectedResult); }, ); test("Generator for..of", () => { - const code = `function* seq() { - yield(1); - yield(2); - yield(3); - return 4; - } - let result = 0; - for(let i of seq()) - { - result = result * 10 + i; - } - return result`; + const code = ` + function* seq() { + yield(1); + yield(2); + yield(3); + return 4; + } + let result = 0; + for(let i of seq()) + { + result = result * 10 + i; + } + return result + `; const result = util.transpileAndExecute(code); expect(result).toBe(123); }); test("Function local overriding export", () => { - const code = `export const foo = 5; + const code = ` + export const foo = 5; function bar(foo: number) { return foo; } - export const result = bar(7);`; + export const result = bar(7); + `; expect(util.transpileExecuteAndReturnExport(code, "result")).toBe(7); }); test("Function using global as this", () => { - const code = `var foo = "foo"; + const code = ` + var foo = "foo"; function bar(this: any) { return this.foo; - }`; + } + `; expect(util.transpileAndExecute("return foo;", undefined, undefined, code)).toBe("foo"); }); test("Function rest binding pattern", () => { - const result = util.transpileAndExecute( - `function bar(foo: string, ...[bar, baz]: [string, string]) { + const result = util.transpileAndExecute(` + function bar(foo: string, ...[bar, baz]: [string, string]) { return bar + baz + foo; } return bar("abc", "def", "xyz"); - `, - ); + `); expect(result).toBe("defxyzabc"); }); diff --git a/test/unit/hoisting.spec.ts b/test/unit/hoisting.spec.ts index 5d5b204eb..215d38c49 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -3,78 +3,96 @@ import { TSTLErrors } from "../../src/TSTLErrors"; import * as util from "../util"; test("Var Hoisting", () => { - const code = `foo = "foo"; + const code = ` + foo = "foo"; var foo; - return foo;`; + return foo; + `; const result = util.transpileAndExecute(code); expect(result).toBe("foo"); }); test("Exported Var Hoisting", () => { - const code = `foo = "foo"; - export var foo;`; + const code = ` + foo = "foo"; + export var foo; + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test.each(["let", "const"])("Let/Const Hoisting (%p)", varType => { - const code = `let bar: string; + const code = ` + let bar: string; function setBar() { bar = foo; } ${varType} foo = "foo"; setBar(); - return foo;`; + return foo; + `; const result = util.transpileAndExecute(code); expect(result).toBe("foo"); }); test.each(["let", "const"])("Exported Let/Const Hoisting (%p)", varType => { - const code = `let bar: string; + const code = ` + let bar: string; function setBar() { bar = foo; } export ${varType} foo = "foo"; - setBar();`; + setBar(); + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test("Global Function Hoisting", () => { - const code = `const foo = bar(); + const code = ` + const foo = bar(); function bar() { return "bar"; } - return foo;`; + return foo; + `; const result = util.transpileAndExecute(code); expect(result).toBe("bar"); }); test("Local Function Hoisting", () => { - const code = `export const foo = bar(); - function bar() { return "bar"; }`; + const code = ` + export const foo = bar(); + function bar() { return "bar"; } + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("bar"); }); test("Exported Function Hoisting", () => { - const code = `const foo = bar(); + const code = ` + const foo = bar(); export function bar() { return "bar"; } - export const baz = foo;`; + export const baz = foo; + `; const result = util.transpileExecuteAndReturnExport(code, "baz"); expect(result).toBe("bar"); }); test("Namespace Function Hoisting", () => { - const code = `let foo: string; + const code = ` + let foo: string; namespace NS { foo = bar(); function bar() { return "bar"; } - }`; + } + `; const result = util.transpileAndExecute("return foo;", undefined, undefined, code); expect(result).toBe("bar"); }); test("Exported Namespace Function Hoisting", () => { - const code = `let foo: string; + const code = ` + let foo: string; namespace NS { foo = bar(); export function bar() { return "bar"; } - }`; + } + `; const result = util.transpileAndExecute("return foo;", undefined, undefined, code); expect(result).toBe("bar"); }); @@ -84,14 +102,16 @@ test.each([ { varType: "let", expectResult: "bar" }, { varType: "const", expectResult: "bar" }, ])("Hoisting in Non-Function Scope (%p)", ({ varType, expectResult }) => { - const code = `function foo() { + const code = ` + function foo() { ${varType} bar = "bar"; for (let i = 0; i < 1; ++i) { ${varType} bar = "foo"; } return bar; } - return foo();`; + return foo(); + `; const result = util.transpileAndExecute(code); expect(result).toBe(expectResult); }); @@ -100,54 +120,63 @@ test.each([ { initializer: "", expectResult: "foofoo" }, { initializer: ' = "bar"', expectResult: "barbar" }, ])("Var hoisting from child scope (%p)", ({ initializer, expectResult }) => { - const code = `foo = "foo"; + const code = ` + foo = "foo"; let result: string; if (true) { var foo${initializer}; result = foo; } - return foo + result;`; + return foo + result; + `; const result = util.transpileAndExecute(code); expect(result).toBe(expectResult); }); test("Hoisting due to reference from hoisted function", () => { - const code = `const foo = "foo"; + const code = ` + const foo = "foo"; const result = bar(); function bar() { return foo; } - return result;`; + return result; + `; const result = util.transpileAndExecute(code); expect(result).toBe("foo"); }); test("Namespace Hoisting", () => { - const code = `function bar() { + const code = ` + function bar() { return NS.foo; } namespace NS { export let foo = "foo"; } - export const foo = bar();`; + export const foo = bar(); + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test("Exported Namespace Hoisting", () => { - const code = `function bar() { + const code = ` + function bar() { return NS.foo; } export namespace NS { export let foo = "foo"; } - export const foo = bar();`; + export const foo = bar(); + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test("Nested Namespace Hoisting", () => { - const code = `export namespace Outer { + const code = ` + export namespace Outer { export function bar() { return Inner.foo; } @@ -155,31 +184,36 @@ test("Nested Namespace Hoisting", () => { export let foo = "foo"; } } - export const foo = Outer.bar();`; + export const foo = Outer.bar(); + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test("Class Hoisting", () => { - const code = `function makeFoo() { + const code = ` + function makeFoo() { return new Foo(); } class Foo { public bar = "foo"; } - export const foo = makeFoo().bar;`; + export const foo = makeFoo().bar; + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); test("Enum Hoisting", () => { - const code = `function bar() { + const code = ` + function bar() { return E.A; } enum E { A = "foo" } - export const foo = bar();`; + export const foo = bar(); + `; const result = util.transpileExecuteAndReturnExport(code, "foo"); expect(result).toBe("foo"); }); diff --git a/test/unit/lualib/lualib.spec.ts b/test/unit/lualib/lualib.spec.ts index 2fba27716..8c4052562 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -238,8 +238,7 @@ test.each([{ inp: [1, 2, 3], expected: 3 }, { inp: [1, 2, 3, 4, 5], expected: 3 ({ inp, expected }) => { const result = util.transpileAndExecute( `let [x, y, z] = ${JSON.stringify(inp)} - return z; - `, + return z;`, ); expect(result).toBe(expected); @@ -250,8 +249,7 @@ test.each([{ inp: [1] }, { inp: [1, 2, 3] }])("array.push (%p)", ({ inp }) => { const result = util.transpileAndExecute( `let testArray = [0]; testArray.push(${inp.join(", ")}); - return JSONStringify(testArray); - `, + return JSONStringify(testArray);`, ); expect(result).toBe(JSON.stringify([0].concat(inp))); diff --git a/test/unit/lualib/weakSet.spec.ts b/test/unit/lualib/weakSet.spec.ts index dd2e7df01..1b50a4756 100644 --- a/test/unit/lualib/weakSet.spec.ts +++ b/test/unit/lualib/weakSet.spec.ts @@ -1,7 +1,9 @@ import * as util from "../../util"; -const initRefsTs = `let ref = {}; - let ref2 = () => {};`; +const initRefsTs = ` + let ref = {}; + let ref2 = () => {}; +`; test("weakSet constructor", () => { const result = util.transpileAndExecute(` diff --git a/test/unit/modules.spec.ts b/test/unit/modules.spec.ts index 82e866f53..c02f052de 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -54,10 +54,12 @@ test("Nested module with dot in name", () => { }); test("Access this in module", () => { - const header = `module M { + const header = ` + module M { export const foo = "foo"; export function bar() { return this.foo + "bar"; } - }`; + } + `; const code = `return M.bar();`; expect(util.transpileAndExecute(code, undefined, undefined, header)).toBe("foobar"); }); diff --git a/test/unit/tshelper.spec.ts b/test/unit/tshelper.spec.ts index ee314672c..6e1b0d9df 100644 --- a/test/unit/tshelper.spec.ts +++ b/test/unit/tshelper.spec.ts @@ -38,7 +38,8 @@ test("IsFileModuleNull", () => { }); test("GetCustomDecorators single", () => { - const source = `/** @compileMembersOnly */ + const source = ` + /** @compileMembersOnly */ enum TestEnum { val1 = 0, val2 = 2, @@ -46,7 +47,8 @@ test("GetCustomDecorators single", () => { val4 = "bye", } - const a = TestEnum.val1;`; + const a = TestEnum.val1; + `; const [sourceFile, typeChecker] = util.parseTypeScript(source); const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); @@ -59,7 +61,8 @@ test("GetCustomDecorators single", () => { }); test("GetCustomDecorators multiple", () => { - const source = `/** @compileMembersOnly + const source = ` + /** @compileMembersOnly * @Phantom */ enum TestEnum { val1 = 0, @@ -68,7 +71,8 @@ test("GetCustomDecorators multiple", () => { val4 = "bye", } - const a = TestEnum.val1;`; + const a = TestEnum.val1; + `; const [sourceFile, typeChecker] = util.parseTypeScript(source); const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); @@ -82,7 +86,8 @@ test("GetCustomDecorators multiple", () => { }); test("GetCustomDecorators single jsdoc", () => { - const source = `/** @compileMembersOnly */ + const source = ` + /** @compileMembersOnly */ enum TestEnum { val1 = 0, val2 = 2, @@ -90,7 +95,8 @@ test("GetCustomDecorators single jsdoc", () => { val4 = "bye", } - const a = TestEnum.val1;`; + const a = TestEnum.val1; + `; const [sourceFile, typeChecker] = util.parseTypeScript(source); const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); @@ -103,7 +109,8 @@ test("GetCustomDecorators single jsdoc", () => { }); test("GetCustomDecorators multiple jsdoc", () => { - const source = `/** @phantom + const source = ` + /** @phantom * @CompileMembersOnly */ enum TestEnum { val1 = 0, @@ -112,7 +119,8 @@ test("GetCustomDecorators multiple jsdoc", () => { val4 = "bye", } - const a = TestEnum.val1;`; + const a = TestEnum.val1; + `; const [sourceFile, typeChecker] = util.parseTypeScript(source); const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); @@ -126,7 +134,8 @@ test("GetCustomDecorators multiple jsdoc", () => { }); test("GetCustomDecorators multiple default jsdoc", () => { - const source = `/** + const source = ` + /** * @description abc * @phantom * @compileMembersOnly */ @@ -137,7 +146,8 @@ test("GetCustomDecorators multiple default jsdoc", () => { val4 = "bye", } - const a = TestEnum.val1;`; + const a = TestEnum.val1; + `; const [sourceFile, typeChecker] = util.parseTypeScript(source); const identifier = util.findFirstChild(sourceFile, ts.isEnumDeclaration); diff --git a/test/unit/tuples.spec.ts b/test/unit/tuples.spec.ts index 7016e44fb..90e0f9ec8 100644 --- a/test/unit/tuples.spec.ts +++ b/test/unit/tuples.spec.ts @@ -134,9 +134,11 @@ test("Tuple Non-Static Method Return Destruct", () => { }); test("Tuple Return on Arrow Function", () => { - const code = `const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; + const code = ` + const fn = /** @tupleReturn */ (s: string) => [s, "bar"]; const [a, b] = fn("foo"); - return a + b;`; + return a + b; + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); @@ -144,10 +146,12 @@ test("Tuple Return on Arrow Function", () => { }); test("Tuple Return Inference", () => { - const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + const code = ` + /** @tupleReturn */ interface Fn { (s: string): [string, string] } const fn: Fn = s => [s, "bar"]; const [a, b] = fn("foo"); - return a + b;`; + return a + b; + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); @@ -155,12 +159,14 @@ test("Tuple Return Inference", () => { }); test("Tuple Return Inference as Argument", () => { - const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + const code = ` + /** @tupleReturn */ interface Fn { (s: string): [string, string] } function foo(fn: Fn) { const [a, b] = fn("foo"); return a + b; } - return foo(s => [s, "bar"]);`; + return foo(s => [s, "bar"]); + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); @@ -168,12 +174,14 @@ test("Tuple Return Inference as Argument", () => { }); test("Tuple Return Inference as Elipsis Argument", () => { - const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + const code = ` + /** @tupleReturn */ interface Fn { (s: string): [string, string] } function foo(a: number, ...fn: Fn[]) { const [a, b] = fn[0]("foo"); return a + b; } - return foo(7, s => [s, "bar"]);`; + return foo(7, s => [s, "bar"]); + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); @@ -181,12 +189,14 @@ test("Tuple Return Inference as Elipsis Argument", () => { }); test("Tuple Return Inference as Elipsis Tuple Argument", () => { - const code = `/** @tupleReturn */ interface Fn { (s: string): [string, string] } + const code = ` + /** @tupleReturn */ interface Fn { (s: string): [string, string] } function foo(a: number, ...fn: [number, Fn]) { const [a, b] = fn[1]("foo"); return a + b; } - return foo(7, 17, s => [s, "bar"]);`; + return foo(7, 17, s => [s, "bar"]); + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); @@ -194,13 +204,15 @@ test("Tuple Return Inference as Elipsis Tuple Argument", () => { }); test("Tuple Return in Spread", () => { - const code = `/** @tupleReturn */ function foo(): [string, string] { + const code = ` + /** @tupleReturn */ function foo(): [string, string] { return ["foo", "bar"]; } function bar(a: string, b: string) { return a + b; } - return bar(...foo());`; + return bar(...foo()); + `; const lua = util.transpileString(code); expect(lua).not.toContain("unpack"); const result = util.executeLua(lua); diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 108a79090..e52337405 100644 --- a/test/unit/typechecking.spec.ts +++ b/test/unit/typechecking.spec.ts @@ -54,21 +54,21 @@ test("instanceof", () => { }); test("instanceof inheritance", () => { - const result = util.transpileAndExecute( - "class myClass {}\n" + - "class childClass extends myClass{}\n" + - "let inst = new childClass(); return inst instanceof myClass;", - ); + const result = util.transpileAndExecute(` + class myClass {} + class childClass extends myClass{} + let inst = new childClass(); return inst instanceof myClass; + `); expect(result).toBeTruthy(); }); test("instanceof inheritance false", () => { - const result = util.transpileAndExecute( - "class myClass {}\n" + - "class childClass extends myClass{}\n" + - "let inst = new myClass(); return inst instanceof childClass;", - ); + const result = util.transpileAndExecute(` + class myClass {} + class childClass extends myClass{} + let inst = new myClass(); return inst instanceof childClass; + `); expect(result).toBe(false); }); @@ -88,11 +88,13 @@ test("null instanceof Class", () => { }); test.each(["extension", "metaExtension"])("instanceof extension (%p)", extensionType => { - const code = `declare class A {} + const code = ` + declare class A {} /** @${extensionType} **/ class B extends A {} declare const foo: any; - const result = foo instanceof B;`; + const result = foo instanceof B; + `; expect(() => util.transpileString(code)).toThrowExactError( TSTLErrors.InvalidInstanceOfExtension(util.nodeStub), ); From 7ce2e8f39d3671899befa5633b1f7da847441cd2 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 03:09:14 +0500 Subject: [PATCH 18/24] Revert formatting changes in characterEscapeSequence translation test --- .prettierignore | 1 + test/translation/ts/characterEscapeSequence.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.prettierignore b/.prettierignore index 7b107d878..862b9c31a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,7 @@ /dist /coverage /test/compiler/testfiles/invalid_syntax.ts +/test/translation/ts/characterEscapeSequence.ts /src *.md diff --git a/test/translation/ts/characterEscapeSequence.ts b/test/translation/ts/characterEscapeSequence.ts index c5ac3a568..8a7fec33e 100644 --- a/test/translation/ts/characterEscapeSequence.ts +++ b/test/translation/ts/characterEscapeSequence.ts @@ -2,15 +2,15 @@ let quoteInDoubleQuotes = "' ' '"; let quoteInTemplateString = `' ' '`; let doubleQuoteInQuotes = '" " "'; -let doubleQuoteInDoubleQuotes = '" " "'; +let doubleQuoteInDoubleQuotes = "\" \" \""; let doubleQuoteInTemplateString = `" " "`; let backQuoteInQuotes = "` ` `"; let backQuoteInDoubleQuotes = "` ` `"; let backQuoteInTemplateString = `\` \` \``; -let escapedCharsInQuotes = "\\ \0 \b \t \n \v \f \" ' `"; -let escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" '"; +let escapedCharsInQuotes = '\\ \0 \b \t \n \v \f \" \' \`'; +let escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" \'"; let escapedCharsInTemplateString = `\\ \0 \b \t \n \v \f \" \' \``; let nonEmptyTemplateString = `Level 0: \n\t ${`Level 1: \n\t\t ${`Level 3: \n\t\t\t ${"Last level \n --"} \n --`} \n --`} \n --`; From c0e8be0a18dbd2e4104cc8554c3bcb7bae5a271c Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 03:40:38 +0500 Subject: [PATCH 19/24] Add pretest script to build lualib --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6df31f201..5f129ee92 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", "build-lualib": "ts-node ./build_lualib.ts", + "pretest": "npm run build-lualib", "test": "jest", "lint": "npm run lint:tslint && npm run lint:prettier", "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", From 77b02d3915b1d029e91c4e272bf6466a35017d7a Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 03:41:23 +0500 Subject: [PATCH 20/24] Improve performance of build_lualib script --- build_lualib.ts | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/build_lualib.ts b/build_lualib.ts index e9f456217..f968f5968 100644 --- a/build_lualib.ts +++ b/build_lualib.ts @@ -6,6 +6,9 @@ import { LuaLib as luaLib, LuaLibFeature } from "./src/LuaLib"; const bundlePath = "./dist/lualib/lualib_bundle.lua"; compile([ + "--skipLibCheck", + "--types", + "node", "--luaLibImport", "none", "--luaTarget", diff --git a/package.json b/package.json index 5f129ee92..c089127fc 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "types": "dist/index.d.ts", "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", - "build-lualib": "ts-node ./build_lualib.ts", + "build-lualib": "ts-node --transpile-only ./build_lualib.ts", "pretest": "npm run build-lualib", "test": "jest", "lint": "npm run lint:tslint && npm run lint:prettier", From 23acd2e99f8f2ccd9759f4daf44aedca2233d336 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 15:57:07 +0500 Subject: [PATCH 21/24] Re-enable type checking for build-lualib script --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c089127fc..c99850749 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "types": "dist/index.d.ts", "scripts": { "build": "tsc -p tsconfig.json && npm run build-lualib", - "build-lualib": "ts-node --transpile-only ./build_lualib.ts", - "pretest": "npm run build-lualib", + "build-lualib": "ts-node ./build_lualib.ts", + "pretest": "ts-node --transpile-only ./build_lualib.ts", "test": "jest", "lint": "npm run lint:tslint && npm run lint:prettier", "lint:prettier": "prettier --check **/*.{js,ts,yml,json}", From af1d0ad9abd624876b15d25f72f0613248369889 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 21:51:07 +0500 Subject: [PATCH 22/24] Use jest's snapshot testing for translation tests --- .prettierignore | 2 +- .../__snapshots__/transformation.spec.ts.snap | 638 ++++++++++++++++++ test/translation/builder.spec.ts | 46 -- test/translation/lua/callNamespace.lua | 1 - .../lua/characterEscapeSequence.lua | 12 - test/translation/lua/classExtension1.lua | 2 - test/translation/lua/classExtension2.lua | 2 - test/translation/lua/classExtension3.lua | 4 - test/translation/lua/classExtension4.lua | 4 - test/translation/lua/classPureAbstract.lua | 12 - test/translation/lua/continue.lua | 12 - test/translation/lua/continueConcurrent.lua | 15 - test/translation/lua/continueNested.lua | 24 - .../lua/continueNestedConcurrent.lua | 27 - test/translation/lua/do.lua | 7 - test/translation/lua/enum.lua | 7 - test/translation/lua/enumHeterogeneous.lua | 7 - test/translation/lua/enumMembersOnly.lua | 5 - test/translation/lua/enumString.lua | 7 - test/translation/lua/exportStatement.lua | 23 - test/translation/lua/for.lua | 9 - test/translation/lua/forIn.lua | 5 - test/translation/lua/forOf.lua | 7 - .../translation/lua/functionRestArguments.lua | 3 - test/translation/lua/getSetAccessors.lua | 26 - test/translation/lua/interfaceIndex.lua | 2 - test/translation/lua/methodRestArguments.lua | 15 - .../lua/modulesChangedVariableExport.lua | 3 - test/translation/lua/modulesClassExport.lua | 14 - .../lua/modulesClassWithMemberExport.lua | 16 - .../translation/lua/modulesFunctionExport.lua | 4 - .../lua/modulesFunctionNoExport.lua | 2 - test/translation/lua/modulesImportAll.lua | 1 - test/translation/lua/modulesImportNamed.lua | 2 - .../lua/modulesImportNamedSpecialChars.lua | 10 - test/translation/lua/modulesImportRenamed.lua | 2 - .../lua/modulesImportRenamedSpecialChars.lua | 10 - .../lua/modulesImportWithoutFromClause.lua | 1 - .../lua/modulesNamespaceExport.lua | 6 - .../lua/modulesNamespaceExportEnum.lua | 11 - ...modulesNamespaceNestedWithMemberExport.lua | 12 - .../lua/modulesNamespaceNoExport.lua | 3 - .../lua/modulesNamespaceWithMemberExport.lua | 8 - .../modulesNamespaceWithMemberNoExport.lua | 9 - .../translation/lua/modulesVariableExport.lua | 3 - .../lua/modulesVariableNoExport.lua | 1 - test/translation/lua/namespace.lua | 6 - test/translation/lua/namespaceMerge.lua | 35 - test/translation/lua/namespaceNested.lua | 10 - test/translation/lua/namespacePhantom.lua | 2 - test/translation/lua/returnDefault.lua | 3 - .../lua/shorthandPropertyAssignment.lua | 4 - test/translation/lua/tryCatch.lua | 8 - test/translation/lua/tryCatchFinally.lua | 11 - test/translation/lua/tryFinally.lua | 8 - test/translation/lua/tupleReturn.lua | 28 - test/translation/lua/typeAssert.lua | 2 - test/translation/lua/while.lua | 7 - test/translation/transformation.spec.ts | 15 + .../{ts => transformation}/callNamespace.ts | 0 .../characterEscapeSequence.ts | 0 .../{ts => transformation}/classExtension1.ts | 0 .../{ts => transformation}/classExtension2.ts | 0 .../{ts => transformation}/classExtension3.ts | 0 .../{ts => transformation}/classExtension4.ts | 0 .../classPureAbstract.ts | 0 .../{ts => transformation}/continue.ts | 0 .../continueConcurrent.ts | 0 .../{ts => transformation}/continueNested.ts | 0 .../continueNestedConcurrent.ts | 0 test/translation/{ts => transformation}/do.ts | 0 .../{ts => transformation}/enum.ts | 0 .../enumHeterogeneous.ts | 0 .../{ts => transformation}/enumMembersOnly.ts | 0 .../{ts => transformation}/enumString.ts | 0 .../{ts => transformation}/exportStatement.ts | 0 .../translation/{ts => transformation}/for.ts | 0 .../{ts => transformation}/forIn.ts | 0 .../{ts => transformation}/forOf.ts | 0 .../functionRestArguments.ts | 0 .../{ts => transformation}/getSetAccessors.ts | 0 .../{ts => transformation}/interfaceIndex.ts | 0 .../methodRestArguments.ts | 0 .../modulesChangedVariableExport.ts | 0 .../modulesClassExport.ts | 0 .../modulesClassWithMemberExport.ts | 0 .../modulesFunctionExport.ts | 0 .../modulesFunctionNoExport.ts | 0 .../modulesImportAll.ts | 0 .../modulesImportNamed.ts | 0 .../modulesImportNamedSpecialChars.ts | 0 .../modulesImportRenamed.ts | 0 .../modulesImportRenamedSpecialChars.ts | 0 .../modulesImportWithoutFromClause.ts | 0 .../modulesNamespaceExport.ts | 0 .../modulesNamespaceExportEnum.ts | 0 .../modulesNamespaceNestedWithMemberExport.ts | 0 .../modulesNamespaceNoExport.ts | 0 .../modulesNamespaceWithMemberExport.ts | 0 .../modulesNamespaceWithMemberNoExport.ts | 0 .../modulesVariableExport.ts | 0 .../modulesVariableNoExport.ts | 0 .../{ts => transformation}/namespace.ts | 0 .../{ts => transformation}/namespaceMerge.ts | 0 .../{ts => transformation}/namespaceNested.ts | 0 .../namespacePhantom.ts | 0 .../{ts => transformation}/returnDefault.ts | 0 .../shorthandPropertyAssignment.ts | 0 .../{ts => transformation}/tryCatch.ts | 0 .../{ts => transformation}/tryCatchFinally.ts | 0 .../{ts => transformation}/tryFinally.ts | 0 .../{ts => transformation}/tupleReturn.ts | 0 .../{ts => transformation}/typeAssert.ts | 0 .../{ts => transformation}/while.ts | 0 test/tsconfig.json | 2 +- 115 files changed, 655 insertions(+), 528 deletions(-) create mode 100644 test/translation/__snapshots__/transformation.spec.ts.snap delete mode 100644 test/translation/builder.spec.ts delete mode 100644 test/translation/lua/callNamespace.lua delete mode 100644 test/translation/lua/characterEscapeSequence.lua delete mode 100644 test/translation/lua/classExtension1.lua delete mode 100644 test/translation/lua/classExtension2.lua delete mode 100644 test/translation/lua/classExtension3.lua delete mode 100644 test/translation/lua/classExtension4.lua delete mode 100644 test/translation/lua/classPureAbstract.lua delete mode 100644 test/translation/lua/continue.lua delete mode 100644 test/translation/lua/continueConcurrent.lua delete mode 100644 test/translation/lua/continueNested.lua delete mode 100644 test/translation/lua/continueNestedConcurrent.lua delete mode 100644 test/translation/lua/do.lua delete mode 100644 test/translation/lua/enum.lua delete mode 100644 test/translation/lua/enumHeterogeneous.lua delete mode 100644 test/translation/lua/enumMembersOnly.lua delete mode 100644 test/translation/lua/enumString.lua delete mode 100644 test/translation/lua/exportStatement.lua delete mode 100644 test/translation/lua/for.lua delete mode 100644 test/translation/lua/forIn.lua delete mode 100644 test/translation/lua/forOf.lua delete mode 100644 test/translation/lua/functionRestArguments.lua delete mode 100644 test/translation/lua/getSetAccessors.lua delete mode 100644 test/translation/lua/interfaceIndex.lua delete mode 100644 test/translation/lua/methodRestArguments.lua delete mode 100644 test/translation/lua/modulesChangedVariableExport.lua delete mode 100644 test/translation/lua/modulesClassExport.lua delete mode 100644 test/translation/lua/modulesClassWithMemberExport.lua delete mode 100644 test/translation/lua/modulesFunctionExport.lua delete mode 100644 test/translation/lua/modulesFunctionNoExport.lua delete mode 100644 test/translation/lua/modulesImportAll.lua delete mode 100644 test/translation/lua/modulesImportNamed.lua delete mode 100644 test/translation/lua/modulesImportNamedSpecialChars.lua delete mode 100644 test/translation/lua/modulesImportRenamed.lua delete mode 100644 test/translation/lua/modulesImportRenamedSpecialChars.lua delete mode 100644 test/translation/lua/modulesImportWithoutFromClause.lua delete mode 100644 test/translation/lua/modulesNamespaceExport.lua delete mode 100644 test/translation/lua/modulesNamespaceExportEnum.lua delete mode 100644 test/translation/lua/modulesNamespaceNestedWithMemberExport.lua delete mode 100644 test/translation/lua/modulesNamespaceNoExport.lua delete mode 100644 test/translation/lua/modulesNamespaceWithMemberExport.lua delete mode 100644 test/translation/lua/modulesNamespaceWithMemberNoExport.lua delete mode 100644 test/translation/lua/modulesVariableExport.lua delete mode 100644 test/translation/lua/modulesVariableNoExport.lua delete mode 100644 test/translation/lua/namespace.lua delete mode 100644 test/translation/lua/namespaceMerge.lua delete mode 100644 test/translation/lua/namespaceNested.lua delete mode 100644 test/translation/lua/namespacePhantom.lua delete mode 100644 test/translation/lua/returnDefault.lua delete mode 100644 test/translation/lua/shorthandPropertyAssignment.lua delete mode 100644 test/translation/lua/tryCatch.lua delete mode 100644 test/translation/lua/tryCatchFinally.lua delete mode 100644 test/translation/lua/tryFinally.lua delete mode 100644 test/translation/lua/tupleReturn.lua delete mode 100644 test/translation/lua/typeAssert.lua delete mode 100644 test/translation/lua/while.lua create mode 100644 test/translation/transformation.spec.ts rename test/translation/{ts => transformation}/callNamespace.ts (100%) rename test/translation/{ts => transformation}/characterEscapeSequence.ts (100%) rename test/translation/{ts => transformation}/classExtension1.ts (100%) rename test/translation/{ts => transformation}/classExtension2.ts (100%) rename test/translation/{ts => transformation}/classExtension3.ts (100%) rename test/translation/{ts => transformation}/classExtension4.ts (100%) rename test/translation/{ts => transformation}/classPureAbstract.ts (100%) rename test/translation/{ts => transformation}/continue.ts (100%) rename test/translation/{ts => transformation}/continueConcurrent.ts (100%) rename test/translation/{ts => transformation}/continueNested.ts (100%) rename test/translation/{ts => transformation}/continueNestedConcurrent.ts (100%) rename test/translation/{ts => transformation}/do.ts (100%) rename test/translation/{ts => transformation}/enum.ts (100%) rename test/translation/{ts => transformation}/enumHeterogeneous.ts (100%) rename test/translation/{ts => transformation}/enumMembersOnly.ts (100%) rename test/translation/{ts => transformation}/enumString.ts (100%) rename test/translation/{ts => transformation}/exportStatement.ts (100%) rename test/translation/{ts => transformation}/for.ts (100%) rename test/translation/{ts => transformation}/forIn.ts (100%) rename test/translation/{ts => transformation}/forOf.ts (100%) rename test/translation/{ts => transformation}/functionRestArguments.ts (100%) rename test/translation/{ts => transformation}/getSetAccessors.ts (100%) rename test/translation/{ts => transformation}/interfaceIndex.ts (100%) rename test/translation/{ts => transformation}/methodRestArguments.ts (100%) rename test/translation/{ts => transformation}/modulesChangedVariableExport.ts (100%) rename test/translation/{ts => transformation}/modulesClassExport.ts (100%) rename test/translation/{ts => transformation}/modulesClassWithMemberExport.ts (100%) rename test/translation/{ts => transformation}/modulesFunctionExport.ts (100%) rename test/translation/{ts => transformation}/modulesFunctionNoExport.ts (100%) rename test/translation/{ts => transformation}/modulesImportAll.ts (100%) rename test/translation/{ts => transformation}/modulesImportNamed.ts (100%) rename test/translation/{ts => transformation}/modulesImportNamedSpecialChars.ts (100%) rename test/translation/{ts => transformation}/modulesImportRenamed.ts (100%) rename test/translation/{ts => transformation}/modulesImportRenamedSpecialChars.ts (100%) rename test/translation/{ts => transformation}/modulesImportWithoutFromClause.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceExport.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceExportEnum.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceNestedWithMemberExport.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceNoExport.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceWithMemberExport.ts (100%) rename test/translation/{ts => transformation}/modulesNamespaceWithMemberNoExport.ts (100%) rename test/translation/{ts => transformation}/modulesVariableExport.ts (100%) rename test/translation/{ts => transformation}/modulesVariableNoExport.ts (100%) rename test/translation/{ts => transformation}/namespace.ts (100%) rename test/translation/{ts => transformation}/namespaceMerge.ts (100%) rename test/translation/{ts => transformation}/namespaceNested.ts (100%) rename test/translation/{ts => transformation}/namespacePhantom.ts (100%) rename test/translation/{ts => transformation}/returnDefault.ts (100%) rename test/translation/{ts => transformation}/shorthandPropertyAssignment.ts (100%) rename test/translation/{ts => transformation}/tryCatch.ts (100%) rename test/translation/{ts => transformation}/tryCatchFinally.ts (100%) rename test/translation/{ts => transformation}/tryFinally.ts (100%) rename test/translation/{ts => transformation}/tupleReturn.ts (100%) rename test/translation/{ts => transformation}/typeAssert.ts (100%) rename test/translation/{ts => transformation}/while.ts (100%) diff --git a/.prettierignore b/.prettierignore index 862b9c31a..a9b94c668 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,7 @@ /dist /coverage /test/compiler/testfiles/invalid_syntax.ts -/test/translation/ts/characterEscapeSequence.ts +/test/translation/transformation/characterEscapeSequence.ts /src *.md diff --git a/test/translation/__snapshots__/transformation.spec.ts.snap b/test/translation/__snapshots__/transformation.spec.ts.snap new file mode 100644 index 000000000..9c88af876 --- /dev/null +++ b/test/translation/__snapshots__/transformation.spec.ts.snap @@ -0,0 +1,638 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Transformation (callNamespace) 1`] = `"Namespace:myFunction();"`; + +exports[`Transformation (characterEscapeSequence) 1`] = ` +"local quoteInDoubleQuotes = \\"\\\\' \\\\' \\\\'\\"; +local quoteInTemplateString = \\"\\\\' \\\\' \\\\'\\"; +local doubleQuoteInQuotes = \\"\\\\\\" \\\\\\" \\\\\\"\\"; +local doubleQuoteInDoubleQuotes = \\"\\\\\\" \\\\\\" \\\\\\"\\"; +local doubleQuoteInTemplateString = \\"\\\\\\" \\\\\\" \\\\\\"\\"; +local backQuoteInQuotes = \\"\` \` \`\\"; +local backQuoteInDoubleQuotes = \\"\` \` \`\\"; +local backQuoteInTemplateString = \\"\` \` \`\\"; +local escapedCharsInQuotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" \\\\' \`\\"; +local escapedCharsInDoubleQUotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" \\\\'\\"; +local escapedCharsInTemplateString = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" \\\\' \`\\"; +local nonEmptyTemplateString = \\"Level 0: \\\\n\\\\t \\" .. (tostring(\\"Level 1: \\\\n\\\\t\\\\t \\" .. (tostring(\\"Level 3: \\\\n\\\\t\\\\t\\\\t \\" .. (tostring(\\"Last level \\\\n --\\") .. \\" \\\\n --\\")) .. \\" \\\\n --\\")) .. \\" \\\\n --\\");" +`; + +exports[`Transformation (classExtension1) 1`] = ` +"MyClass.myFunction = function(self) +end;" +`; + +exports[`Transformation (classExtension2) 1`] = ` +"TestClass.myFunction = function(self) +end;" +`; + +exports[`Transformation (classExtension3) 1`] = ` +"RenamedTestClass.myFunction = function(self) +end; +RenamedMyClass.myFunction = function(self) +end;" +`; + +exports[`Transformation (classExtension4) 1`] = ` +"MyClass.test = \\"test\\"; +MyClass.testP = \\"testP\\"; +MyClass.myFunction = function(self) +end;" +`; + +exports[`Transformation (classPureAbstract) 1`] = ` +"ClassB = ClassB or {}; +ClassB.__index = ClassB; +ClassB.prototype = ClassB.prototype or {}; +ClassB.prototype.__index = ClassB.prototype; +ClassB.prototype.constructor = ClassB; +ClassB.new = function(...) + local self = setmetatable({}, ClassB.prototype); + self:____constructor(...); + return self; +end; +ClassB.prototype.____constructor = function(self) +end;" +`; + +exports[`Transformation (continue) 1`] = ` +"do + local i = 0; + while i < 10 do + do + if i < 5 then + goto __continue1; + end + end + ::__continue1:: + i = i + 1; + end +end" +`; + +exports[`Transformation (continueConcurrent) 1`] = ` +"do + local i = 0; + while i < 10 do + do + if i < 5 then + goto __continue1; + end + if i == 7 then + goto __continue1; + end + end + ::__continue1:: + i = i + 1; + end +end" +`; + +exports[`Transformation (continueNested) 1`] = ` +"do + local i = 0; + while i < 5 do + do + if (i % 2) == 0 then + goto __continue1; + end + do + local j = 0; + while j < 2 do + do + if j == 1 then + goto __continue3; + end + end + ::__continue3:: + j = j + 1; + end + end + end + ::__continue1:: + i = i + 1; + end +end" +`; + +exports[`Transformation (continueNestedConcurrent) 1`] = ` +"do + local i = 0; + while i < 5 do + do + if (i % 2) == 0 then + goto __continue1; + end + do + local j = 0; + while j < 2 do + do + if j == 1 then + goto __continue3; + end + end + ::__continue3:: + j = j + 1; + end + end + if i == 4 then + goto __continue1; + end + end + ::__continue1:: + i = i + 1; + end +end" +`; + +exports[`Transformation (do) 1`] = ` +"local e = 10; +repeat + do + e = e - 1; + end + ::__continue1:: +until not (e > 0);" +`; + +exports[`Transformation (enum) 1`] = ` +"TestEnum = {}; +TestEnum.val1 = 0; +TestEnum[0] = \\"val1\\"; +TestEnum.val2 = 2; +TestEnum[2] = \\"val2\\"; +TestEnum.val3 = 3; +TestEnum[3] = \\"val3\\";" +`; + +exports[`Transformation (enumHeterogeneous) 1`] = ` +"TestEnum = {}; +TestEnum.val1 = 0; +TestEnum[0] = \\"val1\\"; +TestEnum.val2 = 3; +TestEnum[3] = \\"val2\\"; +TestEnum.val3 = \\"baz\\"; +TestEnum.baz = \\"val3\\";" +`; + +exports[`Transformation (enumMembersOnly) 1`] = ` +"val1 = 0; +val2 = 2; +val3 = 3; +val4 = \\"bye\\"; +local a = val1;" +`; + +exports[`Transformation (enumString) 1`] = ` +"TestEnum = {}; +TestEnum.val1 = \\"foo\\"; +TestEnum.foo = \\"val1\\"; +TestEnum.val2 = \\"bar\\"; +TestEnum.bar = \\"val2\\"; +TestEnum.val3 = \\"baz\\"; +TestEnum.baz = \\"val3\\";" +`; + +exports[`Transformation (exportStatement) 1`] = ` +"local exports = exports or {}; +local xyz = 4; +exports.xyz = xyz; +exports.uwv = xyz; +do + local __TSTL_export = require(\\"xyz\\"); + for ____exportKey, ____exportValue in pairs(__TSTL_export) do + exports[____exportKey] = ____exportValue; + end +end +do + local __TSTL_xyz = require(\\"xyz\\"); + local abc = __TSTL_xyz.abc; + local def = __TSTL_xyz.def; + exports.abc = abc; + exports.def = def; +end +do + local __TSTL_xyz = require(\\"xyz\\"); + local def = __TSTL_xyz.abc; + exports.def = def; +end +return exports;" +`; + +exports[`Transformation (for) 1`] = ` +"do + local i = 1; + while i <= 100 do + do + end + ::__continue1:: + i = i + 1; + end +end" +`; + +exports[`Transformation (forIn) 1`] = ` +"for i in pairs({a = 1, b = 2, c = 3, d = 4}) do + do + end + ::__continue1:: +end" +`; + +exports[`Transformation (forOf) 1`] = ` +"local ____TS_array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +for ____TS_index = 1, #____TS_array do + local i = ____TS_array[____TS_index]; + do + end + ::__continue1:: +end" +`; + +exports[`Transformation (functionRestArguments) 1`] = ` +"varargsFunction = function(self, a, ...) + local b = ({...}); +end;" +`; + +exports[`Transformation (getSetAccessors) 1`] = ` +"require(\\"lualib_bundle\\"); +MyClass = MyClass or {}; +MyClass.__index = MyClass; +MyClass.prototype = MyClass.prototype or {}; +MyClass.prototype.____getters = {}; +MyClass.prototype.__index = __TS__Index(MyClass.prototype); +MyClass.prototype.____setters = {}; +MyClass.prototype.__newindex = __TS__NewIndex(MyClass.prototype); +MyClass.prototype.constructor = MyClass; +MyClass.new = function(...) + local self = setmetatable({}, MyClass.prototype); + self:____constructor(...); + return self; +end; +MyClass.prototype.____constructor = function(self) +end; +MyClass.prototype.____getters.field = function(self) + return self._field + 4; +end; +MyClass.prototype.____setters.field = function(self, v) + self._field = v * 2; +end; +local instance = MyClass.new(); +instance.field = 4; +local b = instance.field; +local c = (4 + instance.field) * 3;" +`; + +exports[`Transformation (interfaceIndex) 1`] = ` +"local a = {}; +a.abc = \\"def\\";" +`; + +exports[`Transformation (methodRestArguments) 1`] = ` +"MyClass = MyClass or {}; +MyClass.__index = MyClass; +MyClass.prototype = MyClass.prototype or {}; +MyClass.prototype.__index = MyClass.prototype; +MyClass.prototype.constructor = MyClass; +MyClass.new = function(...) + local self = setmetatable({}, MyClass.prototype); + self:____constructor(...); + return self; +end; +MyClass.prototype.____constructor = function(self) +end; +MyClass.prototype.varargsFunction = function(self, a, ...) + local b = ({...}); +end;" +`; + +exports[`Transformation (modulesChangedVariableExport) 1`] = ` +"local exports = exports or {}; +exports.foo = 1; +return exports;" +`; + +exports[`Transformation (modulesClassExport) 1`] = ` +"local exports = exports or {}; +exports.TestClass = exports.TestClass or {}; +exports.TestClass.__index = exports.TestClass; +exports.TestClass.prototype = exports.TestClass.prototype or {}; +exports.TestClass.prototype.__index = exports.TestClass.prototype; +exports.TestClass.prototype.constructor = exports.TestClass; +exports.TestClass.new = function(...) + local self = setmetatable({}, exports.TestClass.prototype); + self:____constructor(...); + return self; +end; +exports.TestClass.prototype.____constructor = function(self) +end; +return exports;" +`; + +exports[`Transformation (modulesClassWithMemberExport) 1`] = ` +"local exports = exports or {}; +exports.TestClass = exports.TestClass or {}; +exports.TestClass.__index = exports.TestClass; +exports.TestClass.prototype = exports.TestClass.prototype or {}; +exports.TestClass.prototype.__index = exports.TestClass.prototype; +exports.TestClass.prototype.constructor = exports.TestClass; +exports.TestClass.new = function(...) + local self = setmetatable({}, exports.TestClass.prototype); + self:____constructor(...); + return self; +end; +exports.TestClass.prototype.____constructor = function(self) +end; +exports.TestClass.prototype.memberFunc = function(self) +end; +return exports;" +`; + +exports[`Transformation (modulesFunctionExport) 1`] = ` +"local exports = exports or {}; +exports.publicFunc = function(self) +end; +return exports;" +`; + +exports[`Transformation (modulesFunctionNoExport) 1`] = ` +"publicFunc = function(self) +end;" +`; + +exports[`Transformation (modulesImportAll) 1`] = `"local Test = require(\\"test\\");"`; + +exports[`Transformation (modulesImportNamed) 1`] = ` +"local __TSTL_test = require(\\"test\\"); +local TestClass = __TSTL_test.TestClass;" +`; + +exports[`Transformation (modulesImportNamedSpecialChars) 1`] = ` +"local __TSTL_kebab_module = require(\\"kebab-module\\"); +local TestClass = __TSTL_kebab_module.TestClass; +local __TSTL_dollar_module = require(\\"dollar$module\\"); +local TestClass = __TSTL_dollar_module.TestClass; +local __TSTL_singlequote_module = require(\\"singlequote'module\\"); +local TestClass = __TSTL_singlequote_module.TestClass; +local __TSTL_hash_module = require(\\"hash#module\\"); +local TestClass = __TSTL_hash_module.TestClass; +local __TSTL_space_module = require(\\"space module\\"); +local TestClass = __TSTL_space_module.TestClass;" +`; + +exports[`Transformation (modulesImportRenamed) 1`] = ` +"local __TSTL_test = require(\\"test\\"); +local RenamedClass = __TSTL_test.TestClass;" +`; + +exports[`Transformation (modulesImportRenamedSpecialChars) 1`] = ` +"local __TSTL_kebab_module = require(\\"kebab-module\\"); +local RenamedClass = __TSTL_kebab_module.TestClass; +local __TSTL_dollar_module = require(\\"dollar$module\\"); +local RenamedClass = __TSTL_dollar_module.TestClass; +local __TSTL_singlequote_module = require(\\"singlequote'module\\"); +local RenamedClass = __TSTL_singlequote_module.TestClass; +local __TSTL_hash_module = require(\\"hash#module\\"); +local RenamedClass = __TSTL_hash_module.TestClass; +local __TSTL_space_module = require(\\"space module\\"); +local RenamedClass = __TSTL_space_module.TestClass;" +`; + +exports[`Transformation (modulesImportWithoutFromClause) 1`] = `"require(\\"test\\");"`; + +exports[`Transformation (modulesNamespaceExport) 1`] = ` +"local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; +do +end +return exports;" +`; + +exports[`Transformation (modulesNamespaceExportEnum) 1`] = ` +"local exports = exports or {}; +exports.test = exports.test or {}; +local test = exports.test; +do + test.TestEnum = {}; + test.TestEnum.foo = \\"foo\\"; + test.TestEnum.foo = \\"foo\\"; + test.TestEnum.bar = \\"bar\\"; + test.TestEnum.bar = \\"bar\\"; +end +return exports;" +`; + +exports[`Transformation (modulesNamespaceNestedWithMemberExport) 1`] = ` +"local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; +do + TestSpace.TestNestedSpace = TestSpace.TestNestedSpace or {}; + local TestNestedSpace = TestSpace.TestNestedSpace; + do + TestNestedSpace.innerFunc = function(self) + end; + end +end +return exports;" +`; + +exports[`Transformation (modulesNamespaceNoExport) 1`] = ` +"TestSpace = TestSpace or {}; +do +end" +`; + +exports[`Transformation (modulesNamespaceWithMemberExport) 1`] = ` +"local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; +do + TestSpace.innerFunc = function(self) + end; +end +return exports;" +`; + +exports[`Transformation (modulesNamespaceWithMemberNoExport) 1`] = ` +"local exports = exports or {}; +exports.TestSpace = exports.TestSpace or {}; +local TestSpace = exports.TestSpace; +do + local innerFunc; + innerFunc = function(self) + end; +end +return exports;" +`; + +exports[`Transformation (modulesVariableExport) 1`] = ` +"local exports = exports or {}; +exports.foo = \\"bar\\"; +return exports;" +`; + +exports[`Transformation (modulesVariableNoExport) 1`] = `"local foo = \\"bar\\";"`; + +exports[`Transformation (namespace) 1`] = ` +"myNamespace = myNamespace or {}; +do + local nsMember; + nsMember = function(self) + end; +end" +`; + +exports[`Transformation (namespaceMerge) 1`] = ` +"MergedClass = MergedClass or {}; +MergedClass.__index = MergedClass; +MergedClass.prototype = MergedClass.prototype or {}; +MergedClass.prototype.__index = MergedClass.prototype; +MergedClass.prototype.constructor = MergedClass; +MergedClass.new = function(...) + local self = setmetatable({}, MergedClass.prototype); + self:____constructor(...); + return self; +end; +MergedClass.prototype.____constructor = function(self) + self.propertyFunc = function(____) + end; +end; +MergedClass.staticMethodA = function(self) +end; +MergedClass.staticMethodB = function(self) + self:staticMethodA(); +end; +MergedClass.prototype.methodA = function(self) +end; +MergedClass.prototype.methodB = function(self) + self:methodA(); + self:propertyFunc(); +end; +MergedClass = MergedClass or {}; +do + MergedClass.namespaceFunc = function(self) + end; +end +local mergedClass = MergedClass.new(); +mergedClass:methodB(); +mergedClass:propertyFunc(); +MergedClass:staticMethodB(); +MergedClass:namespaceFunc();" +`; + +exports[`Transformation (namespaceNested) 1`] = ` +"myNamespace = myNamespace or {}; +do + myNamespace.myNestedNamespace = myNamespace.myNestedNamespace or {}; + local myNestedNamespace = myNamespace.myNestedNamespace; + do + local nsMember; + nsMember = function(self) + end; + end +end" +`; + +exports[`Transformation (namespacePhantom) 1`] = ` +"nsMember = function(self) +end;" +`; + +exports[`Transformation (returnDefault) 1`] = ` +"myFunc = function(self) + return; +end;" +`; + +exports[`Transformation (shorthandPropertyAssignment) 1`] = ` +"local f; +f = function(____, x) + return ({x = x}); +end;" +`; + +exports[`Transformation (tryCatch) 1`] = ` +"do + local ____TS_try, er = pcall(function() + local a = 42; + end); + if not ____TS_try then + local b = \\"fail\\"; + end +end" +`; + +exports[`Transformation (tryCatchFinally) 1`] = ` +"do + local ____TS_try, er = pcall(function() + local a = 42; + end); + if not ____TS_try then + local b = \\"fail\\"; + end + do + local c = \\"finally\\"; + end +end" +`; + +exports[`Transformation (tryFinally) 1`] = ` +"do + pcall(function() + local a = 42; + end); + do + local b = \\"finally\\"; + end +end" +`; + +exports[`Transformation (tupleReturn) 1`] = ` +"tupleReturn = function(self) + return 0, \\"foobar\\"; +end; +tupleReturn(_G); +noTupleReturn(_G); +local a, b = tupleReturn(_G); +local c, d = table.unpack(noTupleReturn(_G)); +a, b = tupleReturn(_G); +c, d = table.unpack(noTupleReturn(_G)); +local e = ({tupleReturn(_G)}); +local f = noTupleReturn(_G); +e = ({tupleReturn(_G)}); +f = noTupleReturn(_G); +foo(_G, ({tupleReturn(_G)})); +foo(_G, noTupleReturn(_G)); +tupleReturnFromVar = function(self) + local r = {1, \\"baz\\"}; + return table.unpack(r); +end; +tupleReturnForward = function(self) + return tupleReturn(_G); +end; +tupleNoForward = function(self) + return ({tupleReturn(_G)}); +end; +tupleReturnUnpack = function(self) + return table.unpack(tupleNoForward(_G)); +end;" +`; + +exports[`Transformation (typeAssert) 1`] = ` +"local test1 = 10; +local test2 = 10;" +`; + +exports[`Transformation (while) 1`] = ` +"local d = 10; +while d > 0 do + do + d = d - 1; + end + ::__continue1:: +end" +`; diff --git a/test/translation/builder.spec.ts b/test/translation/builder.spec.ts deleted file mode 100644 index fb13a3fff..000000000 --- a/test/translation/builder.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import * as util from "../util"; -import { LuaLibImportKind } from "../../src/CompilerOptions"; - -const files: Array<{ ts: string; lua: string }> = []; -const fileContents: { [key: string]: Buffer } = {}; - -const tsPath = path.join(__dirname, "./ts/"); -const luaPath = path.join(__dirname, "./lua/"); - -const tsFiles = fs.readdirSync(tsPath); -const luaFiles = fs.readdirSync(luaPath); - -tsFiles.forEach((tsFile, i) => { - // ignore non ts files - if (path.extname(tsFile) !== ".ts") { - return; - } - const luaPart = luaFiles.indexOf(tsFile.replace(".ts", ".lua")); - if (luaPart === -1) { - throw new Error("Missing lua counter part for test file: " + tsFile); - } - const luaFile = luaFiles[luaPart]; - const luaFileAbsolute = path.join(luaPath, luaFile); - const tsFileAbsolute = path.join(tsPath, tsFile); - files.push({ ts: tsFile, lua: luaFile }); - fileContents[tsFile] = fs.readFileSync(tsFileAbsolute); - fileContents[luaFile] = fs.readFileSync(luaFileAbsolute); -}); - -function BufferToTestString(b: Buffer): string { - return b - .toString() - .trim() - .split("\r\n") - .join("\n"); -} - -test.each(files)("Transformation Tests (%p)", ({ ts, lua }) => { - expect( - util.transpileString(BufferToTestString(fileContents[ts]), { - luaLibImport: LuaLibImportKind.Require, - }), - ).toEqual(BufferToTestString(fileContents[lua])); -}); diff --git a/test/translation/lua/callNamespace.lua b/test/translation/lua/callNamespace.lua deleted file mode 100644 index 40b907163..000000000 --- a/test/translation/lua/callNamespace.lua +++ /dev/null @@ -1 +0,0 @@ -Namespace:myFunction(); diff --git a/test/translation/lua/characterEscapeSequence.lua b/test/translation/lua/characterEscapeSequence.lua deleted file mode 100644 index 82f43bbaa..000000000 --- a/test/translation/lua/characterEscapeSequence.lua +++ /dev/null @@ -1,12 +0,0 @@ -local quoteInDoubleQuotes = "\' \' \'"; -local quoteInTemplateString = "\' \' \'"; -local doubleQuoteInQuotes = "\" \" \""; -local doubleQuoteInDoubleQuotes = "\" \" \""; -local doubleQuoteInTemplateString = "\" \" \""; -local backQuoteInQuotes = "` ` `"; -local backQuoteInDoubleQuotes = "` ` `"; -local backQuoteInTemplateString = "` ` `"; -local escapedCharsInQuotes = "\\ \0 \b \t \n \v \f \" \' `"; -local escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" \'"; -local escapedCharsInTemplateString = "\\ \0 \b \t \n \v \f \" \' `"; -local nonEmptyTemplateString = "Level 0: \n\t " .. (tostring("Level 1: \n\t\t " .. (tostring("Level 3: \n\t\t\t " .. (tostring("Last level \n --") .. " \n --")) .. " \n --")) .. " \n --"); diff --git a/test/translation/lua/classExtension1.lua b/test/translation/lua/classExtension1.lua deleted file mode 100644 index ff9e5bb5d..000000000 --- a/test/translation/lua/classExtension1.lua +++ /dev/null @@ -1,2 +0,0 @@ -MyClass.myFunction = function(self) -end; diff --git a/test/translation/lua/classExtension2.lua b/test/translation/lua/classExtension2.lua deleted file mode 100644 index 94e8f655f..000000000 --- a/test/translation/lua/classExtension2.lua +++ /dev/null @@ -1,2 +0,0 @@ -TestClass.myFunction = function(self) -end; diff --git a/test/translation/lua/classExtension3.lua b/test/translation/lua/classExtension3.lua deleted file mode 100644 index 008d45956..000000000 --- a/test/translation/lua/classExtension3.lua +++ /dev/null @@ -1,4 +0,0 @@ -RenamedTestClass.myFunction = function(self) -end; -RenamedMyClass.myFunction = function(self) -end; diff --git a/test/translation/lua/classExtension4.lua b/test/translation/lua/classExtension4.lua deleted file mode 100644 index 8fcb73124..000000000 --- a/test/translation/lua/classExtension4.lua +++ /dev/null @@ -1,4 +0,0 @@ -MyClass.test = "test"; -MyClass.testP = "testP"; -MyClass.myFunction = function(self) -end; diff --git a/test/translation/lua/classPureAbstract.lua b/test/translation/lua/classPureAbstract.lua deleted file mode 100644 index 70ba4efb3..000000000 --- a/test/translation/lua/classPureAbstract.lua +++ /dev/null @@ -1,12 +0,0 @@ -ClassB = ClassB or {}; -ClassB.__index = ClassB; -ClassB.prototype = ClassB.prototype or {}; -ClassB.prototype.__index = ClassB.prototype; -ClassB.prototype.constructor = ClassB; -ClassB.new = function(...) - local self = setmetatable({}, ClassB.prototype); - self:____constructor(...); - return self; -end; -ClassB.prototype.____constructor = function(self) -end; diff --git a/test/translation/lua/continue.lua b/test/translation/lua/continue.lua deleted file mode 100644 index 25ccd79f1..000000000 --- a/test/translation/lua/continue.lua +++ /dev/null @@ -1,12 +0,0 @@ -do - local i = 0; - while i < 10 do - do - if i < 5 then - goto __continue1; - end - end - ::__continue1:: - i = i + 1; - end -end diff --git a/test/translation/lua/continueConcurrent.lua b/test/translation/lua/continueConcurrent.lua deleted file mode 100644 index 6dbd5c31c..000000000 --- a/test/translation/lua/continueConcurrent.lua +++ /dev/null @@ -1,15 +0,0 @@ -do - local i = 0; - while i < 10 do - do - if i < 5 then - goto __continue1; - end - if i == 7 then - goto __continue1; - end - end - ::__continue1:: - i = i + 1; - end -end diff --git a/test/translation/lua/continueNested.lua b/test/translation/lua/continueNested.lua deleted file mode 100644 index 18da6fbf7..000000000 --- a/test/translation/lua/continueNested.lua +++ /dev/null @@ -1,24 +0,0 @@ -do - local i = 0; - while i < 5 do - do - if (i % 2) == 0 then - goto __continue1; - end - do - local j = 0; - while j < 2 do - do - if j == 1 then - goto __continue3; - end - end - ::__continue3:: - j = j + 1; - end - end - end - ::__continue1:: - i = i + 1; - end -end diff --git a/test/translation/lua/continueNestedConcurrent.lua b/test/translation/lua/continueNestedConcurrent.lua deleted file mode 100644 index 55a1b7f2a..000000000 --- a/test/translation/lua/continueNestedConcurrent.lua +++ /dev/null @@ -1,27 +0,0 @@ -do - local i = 0; - while i < 5 do - do - if (i % 2) == 0 then - goto __continue1; - end - do - local j = 0; - while j < 2 do - do - if j == 1 then - goto __continue3; - end - end - ::__continue3:: - j = j + 1; - end - end - if i == 4 then - goto __continue1; - end - end - ::__continue1:: - i = i + 1; - end -end diff --git a/test/translation/lua/do.lua b/test/translation/lua/do.lua deleted file mode 100644 index 14639278d..000000000 --- a/test/translation/lua/do.lua +++ /dev/null @@ -1,7 +0,0 @@ -local e = 10; -repeat - do - e = e - 1; - end - ::__continue1:: -until not (e > 0); diff --git a/test/translation/lua/enum.lua b/test/translation/lua/enum.lua deleted file mode 100644 index ab48266d7..000000000 --- a/test/translation/lua/enum.lua +++ /dev/null @@ -1,7 +0,0 @@ -TestEnum = {}; -TestEnum.val1 = 0; -TestEnum[0] = "val1"; -TestEnum.val2 = 2; -TestEnum[2] = "val2"; -TestEnum.val3 = 3; -TestEnum[3] = "val3"; diff --git a/test/translation/lua/enumHeterogeneous.lua b/test/translation/lua/enumHeterogeneous.lua deleted file mode 100644 index fec3ab147..000000000 --- a/test/translation/lua/enumHeterogeneous.lua +++ /dev/null @@ -1,7 +0,0 @@ -TestEnum = {}; -TestEnum.val1 = 0; -TestEnum[0] = "val1"; -TestEnum.val2 = 3; -TestEnum[3] = "val2"; -TestEnum.val3 = "baz"; -TestEnum.baz = "val3"; diff --git a/test/translation/lua/enumMembersOnly.lua b/test/translation/lua/enumMembersOnly.lua deleted file mode 100644 index 06bdb5f70..000000000 --- a/test/translation/lua/enumMembersOnly.lua +++ /dev/null @@ -1,5 +0,0 @@ -val1 = 0; -val2 = 2; -val3 = 3; -val4 = "bye"; -local a = val1; diff --git a/test/translation/lua/enumString.lua b/test/translation/lua/enumString.lua deleted file mode 100644 index f35f146a6..000000000 --- a/test/translation/lua/enumString.lua +++ /dev/null @@ -1,7 +0,0 @@ -TestEnum = {}; -TestEnum.val1 = "foo"; -TestEnum.foo = "val1"; -TestEnum.val2 = "bar"; -TestEnum.bar = "val2"; -TestEnum.val3 = "baz"; -TestEnum.baz = "val3"; diff --git a/test/translation/lua/exportStatement.lua b/test/translation/lua/exportStatement.lua deleted file mode 100644 index 2369b004b..000000000 --- a/test/translation/lua/exportStatement.lua +++ /dev/null @@ -1,23 +0,0 @@ -local exports = exports or {}; -local xyz = 4; -exports.xyz = xyz; -exports.uwv = xyz; -do - local __TSTL_export = require("xyz"); - for ____exportKey, ____exportValue in pairs(__TSTL_export) do - exports[____exportKey] = ____exportValue; - end -end -do - local __TSTL_xyz = require("xyz"); - local abc = __TSTL_xyz.abc; - local def = __TSTL_xyz.def; - exports.abc = abc; - exports.def = def; -end -do - local __TSTL_xyz = require("xyz"); - local def = __TSTL_xyz.abc; - exports.def = def; -end -return exports; \ No newline at end of file diff --git a/test/translation/lua/for.lua b/test/translation/lua/for.lua deleted file mode 100644 index 9f0dfb360..000000000 --- a/test/translation/lua/for.lua +++ /dev/null @@ -1,9 +0,0 @@ -do - local i = 1; - while i <= 100 do - do - end - ::__continue1:: - i = i + 1; - end -end diff --git a/test/translation/lua/forIn.lua b/test/translation/lua/forIn.lua deleted file mode 100644 index 5882e705d..000000000 --- a/test/translation/lua/forIn.lua +++ /dev/null @@ -1,5 +0,0 @@ -for i in pairs({a = 1, b = 2, c = 3, d = 4}) do - do - end - ::__continue1:: -end diff --git a/test/translation/lua/forOf.lua b/test/translation/lua/forOf.lua deleted file mode 100644 index ce8676017..000000000 --- a/test/translation/lua/forOf.lua +++ /dev/null @@ -1,7 +0,0 @@ -local ____TS_array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; -for ____TS_index = 1, #____TS_array do - local i = ____TS_array[____TS_index]; - do - end - ::__continue1:: -end diff --git a/test/translation/lua/functionRestArguments.lua b/test/translation/lua/functionRestArguments.lua deleted file mode 100644 index b440062ed..000000000 --- a/test/translation/lua/functionRestArguments.lua +++ /dev/null @@ -1,3 +0,0 @@ -varargsFunction = function(self, a, ...) - local b = ({...}); -end; diff --git a/test/translation/lua/getSetAccessors.lua b/test/translation/lua/getSetAccessors.lua deleted file mode 100644 index a4188e9c7..000000000 --- a/test/translation/lua/getSetAccessors.lua +++ /dev/null @@ -1,26 +0,0 @@ -require("lualib_bundle"); -MyClass = MyClass or {}; -MyClass.__index = MyClass; -MyClass.prototype = MyClass.prototype or {}; -MyClass.prototype.____getters = {}; -MyClass.prototype.__index = __TS__Index(MyClass.prototype); -MyClass.prototype.____setters = {}; -MyClass.prototype.__newindex = __TS__NewIndex(MyClass.prototype); -MyClass.prototype.constructor = MyClass; -MyClass.new = function(...) - local self = setmetatable({}, MyClass.prototype); - self:____constructor(...); - return self; -end; -MyClass.prototype.____constructor = function(self) -end; -MyClass.prototype.____getters.field = function(self) - return self._field + 4; -end; -MyClass.prototype.____setters.field = function(self, v) - self._field = v * 2; -end; -local instance = MyClass.new(); -instance.field = 4; -local b = instance.field; -local c = (4 + instance.field) * 3; diff --git a/test/translation/lua/interfaceIndex.lua b/test/translation/lua/interfaceIndex.lua deleted file mode 100644 index a29d6d09d..000000000 --- a/test/translation/lua/interfaceIndex.lua +++ /dev/null @@ -1,2 +0,0 @@ -local a = {}; -a.abc = "def"; diff --git a/test/translation/lua/methodRestArguments.lua b/test/translation/lua/methodRestArguments.lua deleted file mode 100644 index 0f2ba1555..000000000 --- a/test/translation/lua/methodRestArguments.lua +++ /dev/null @@ -1,15 +0,0 @@ -MyClass = MyClass or {}; -MyClass.__index = MyClass; -MyClass.prototype = MyClass.prototype or {}; -MyClass.prototype.__index = MyClass.prototype; -MyClass.prototype.constructor = MyClass; -MyClass.new = function(...) - local self = setmetatable({}, MyClass.prototype); - self:____constructor(...); - return self; -end; -MyClass.prototype.____constructor = function(self) -end; -MyClass.prototype.varargsFunction = function(self, a, ...) - local b = ({...}); -end; diff --git a/test/translation/lua/modulesChangedVariableExport.lua b/test/translation/lua/modulesChangedVariableExport.lua deleted file mode 100644 index f55befe6d..000000000 --- a/test/translation/lua/modulesChangedVariableExport.lua +++ /dev/null @@ -1,3 +0,0 @@ -local exports = exports or {}; -exports.foo = 1; -return exports; diff --git a/test/translation/lua/modulesClassExport.lua b/test/translation/lua/modulesClassExport.lua deleted file mode 100644 index 48dd160d5..000000000 --- a/test/translation/lua/modulesClassExport.lua +++ /dev/null @@ -1,14 +0,0 @@ -local exports = exports or {}; -exports.TestClass = exports.TestClass or {}; -exports.TestClass.__index = exports.TestClass; -exports.TestClass.prototype = exports.TestClass.prototype or {}; -exports.TestClass.prototype.__index = exports.TestClass.prototype; -exports.TestClass.prototype.constructor = exports.TestClass; -exports.TestClass.new = function(...) - local self = setmetatable({}, exports.TestClass.prototype); - self:____constructor(...); - return self; -end; -exports.TestClass.prototype.____constructor = function(self) -end; -return exports; diff --git a/test/translation/lua/modulesClassWithMemberExport.lua b/test/translation/lua/modulesClassWithMemberExport.lua deleted file mode 100644 index f4f63ab0b..000000000 --- a/test/translation/lua/modulesClassWithMemberExport.lua +++ /dev/null @@ -1,16 +0,0 @@ -local exports = exports or {}; -exports.TestClass = exports.TestClass or {}; -exports.TestClass.__index = exports.TestClass; -exports.TestClass.prototype = exports.TestClass.prototype or {}; -exports.TestClass.prototype.__index = exports.TestClass.prototype; -exports.TestClass.prototype.constructor = exports.TestClass; -exports.TestClass.new = function(...) - local self = setmetatable({}, exports.TestClass.prototype); - self:____constructor(...); - return self; -end; -exports.TestClass.prototype.____constructor = function(self) -end; -exports.TestClass.prototype.memberFunc = function(self) -end; -return exports; diff --git a/test/translation/lua/modulesFunctionExport.lua b/test/translation/lua/modulesFunctionExport.lua deleted file mode 100644 index 7b8d3dd58..000000000 --- a/test/translation/lua/modulesFunctionExport.lua +++ /dev/null @@ -1,4 +0,0 @@ -local exports = exports or {}; -exports.publicFunc = function(self) -end; -return exports; diff --git a/test/translation/lua/modulesFunctionNoExport.lua b/test/translation/lua/modulesFunctionNoExport.lua deleted file mode 100644 index 59eb73913..000000000 --- a/test/translation/lua/modulesFunctionNoExport.lua +++ /dev/null @@ -1,2 +0,0 @@ -publicFunc = function(self) -end; diff --git a/test/translation/lua/modulesImportAll.lua b/test/translation/lua/modulesImportAll.lua deleted file mode 100644 index 334fc07a7..000000000 --- a/test/translation/lua/modulesImportAll.lua +++ /dev/null @@ -1 +0,0 @@ -local Test = require("test"); diff --git a/test/translation/lua/modulesImportNamed.lua b/test/translation/lua/modulesImportNamed.lua deleted file mode 100644 index 27cbae8c9..000000000 --- a/test/translation/lua/modulesImportNamed.lua +++ /dev/null @@ -1,2 +0,0 @@ -local __TSTL_test = require("test"); -local TestClass = __TSTL_test.TestClass; diff --git a/test/translation/lua/modulesImportNamedSpecialChars.lua b/test/translation/lua/modulesImportNamedSpecialChars.lua deleted file mode 100644 index 837c6ae21..000000000 --- a/test/translation/lua/modulesImportNamedSpecialChars.lua +++ /dev/null @@ -1,10 +0,0 @@ -local __TSTL_kebab_module = require("kebab-module"); -local TestClass = __TSTL_kebab_module.TestClass; -local __TSTL_dollar_module = require("dollar$module"); -local TestClass = __TSTL_dollar_module.TestClass; -local __TSTL_singlequote_module = require("singlequote'module"); -local TestClass = __TSTL_singlequote_module.TestClass; -local __TSTL_hash_module = require("hash#module"); -local TestClass = __TSTL_hash_module.TestClass; -local __TSTL_space_module = require("space module"); -local TestClass = __TSTL_space_module.TestClass; diff --git a/test/translation/lua/modulesImportRenamed.lua b/test/translation/lua/modulesImportRenamed.lua deleted file mode 100644 index 84c484b5d..000000000 --- a/test/translation/lua/modulesImportRenamed.lua +++ /dev/null @@ -1,2 +0,0 @@ -local __TSTL_test = require("test"); -local RenamedClass = __TSTL_test.TestClass; diff --git a/test/translation/lua/modulesImportRenamedSpecialChars.lua b/test/translation/lua/modulesImportRenamedSpecialChars.lua deleted file mode 100644 index 000113c65..000000000 --- a/test/translation/lua/modulesImportRenamedSpecialChars.lua +++ /dev/null @@ -1,10 +0,0 @@ -local __TSTL_kebab_module = require("kebab-module"); -local RenamedClass = __TSTL_kebab_module.TestClass; -local __TSTL_dollar_module = require("dollar$module"); -local RenamedClass = __TSTL_dollar_module.TestClass; -local __TSTL_singlequote_module = require("singlequote'module"); -local RenamedClass = __TSTL_singlequote_module.TestClass; -local __TSTL_hash_module = require("hash#module"); -local RenamedClass = __TSTL_hash_module.TestClass; -local __TSTL_space_module = require("space module"); -local RenamedClass = __TSTL_space_module.TestClass; diff --git a/test/translation/lua/modulesImportWithoutFromClause.lua b/test/translation/lua/modulesImportWithoutFromClause.lua deleted file mode 100644 index e7b7d56c8..000000000 --- a/test/translation/lua/modulesImportWithoutFromClause.lua +++ /dev/null @@ -1 +0,0 @@ -require("test"); diff --git a/test/translation/lua/modulesNamespaceExport.lua b/test/translation/lua/modulesNamespaceExport.lua deleted file mode 100644 index 122f64cf0..000000000 --- a/test/translation/lua/modulesNamespaceExport.lua +++ /dev/null @@ -1,6 +0,0 @@ -local exports = exports or {}; -exports.TestSpace = exports.TestSpace or {}; -local TestSpace = exports.TestSpace; -do -end -return exports; diff --git a/test/translation/lua/modulesNamespaceExportEnum.lua b/test/translation/lua/modulesNamespaceExportEnum.lua deleted file mode 100644 index 5e3997f00..000000000 --- a/test/translation/lua/modulesNamespaceExportEnum.lua +++ /dev/null @@ -1,11 +0,0 @@ -local exports = exports or {}; -exports.test = exports.test or {}; -local test = exports.test; -do - test.TestEnum = {}; - test.TestEnum.foo = "foo"; - test.TestEnum.foo = "foo"; - test.TestEnum.bar = "bar"; - test.TestEnum.bar = "bar"; -end -return exports; diff --git a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua b/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua deleted file mode 100644 index bde538a11..000000000 --- a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua +++ /dev/null @@ -1,12 +0,0 @@ -local exports = exports or {}; -exports.TestSpace = exports.TestSpace or {}; -local TestSpace = exports.TestSpace; -do - TestSpace.TestNestedSpace = TestSpace.TestNestedSpace or {}; - local TestNestedSpace = TestSpace.TestNestedSpace; - do - TestNestedSpace.innerFunc = function(self) - end; - end -end -return exports; diff --git a/test/translation/lua/modulesNamespaceNoExport.lua b/test/translation/lua/modulesNamespaceNoExport.lua deleted file mode 100644 index 9f4892365..000000000 --- a/test/translation/lua/modulesNamespaceNoExport.lua +++ /dev/null @@ -1,3 +0,0 @@ -TestSpace = TestSpace or {}; -do -end diff --git a/test/translation/lua/modulesNamespaceWithMemberExport.lua b/test/translation/lua/modulesNamespaceWithMemberExport.lua deleted file mode 100644 index 1e267f322..000000000 --- a/test/translation/lua/modulesNamespaceWithMemberExport.lua +++ /dev/null @@ -1,8 +0,0 @@ -local exports = exports or {}; -exports.TestSpace = exports.TestSpace or {}; -local TestSpace = exports.TestSpace; -do - TestSpace.innerFunc = function(self) - end; -end -return exports; diff --git a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua deleted file mode 100644 index bdbade0fe..000000000 --- a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua +++ /dev/null @@ -1,9 +0,0 @@ -local exports = exports or {}; -exports.TestSpace = exports.TestSpace or {}; -local TestSpace = exports.TestSpace; -do - local innerFunc; - innerFunc = function(self) - end; -end -return exports; diff --git a/test/translation/lua/modulesVariableExport.lua b/test/translation/lua/modulesVariableExport.lua deleted file mode 100644 index dd07ed7b8..000000000 --- a/test/translation/lua/modulesVariableExport.lua +++ /dev/null @@ -1,3 +0,0 @@ -local exports = exports or {}; -exports.foo = "bar"; -return exports; diff --git a/test/translation/lua/modulesVariableNoExport.lua b/test/translation/lua/modulesVariableNoExport.lua deleted file mode 100644 index fe16f36dc..000000000 --- a/test/translation/lua/modulesVariableNoExport.lua +++ /dev/null @@ -1 +0,0 @@ -local foo = "bar"; diff --git a/test/translation/lua/namespace.lua b/test/translation/lua/namespace.lua deleted file mode 100644 index f59170157..000000000 --- a/test/translation/lua/namespace.lua +++ /dev/null @@ -1,6 +0,0 @@ -myNamespace = myNamespace or {}; -do - local nsMember; - nsMember = function(self) - end; -end diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua deleted file mode 100644 index 7bac3efb6..000000000 --- a/test/translation/lua/namespaceMerge.lua +++ /dev/null @@ -1,35 +0,0 @@ -MergedClass = MergedClass or {}; -MergedClass.__index = MergedClass; -MergedClass.prototype = MergedClass.prototype or {}; -MergedClass.prototype.__index = MergedClass.prototype; -MergedClass.prototype.constructor = MergedClass; -MergedClass.new = function(...) - local self = setmetatable({}, MergedClass.prototype); - self:____constructor(...); - return self; -end; -MergedClass.prototype.____constructor = function(self) - self.propertyFunc = function(____) - end; -end; -MergedClass.staticMethodA = function(self) -end; -MergedClass.staticMethodB = function(self) - self:staticMethodA(); -end; -MergedClass.prototype.methodA = function(self) -end; -MergedClass.prototype.methodB = function(self) - self:methodA(); - self:propertyFunc(); -end; -MergedClass = MergedClass or {}; -do - MergedClass.namespaceFunc = function(self) - end; -end -local mergedClass = MergedClass.new(); -mergedClass:methodB(); -mergedClass:propertyFunc(); -MergedClass:staticMethodB(); -MergedClass:namespaceFunc(); diff --git a/test/translation/lua/namespaceNested.lua b/test/translation/lua/namespaceNested.lua deleted file mode 100644 index e409f968e..000000000 --- a/test/translation/lua/namespaceNested.lua +++ /dev/null @@ -1,10 +0,0 @@ -myNamespace = myNamespace or {}; -do - myNamespace.myNestedNamespace = myNamespace.myNestedNamespace or {}; - local myNestedNamespace = myNamespace.myNestedNamespace; - do - local nsMember; - nsMember = function(self) - end; - end -end diff --git a/test/translation/lua/namespacePhantom.lua b/test/translation/lua/namespacePhantom.lua deleted file mode 100644 index 63de0e172..000000000 --- a/test/translation/lua/namespacePhantom.lua +++ /dev/null @@ -1,2 +0,0 @@ -nsMember = function(self) -end; diff --git a/test/translation/lua/returnDefault.lua b/test/translation/lua/returnDefault.lua deleted file mode 100644 index 7b013615d..000000000 --- a/test/translation/lua/returnDefault.lua +++ /dev/null @@ -1,3 +0,0 @@ -myFunc = function(self) - return; -end; diff --git a/test/translation/lua/shorthandPropertyAssignment.lua b/test/translation/lua/shorthandPropertyAssignment.lua deleted file mode 100644 index 96a5da700..000000000 --- a/test/translation/lua/shorthandPropertyAssignment.lua +++ /dev/null @@ -1,4 +0,0 @@ -local f; -f = function(____, x) - return ({x = x}); -end; diff --git a/test/translation/lua/tryCatch.lua b/test/translation/lua/tryCatch.lua deleted file mode 100644 index f3194765e..000000000 --- a/test/translation/lua/tryCatch.lua +++ /dev/null @@ -1,8 +0,0 @@ -do - local ____TS_try, er = pcall(function() - local a = 42; - end); - if not ____TS_try then - local b = "fail"; - end -end diff --git a/test/translation/lua/tryCatchFinally.lua b/test/translation/lua/tryCatchFinally.lua deleted file mode 100644 index 4b5caf9a6..000000000 --- a/test/translation/lua/tryCatchFinally.lua +++ /dev/null @@ -1,11 +0,0 @@ -do - local ____TS_try, er = pcall(function() - local a = 42; - end); - if not ____TS_try then - local b = "fail"; - end - do - local c = "finally"; - end -end diff --git a/test/translation/lua/tryFinally.lua b/test/translation/lua/tryFinally.lua deleted file mode 100644 index a117b8bb2..000000000 --- a/test/translation/lua/tryFinally.lua +++ /dev/null @@ -1,8 +0,0 @@ -do - pcall(function() - local a = 42; - end); - do - local b = "finally"; - end -end diff --git a/test/translation/lua/tupleReturn.lua b/test/translation/lua/tupleReturn.lua deleted file mode 100644 index bc81abc3f..000000000 --- a/test/translation/lua/tupleReturn.lua +++ /dev/null @@ -1,28 +0,0 @@ -tupleReturn = function(self) - return 0, "foobar"; -end; -tupleReturn(_G); -noTupleReturn(_G); -local a, b = tupleReturn(_G); -local c, d = table.unpack(noTupleReturn(_G)); -a, b = tupleReturn(_G); -c, d = table.unpack(noTupleReturn(_G)); -local e = ({tupleReturn(_G)}); -local f = noTupleReturn(_G); -e = ({tupleReturn(_G)}); -f = noTupleReturn(_G); -foo(_G, ({tupleReturn(_G)})); -foo(_G, noTupleReturn(_G)); -tupleReturnFromVar = function(self) - local r = {1, "baz"}; - return table.unpack(r); -end; -tupleReturnForward = function(self) - return tupleReturn(_G); -end; -tupleNoForward = function(self) - return ({tupleReturn(_G)}); -end; -tupleReturnUnpack = function(self) - return table.unpack(tupleNoForward(_G)); -end; diff --git a/test/translation/lua/typeAssert.lua b/test/translation/lua/typeAssert.lua deleted file mode 100644 index 1c7069d36..000000000 --- a/test/translation/lua/typeAssert.lua +++ /dev/null @@ -1,2 +0,0 @@ -local test1 = 10; -local test2 = 10; diff --git a/test/translation/lua/while.lua b/test/translation/lua/while.lua deleted file mode 100644 index a779e9ded..000000000 --- a/test/translation/lua/while.lua +++ /dev/null @@ -1,7 +0,0 @@ -local d = 10; -while d > 0 do - do - d = d - 1; - end - ::__continue1:: -end diff --git a/test/translation/transformation.spec.ts b/test/translation/transformation.spec.ts new file mode 100644 index 000000000..3595da016 --- /dev/null +++ b/test/translation/transformation.spec.ts @@ -0,0 +1,15 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as util from "../util"; +import { LuaLibImportKind } from "../../src/CompilerOptions"; + +const fixturesPath = path.join(__dirname, "./transformation"); +const fixtures = fs + .readdirSync(fixturesPath) + .filter(f => path.extname(f) === ".ts") + .map(f => [path.parse(f).name, fs.readFileSync(path.join(fixturesPath, f), "utf8")]); + +test.each(fixtures)("Transformation (%s)", (_name, content) => { + const result = util.transpileString(content, { luaLibImport: LuaLibImportKind.Require }); + expect(result).toMatchSnapshot(); +}); diff --git a/test/translation/ts/callNamespace.ts b/test/translation/transformation/callNamespace.ts similarity index 100% rename from test/translation/ts/callNamespace.ts rename to test/translation/transformation/callNamespace.ts diff --git a/test/translation/ts/characterEscapeSequence.ts b/test/translation/transformation/characterEscapeSequence.ts similarity index 100% rename from test/translation/ts/characterEscapeSequence.ts rename to test/translation/transformation/characterEscapeSequence.ts diff --git a/test/translation/ts/classExtension1.ts b/test/translation/transformation/classExtension1.ts similarity index 100% rename from test/translation/ts/classExtension1.ts rename to test/translation/transformation/classExtension1.ts diff --git a/test/translation/ts/classExtension2.ts b/test/translation/transformation/classExtension2.ts similarity index 100% rename from test/translation/ts/classExtension2.ts rename to test/translation/transformation/classExtension2.ts diff --git a/test/translation/ts/classExtension3.ts b/test/translation/transformation/classExtension3.ts similarity index 100% rename from test/translation/ts/classExtension3.ts rename to test/translation/transformation/classExtension3.ts diff --git a/test/translation/ts/classExtension4.ts b/test/translation/transformation/classExtension4.ts similarity index 100% rename from test/translation/ts/classExtension4.ts rename to test/translation/transformation/classExtension4.ts diff --git a/test/translation/ts/classPureAbstract.ts b/test/translation/transformation/classPureAbstract.ts similarity index 100% rename from test/translation/ts/classPureAbstract.ts rename to test/translation/transformation/classPureAbstract.ts diff --git a/test/translation/ts/continue.ts b/test/translation/transformation/continue.ts similarity index 100% rename from test/translation/ts/continue.ts rename to test/translation/transformation/continue.ts diff --git a/test/translation/ts/continueConcurrent.ts b/test/translation/transformation/continueConcurrent.ts similarity index 100% rename from test/translation/ts/continueConcurrent.ts rename to test/translation/transformation/continueConcurrent.ts diff --git a/test/translation/ts/continueNested.ts b/test/translation/transformation/continueNested.ts similarity index 100% rename from test/translation/ts/continueNested.ts rename to test/translation/transformation/continueNested.ts diff --git a/test/translation/ts/continueNestedConcurrent.ts b/test/translation/transformation/continueNestedConcurrent.ts similarity index 100% rename from test/translation/ts/continueNestedConcurrent.ts rename to test/translation/transformation/continueNestedConcurrent.ts diff --git a/test/translation/ts/do.ts b/test/translation/transformation/do.ts similarity index 100% rename from test/translation/ts/do.ts rename to test/translation/transformation/do.ts diff --git a/test/translation/ts/enum.ts b/test/translation/transformation/enum.ts similarity index 100% rename from test/translation/ts/enum.ts rename to test/translation/transformation/enum.ts diff --git a/test/translation/ts/enumHeterogeneous.ts b/test/translation/transformation/enumHeterogeneous.ts similarity index 100% rename from test/translation/ts/enumHeterogeneous.ts rename to test/translation/transformation/enumHeterogeneous.ts diff --git a/test/translation/ts/enumMembersOnly.ts b/test/translation/transformation/enumMembersOnly.ts similarity index 100% rename from test/translation/ts/enumMembersOnly.ts rename to test/translation/transformation/enumMembersOnly.ts diff --git a/test/translation/ts/enumString.ts b/test/translation/transformation/enumString.ts similarity index 100% rename from test/translation/ts/enumString.ts rename to test/translation/transformation/enumString.ts diff --git a/test/translation/ts/exportStatement.ts b/test/translation/transformation/exportStatement.ts similarity index 100% rename from test/translation/ts/exportStatement.ts rename to test/translation/transformation/exportStatement.ts diff --git a/test/translation/ts/for.ts b/test/translation/transformation/for.ts similarity index 100% rename from test/translation/ts/for.ts rename to test/translation/transformation/for.ts diff --git a/test/translation/ts/forIn.ts b/test/translation/transformation/forIn.ts similarity index 100% rename from test/translation/ts/forIn.ts rename to test/translation/transformation/forIn.ts diff --git a/test/translation/ts/forOf.ts b/test/translation/transformation/forOf.ts similarity index 100% rename from test/translation/ts/forOf.ts rename to test/translation/transformation/forOf.ts diff --git a/test/translation/ts/functionRestArguments.ts b/test/translation/transformation/functionRestArguments.ts similarity index 100% rename from test/translation/ts/functionRestArguments.ts rename to test/translation/transformation/functionRestArguments.ts diff --git a/test/translation/ts/getSetAccessors.ts b/test/translation/transformation/getSetAccessors.ts similarity index 100% rename from test/translation/ts/getSetAccessors.ts rename to test/translation/transformation/getSetAccessors.ts diff --git a/test/translation/ts/interfaceIndex.ts b/test/translation/transformation/interfaceIndex.ts similarity index 100% rename from test/translation/ts/interfaceIndex.ts rename to test/translation/transformation/interfaceIndex.ts diff --git a/test/translation/ts/methodRestArguments.ts b/test/translation/transformation/methodRestArguments.ts similarity index 100% rename from test/translation/ts/methodRestArguments.ts rename to test/translation/transformation/methodRestArguments.ts diff --git a/test/translation/ts/modulesChangedVariableExport.ts b/test/translation/transformation/modulesChangedVariableExport.ts similarity index 100% rename from test/translation/ts/modulesChangedVariableExport.ts rename to test/translation/transformation/modulesChangedVariableExport.ts diff --git a/test/translation/ts/modulesClassExport.ts b/test/translation/transformation/modulesClassExport.ts similarity index 100% rename from test/translation/ts/modulesClassExport.ts rename to test/translation/transformation/modulesClassExport.ts diff --git a/test/translation/ts/modulesClassWithMemberExport.ts b/test/translation/transformation/modulesClassWithMemberExport.ts similarity index 100% rename from test/translation/ts/modulesClassWithMemberExport.ts rename to test/translation/transformation/modulesClassWithMemberExport.ts diff --git a/test/translation/ts/modulesFunctionExport.ts b/test/translation/transformation/modulesFunctionExport.ts similarity index 100% rename from test/translation/ts/modulesFunctionExport.ts rename to test/translation/transformation/modulesFunctionExport.ts diff --git a/test/translation/ts/modulesFunctionNoExport.ts b/test/translation/transformation/modulesFunctionNoExport.ts similarity index 100% rename from test/translation/ts/modulesFunctionNoExport.ts rename to test/translation/transformation/modulesFunctionNoExport.ts diff --git a/test/translation/ts/modulesImportAll.ts b/test/translation/transformation/modulesImportAll.ts similarity index 100% rename from test/translation/ts/modulesImportAll.ts rename to test/translation/transformation/modulesImportAll.ts diff --git a/test/translation/ts/modulesImportNamed.ts b/test/translation/transformation/modulesImportNamed.ts similarity index 100% rename from test/translation/ts/modulesImportNamed.ts rename to test/translation/transformation/modulesImportNamed.ts diff --git a/test/translation/ts/modulesImportNamedSpecialChars.ts b/test/translation/transformation/modulesImportNamedSpecialChars.ts similarity index 100% rename from test/translation/ts/modulesImportNamedSpecialChars.ts rename to test/translation/transformation/modulesImportNamedSpecialChars.ts diff --git a/test/translation/ts/modulesImportRenamed.ts b/test/translation/transformation/modulesImportRenamed.ts similarity index 100% rename from test/translation/ts/modulesImportRenamed.ts rename to test/translation/transformation/modulesImportRenamed.ts diff --git a/test/translation/ts/modulesImportRenamedSpecialChars.ts b/test/translation/transformation/modulesImportRenamedSpecialChars.ts similarity index 100% rename from test/translation/ts/modulesImportRenamedSpecialChars.ts rename to test/translation/transformation/modulesImportRenamedSpecialChars.ts diff --git a/test/translation/ts/modulesImportWithoutFromClause.ts b/test/translation/transformation/modulesImportWithoutFromClause.ts similarity index 100% rename from test/translation/ts/modulesImportWithoutFromClause.ts rename to test/translation/transformation/modulesImportWithoutFromClause.ts diff --git a/test/translation/ts/modulesNamespaceExport.ts b/test/translation/transformation/modulesNamespaceExport.ts similarity index 100% rename from test/translation/ts/modulesNamespaceExport.ts rename to test/translation/transformation/modulesNamespaceExport.ts diff --git a/test/translation/ts/modulesNamespaceExportEnum.ts b/test/translation/transformation/modulesNamespaceExportEnum.ts similarity index 100% rename from test/translation/ts/modulesNamespaceExportEnum.ts rename to test/translation/transformation/modulesNamespaceExportEnum.ts diff --git a/test/translation/ts/modulesNamespaceNestedWithMemberExport.ts b/test/translation/transformation/modulesNamespaceNestedWithMemberExport.ts similarity index 100% rename from test/translation/ts/modulesNamespaceNestedWithMemberExport.ts rename to test/translation/transformation/modulesNamespaceNestedWithMemberExport.ts diff --git a/test/translation/ts/modulesNamespaceNoExport.ts b/test/translation/transformation/modulesNamespaceNoExport.ts similarity index 100% rename from test/translation/ts/modulesNamespaceNoExport.ts rename to test/translation/transformation/modulesNamespaceNoExport.ts diff --git a/test/translation/ts/modulesNamespaceWithMemberExport.ts b/test/translation/transformation/modulesNamespaceWithMemberExport.ts similarity index 100% rename from test/translation/ts/modulesNamespaceWithMemberExport.ts rename to test/translation/transformation/modulesNamespaceWithMemberExport.ts diff --git a/test/translation/ts/modulesNamespaceWithMemberNoExport.ts b/test/translation/transformation/modulesNamespaceWithMemberNoExport.ts similarity index 100% rename from test/translation/ts/modulesNamespaceWithMemberNoExport.ts rename to test/translation/transformation/modulesNamespaceWithMemberNoExport.ts diff --git a/test/translation/ts/modulesVariableExport.ts b/test/translation/transformation/modulesVariableExport.ts similarity index 100% rename from test/translation/ts/modulesVariableExport.ts rename to test/translation/transformation/modulesVariableExport.ts diff --git a/test/translation/ts/modulesVariableNoExport.ts b/test/translation/transformation/modulesVariableNoExport.ts similarity index 100% rename from test/translation/ts/modulesVariableNoExport.ts rename to test/translation/transformation/modulesVariableNoExport.ts diff --git a/test/translation/ts/namespace.ts b/test/translation/transformation/namespace.ts similarity index 100% rename from test/translation/ts/namespace.ts rename to test/translation/transformation/namespace.ts diff --git a/test/translation/ts/namespaceMerge.ts b/test/translation/transformation/namespaceMerge.ts similarity index 100% rename from test/translation/ts/namespaceMerge.ts rename to test/translation/transformation/namespaceMerge.ts diff --git a/test/translation/ts/namespaceNested.ts b/test/translation/transformation/namespaceNested.ts similarity index 100% rename from test/translation/ts/namespaceNested.ts rename to test/translation/transformation/namespaceNested.ts diff --git a/test/translation/ts/namespacePhantom.ts b/test/translation/transformation/namespacePhantom.ts similarity index 100% rename from test/translation/ts/namespacePhantom.ts rename to test/translation/transformation/namespacePhantom.ts diff --git a/test/translation/ts/returnDefault.ts b/test/translation/transformation/returnDefault.ts similarity index 100% rename from test/translation/ts/returnDefault.ts rename to test/translation/transformation/returnDefault.ts diff --git a/test/translation/ts/shorthandPropertyAssignment.ts b/test/translation/transformation/shorthandPropertyAssignment.ts similarity index 100% rename from test/translation/ts/shorthandPropertyAssignment.ts rename to test/translation/transformation/shorthandPropertyAssignment.ts diff --git a/test/translation/ts/tryCatch.ts b/test/translation/transformation/tryCatch.ts similarity index 100% rename from test/translation/ts/tryCatch.ts rename to test/translation/transformation/tryCatch.ts diff --git a/test/translation/ts/tryCatchFinally.ts b/test/translation/transformation/tryCatchFinally.ts similarity index 100% rename from test/translation/ts/tryCatchFinally.ts rename to test/translation/transformation/tryCatchFinally.ts diff --git a/test/translation/ts/tryFinally.ts b/test/translation/transformation/tryFinally.ts similarity index 100% rename from test/translation/ts/tryFinally.ts rename to test/translation/transformation/tryFinally.ts diff --git a/test/translation/ts/tupleReturn.ts b/test/translation/transformation/tupleReturn.ts similarity index 100% rename from test/translation/ts/tupleReturn.ts rename to test/translation/transformation/tupleReturn.ts diff --git a/test/translation/ts/typeAssert.ts b/test/translation/transformation/typeAssert.ts similarity index 100% rename from test/translation/ts/typeAssert.ts rename to test/translation/transformation/typeAssert.ts diff --git a/test/translation/ts/while.ts b/test/translation/transformation/while.ts similarity index 100% rename from test/translation/ts/while.ts rename to test/translation/transformation/while.ts diff --git a/test/tsconfig.json b/test/tsconfig.json index 0c62d9606..786d64a68 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -6,5 +6,5 @@ "noEmit": true, "module": "commonjs" }, - "exclude": ["translation/ts", "compiler/projects", "compiler/testfiles"] + "exclude": ["translation/transformation", "compiler/projects", "compiler/testfiles"] } From 8c86106f5eab9420c880f9442c23ce1bbc02c1dc Mon Sep 17 00:00:00 2001 From: ark120202 Date: Tue, 26 Mar 2019 21:54:13 +0500 Subject: [PATCH 23/24] Use regular --watch flag instead of --watchAll in contributing docs --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45935e825..d298d2374 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ Due to the time required to run all tests, it is impractical to run every test w - Use `npm test name` to run tests that match a file name pattern -- Use `npm test -- --watchAll [name]` to start tests and rerun them on change +- Use `npm test -- --watch [name]` to start tests and rerun them on change - Check out `Watch Usage` in the watching interface to get information about filtering tests without restarting CLI From e5fa49a4ab83a393f4fe50d7929529749eaed365 Mon Sep 17 00:00:00 2001 From: ark120202 Date: Wed, 27 Mar 2019 00:21:22 +0500 Subject: [PATCH 24/24] Sort transformation test fixture names --- test/translation/transformation.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/translation/transformation.spec.ts b/test/translation/transformation.spec.ts index 3595da016..bd246dddf 100644 --- a/test/translation/transformation.spec.ts +++ b/test/translation/transformation.spec.ts @@ -7,6 +7,7 @@ const fixturesPath = path.join(__dirname, "./transformation"); const fixtures = fs .readdirSync(fixturesPath) .filter(f => path.extname(f) === ".ts") + .sort() .map(f => [path.parse(f).name, fs.readFileSync(path.join(fixturesPath, f), "utf8")]); test.each(fixtures)("Transformation (%s)", (_name, content) => {