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/.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..a9b94c668 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +/dist +/coverage +/test/compiler/testfiles/invalid_syntax.ts +/test/translation/transformation/characterEscapeSequence.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..d298d2374 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,59 +14,36 @@ 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/` * This directory contains all testing code for the transpiler. - * `test/src/` - - Contains all extra source and utility used to run tests. * `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. * `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 -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`. +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: -For example: -```ts -import { Expect, FocusTests, Test, TestCase } from "alsatian"; +- Use `npm test name` to run tests that match a file name pattern -@FocusTests -export class FunctionTests { - // All tests in here will be executed. -} +- Use `npm test -- --watch [name]` to start tests and rerun them on change -// All other tests will be ignored. -``` +- Check out `Watch Usage` in the watching interface to get information about filtering tests without restarting CLI -Or +- Use `.only` and `.skip` to filter executed tests in the file -```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. -``` + ```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. @@ -74,7 +51,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`. 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))` * 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..f968f5968 100644 --- a/build_lualib.ts +++ b/build_lualib.ts @@ -1,11 +1,14 @@ 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"; compile([ + "--skipLibCheck", + "--types", + "node", "--luaLibImport", "none", "--luaTarget", diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..8afb70bd0 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,18 @@ +const isCI = require("is-ci"); + +/** @type {Partial} */ +module.exports = { + testMatch: ["**/test/**/*.spec.ts"], + collectCoverageFrom: ["/src/**/*", "!/src/lualib/**/*"], + watchPathIgnorePatterns: ["/watch\\.ts$"], + + testEnvironment: "node", + testRunner: "jest-circus/runner", + preset: "ts-jest", + globals: { + "ts-jest": { + tsConfig: "/test/tsconfig.json", + diagnostics: { warnOnly: !isCI }, + }, + }, +}; diff --git a/package-lock.json b/package-lock.json index 0d029c704..861f7a478 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,3690 @@ "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-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 +4047,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 +4391,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 +4521,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 +4573,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 +5029,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 +5159,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 +5275,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 +5426,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..c99850749 100644 --- a/package.json +++ b/package.json @@ -19,34 +19,37 @@ "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", + "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}", + "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", "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": [ + "**/*.md", + "**/*.yml", + "**/.*.yml" + ], + "options": { + "tabWidth": 2 + } + } ] }, "engines": { @@ -57,16 +60,15 @@ }, "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", "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/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 0659ea527..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); @@ -105,7 +104,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 +121,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 +138,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/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 4eee5cde8..97b789989 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; @@ -3056,7 +3055,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/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 c9ef6dd3a..b0326fe3d 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/TranspileError.ts b/src/TranspileError.ts index c05b7a703..dc64f3da6 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/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/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..e82e7341b 100644 --- a/test/compiler/outfile.spec.ts +++ b/test/compiler/outfile.spec.ts @@ -1,47 +1,47 @@ -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", + "--skipLibCheck", + "--outFile", + outFileAbsPath, + path.join(__dirname, "./testfiles/out_file.ts"), + ]); + + expect(fs.existsSync(outFileAbsPath)).toBe(true); +}); + +test("Outfile relative path", () => { + compile([ + "--types", + "node", + "--skipLibCheck", + "--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..299ae7cf8 100644 --- a/test/compiler/projects/baseurl/tsconfig.json +++ b/test/compiler/projects/baseurl/tsconfig.json @@ -4,5 +4,7 @@ "outDir": "./out_dir", "rootDir": ".", "baseUrl": "./test_src/test_lib", + "types": [], + "skipLibCheck": true } } 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..ec7262ddf --- a/test/compiler/projects/basic/tsconfig.json +++ b/test/compiler/projects/basic/tsconfig.json @@ -1,3 +1,7 @@ { - "luaTarget": "JIT" + "luaTarget": "JIT", + "compilerOptions": { + "types": [], + "skipLibCheck": true + } } 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..ec7262ddf 100644 --- a/test/compiler/projects/watchmode/tsconfig.json +++ b/test/compiler/projects/watchmode/tsconfig.json @@ -1,3 +1,7 @@ { - "luaTarget": "JIT" + "luaTarget": "JIT", + "compilerOptions": { + "types": [], + "skipLibCheck": true + } } 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/watchmode.spec.ts b/test/compiler/watchmode.spec.ts index 7b838316b..2d695f698 100644 --- a/test/compiler/watchmode.spec.ts +++ b/test/compiler/watchmode.spec.ts @@ -1,68 +1,74 @@ -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: [ + "--types", + "node", + "--skipLibCheck", + "-w", + 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.ts"), [], { + silent: true, + execArgv: ["--require", "ts-node/register/transpile-only"], + }); - 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); + }, + 20000, +); 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/__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 f667a6fd0..000000000 --- a/test/translation/builder.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Expect, Test, TestCases } from "alsatian"; - -import * as util from "../src/util"; - -import * as fs from "fs"; -import * as path from "path"; - -const files: 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([tsFile, 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"); -} - -export class FileTests { - - @TestCases(files) - @Test("Transformation Tests") - public transformationTests(tsFile: string, luaFile: string) { - Expect(util.transpileString(BufferToTestString(fileContents[tsFile]))) - .toEqual(BufferToTestString(fileContents[luaFile])); - } - -} 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 aa02323b6..000000000 --- a/test/translation/lua/modulesChangedVariableExport.lua +++ /dev/null @@ -1,3 +0,0 @@ -local exports = exports or {}; -exports.test = 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 76c98810f..000000000 --- a/test/translation/lua/modulesVariableExport.lua +++ /dev/null @@ -1,3 +0,0 @@ -local exports = exports or {}; -exports.test = "test"; -return exports; diff --git a/test/translation/lua/modulesVariableNoExport.lua b/test/translation/lua/modulesVariableNoExport.lua deleted file mode 100644 index f20c4efeb..000000000 --- a/test/translation/lua/modulesVariableNoExport.lua +++ /dev/null @@ -1 +0,0 @@ -local test = "test"; 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..bd246dddf --- /dev/null +++ b/test/translation/transformation.spec.ts @@ -0,0 +1,16 @@ +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") + .sort() + .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 71% rename from test/translation/ts/callNamespace.ts rename to test/translation/transformation/callNamespace.ts index e87b7b751..43ed32d6d 100644 --- a/test/translation/ts/callNamespace.ts +++ b/test/translation/transformation/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/transformation/characterEscapeSequence.ts similarity index 84% rename from test/translation/ts/characterEscapeSequence.ts rename to test/translation/transformation/characterEscapeSequence.ts index e3ec0b741..8a7fec33e 100644 --- a/test/translation/ts/characterEscapeSequence.ts +++ b/test/translation/transformation/characterEscapeSequence.ts @@ -5,7 +5,7 @@ let doubleQuoteInQuotes = '" " "'; let doubleQuoteInDoubleQuotes = "\" \" \""; let doubleQuoteInTemplateString = `" " "`; -let backQuoteInQuotes = '` ` `'; +let backQuoteInQuotes = "` ` `"; let backQuoteInDoubleQuotes = "` ` `"; let backQuoteInTemplateString = `\` \` \``; @@ -13,4 +13,4 @@ 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/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 83% rename from test/translation/ts/classExtension2.ts rename to test/translation/transformation/classExtension2.ts index 158f16422..11145e9d5 100644 --- a/test/translation/ts/classExtension2.ts +++ b/test/translation/transformation/classExtension2.ts @@ -1,6 +1,5 @@ /** @extension */ -class TestClass { -} +class TestClass {} /** @extension */ class MyClass extends TestClass { 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 59% rename from test/translation/ts/classPureAbstract.ts rename to test/translation/transformation/classPureAbstract.ts index 178c23b59..d9a661160 100644 --- a/test/translation/ts/classPureAbstract.ts +++ b/test/translation/transformation/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/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/transformation/do.ts b/test/translation/transformation/do.ts new file mode 100644 index 000000000..c17e3d1aa --- /dev/null +++ b/test/translation/transformation/do.ts @@ -0,0 +1,4 @@ +let e = 10; +do { + e--; +} while (e > 0); diff --git a/test/translation/ts/enum.ts b/test/translation/transformation/enum.ts similarity index 78% rename from test/translation/ts/enum.ts rename to test/translation/transformation/enum.ts index a59f7ac76..3d48fbcfb 100644 --- a/test/translation/ts/enum.ts +++ b/test/translation/transformation/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/transformation/enumHeterogeneous.ts b/test/translation/transformation/enumHeterogeneous.ts new file mode 100644 index 000000000..d4e69f10b --- /dev/null +++ b/test/translation/transformation/enumHeterogeneous.ts @@ -0,0 +1,5 @@ +enum TestEnum { + val1, + val2 = 3, + val3 = "baz", +} 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/transformation/enumString.ts b/test/translation/transformation/enumString.ts new file mode 100644 index 000000000..3d7d29747 --- /dev/null +++ b/test/translation/transformation/enumString.ts @@ -0,0 +1,5 @@ +enum TestEnum { + val1 = "foo", + val2 = "bar", + val3 = "baz", +} diff --git a/test/translation/transformation/exportStatement.ts b/test/translation/transformation/exportStatement.ts new file mode 100644 index 000000000..7aa965422 --- /dev/null +++ b/test/translation/transformation/exportStatement.ts @@ -0,0 +1,6 @@ +const xyz = 4; +export { xyz }; +export { xyz as uwv }; +export * from "xyz"; +export { abc, def } from "xyz"; +export { abc as def } from "xyz"; diff --git a/test/translation/transformation/for.ts b/test/translation/transformation/for.ts new file mode 100644 index 000000000..a9dd48620 --- /dev/null +++ b/test/translation/transformation/for.ts @@ -0,0 +1 @@ +for (let i = 1; i <= 100; i++) {} diff --git a/test/translation/transformation/forIn.ts b/test/translation/transformation/forIn.ts new file mode 100644 index 000000000..8d1bff356 --- /dev/null +++ b/test/translation/transformation/forIn.ts @@ -0,0 +1,7 @@ +for (let i in { + a: 1, + b: 2, + c: 3, + d: 4, +}) { +} 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 78% rename from test/translation/ts/getSetAccessors.ts rename to test/translation/transformation/getSetAccessors.ts index b721f0f0b..d61f592a2 100644 --- a/test/translation/ts/getSetAccessors.ts +++ b/test/translation/transformation/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/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/transformation/modulesChangedVariableExport.ts b/test/translation/transformation/modulesChangedVariableExport.ts new file mode 100644 index 000000000..009c4cd06 --- /dev/null +++ b/test/translation/transformation/modulesChangedVariableExport.ts @@ -0,0 +1,2 @@ +export let foo; +foo = 1; 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/transformation/modulesImportAll.ts b/test/translation/transformation/modulesImportAll.ts new file mode 100644 index 000000000..b452afb73 --- /dev/null +++ b/test/translation/transformation/modulesImportAll.ts @@ -0,0 +1 @@ +import * as Test from "test"; diff --git a/test/translation/transformation/modulesImportNamed.ts b/test/translation/transformation/modulesImportNamed.ts new file mode 100644 index 000000000..b4c16e54b --- /dev/null +++ b/test/translation/transformation/modulesImportNamed.ts @@ -0,0 +1 @@ +import { TestClass } from "test"; diff --git a/test/translation/transformation/modulesImportNamedSpecialChars.ts b/test/translation/transformation/modulesImportNamedSpecialChars.ts new file mode 100644 index 000000000..7237d70a2 --- /dev/null +++ b/test/translation/transformation/modulesImportNamedSpecialChars.ts @@ -0,0 +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"; diff --git a/test/translation/transformation/modulesImportRenamed.ts b/test/translation/transformation/modulesImportRenamed.ts new file mode 100644 index 000000000..42129a291 --- /dev/null +++ b/test/translation/transformation/modulesImportRenamed.ts @@ -0,0 +1 @@ +import { TestClass as RenamedClass } from "test"; diff --git a/test/translation/transformation/modulesImportRenamedSpecialChars.ts b/test/translation/transformation/modulesImportRenamedSpecialChars.ts new file mode 100644 index 000000000..59e7ed862 --- /dev/null +++ b/test/translation/transformation/modulesImportRenamedSpecialChars.ts @@ -0,0 +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"; 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/transformation/modulesNamespaceExportEnum.ts b/test/translation/transformation/modulesNamespaceExportEnum.ts new file mode 100644 index 000000000..0c85b6872 --- /dev/null +++ b/test/translation/transformation/modulesNamespaceExportEnum.ts @@ -0,0 +1,6 @@ +export namespace test { + export enum TestEnum { + foo = "foo", + bar = "bar", + } +} 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/transformation/modulesVariableExport.ts b/test/translation/transformation/modulesVariableExport.ts new file mode 100644 index 000000000..d407b0602 --- /dev/null +++ b/test/translation/transformation/modulesVariableExport.ts @@ -0,0 +1 @@ +export const foo = "bar"; diff --git a/test/translation/transformation/modulesVariableNoExport.ts b/test/translation/transformation/modulesVariableNoExport.ts new file mode 100644 index 000000000..4f4b4c843 --- /dev/null +++ b/test/translation/transformation/modulesVariableNoExport.ts @@ -0,0 +1 @@ +const foo = "bar"; diff --git a/test/translation/ts/namespace.ts b/test/translation/transformation/namespace.ts similarity index 96% rename from test/translation/ts/namespace.ts rename to test/translation/transformation/namespace.ts index d9ae73274..24f4a78e0 100644 --- a/test/translation/ts/namespace.ts +++ b/test/translation/transformation/namespace.ts @@ -1,3 +1,3 @@ namespace myNamespace { function nsMember() {} -} \ No newline at end of file +} 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 97% rename from test/translation/ts/namespacePhantom.ts rename to test/translation/transformation/namespacePhantom.ts index c99b88e8d..2f003c28e 100644 --- a/test/translation/ts/namespacePhantom.ts +++ b/test/translation/transformation/namespacePhantom.ts @@ -1,4 +1,4 @@ /** @phantom */ namespace myNamespace { function nsMember() {} -} \ No newline at end of file +} 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 96% rename from test/translation/ts/tupleReturn.ts rename to test/translation/transformation/tupleReturn.ts index 0d2936071..75b7fbf01 100644 --- a/test/translation/ts/tupleReturn.ts +++ b/test/translation/transformation/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/transformation/typeAssert.ts similarity index 50% rename from test/translation/ts/typeAssert.ts rename to test/translation/transformation/typeAssert.ts index 95c751a36..4b654d851 100644 --- a/test/translation/ts/typeAssert.ts +++ b/test/translation/transformation/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/transformation/while.ts similarity index 76% rename from test/translation/ts/while.ts rename to test/translation/transformation/while.ts index 6101bd4f2..4014a4add 100644 --- a/test/translation/ts/while.ts +++ b/test/translation/transformation/while.ts @@ -1,4 +1,4 @@ let d = 10; while (d > 0) { - d--; + d--; } diff --git a/test/translation/ts/do.ts b/test/translation/ts/do.ts deleted file mode 100644 index 62b1c0a65..000000000 --- a/test/translation/ts/do.ts +++ /dev/null @@ -1,4 +0,0 @@ -let e = 10 -do { - e--; -} while (e > 0) diff --git a/test/translation/ts/enumHeterogeneous.ts b/test/translation/ts/enumHeterogeneous.ts deleted file mode 100644 index a047d66fe..000000000 --- a/test/translation/ts/enumHeterogeneous.ts +++ /dev/null @@ -1,5 +0,0 @@ -enum TestEnum { - val1, - val2 = 3, - val3 = "baz", -} diff --git a/test/translation/ts/enumString.ts b/test/translation/ts/enumString.ts deleted file mode 100644 index 8ab7e30d1..000000000 --- a/test/translation/ts/enumString.ts +++ /dev/null @@ -1,5 +0,0 @@ -enum TestEnum { - val1 = "foo", - val2 = "bar", - val3 = "baz", -} diff --git a/test/translation/ts/exportStatement.ts b/test/translation/ts/exportStatement.ts deleted file mode 100644 index 524be0bd9..000000000 --- a/test/translation/ts/exportStatement.ts +++ /dev/null @@ -1,6 +0,0 @@ -const xyz = 4; -export {xyz}; -export {xyz as uwv}; -export * 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 deleted file mode 100644 index 02d8156e2..000000000 --- a/test/translation/ts/for.ts +++ /dev/null @@ -1,2 +0,0 @@ -for (let i = 1; i <= 100; i++) { -} diff --git a/test/translation/ts/forIn.ts b/test/translation/ts/forIn.ts deleted file mode 100644 index 55e50cce7..000000000 --- a/test/translation/ts/forIn.ts +++ /dev/null @@ -1,7 +0,0 @@ -for (let i in { - a: 1, - b: 2, - c: 3, - d: 4 -}) { -} diff --git a/test/translation/ts/modulesChangedVariableExport.ts b/test/translation/ts/modulesChangedVariableExport.ts deleted file mode 100644 index 6386d1b78..000000000 --- a/test/translation/ts/modulesChangedVariableExport.ts +++ /dev/null @@ -1,2 +0,0 @@ -export let test; -test = 1; diff --git a/test/translation/ts/modulesImportAll.ts b/test/translation/ts/modulesImportAll.ts deleted file mode 100644 index 1ffb29e95..000000000 --- a/test/translation/ts/modulesImportAll.ts +++ /dev/null @@ -1 +0,0 @@ -import * as Test from "test" diff --git a/test/translation/ts/modulesImportNamed.ts b/test/translation/ts/modulesImportNamed.ts deleted file mode 100644 index 14ba1ec8d..000000000 --- a/test/translation/ts/modulesImportNamed.ts +++ /dev/null @@ -1 +0,0 @@ -import {TestClass} from "test" diff --git a/test/translation/ts/modulesImportNamedSpecialChars.ts b/test/translation/ts/modulesImportNamedSpecialChars.ts deleted file mode 100644 index cff06e7c0..000000000 --- a/test/translation/ts/modulesImportNamedSpecialChars.ts +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index bc19b6b8b..000000000 --- a/test/translation/ts/modulesImportRenamed.ts +++ /dev/null @@ -1 +0,0 @@ -import {TestClass as RenamedClass} from "test" diff --git a/test/translation/ts/modulesImportRenamedSpecialChars.ts b/test/translation/ts/modulesImportRenamedSpecialChars.ts deleted file mode 100644 index 10cc4b0cc..000000000 --- a/test/translation/ts/modulesImportRenamedSpecialChars.ts +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index dd40d81cb..000000000 --- a/test/translation/ts/modulesNamespaceExportEnum.ts +++ /dev/null @@ -1,6 +0,0 @@ -export namespace test { - export enum TestEnum { - foo = "foo", - bar = "bar", - } -} diff --git a/test/translation/ts/modulesVariableExport.ts b/test/translation/ts/modulesVariableExport.ts deleted file mode 100644 index 13f4d5b45..000000000 --- a/test/translation/ts/modulesVariableExport.ts +++ /dev/null @@ -1 +0,0 @@ -export const test = "test" diff --git a/test/translation/ts/modulesVariableNoExport.ts b/test/translation/ts/modulesVariableNoExport.ts deleted file mode 100644 index 858f3dd7c..000000000 --- a/test/translation/ts/modulesVariableNoExport.ts +++ /dev/null @@ -1 +0,0 @@ -const test = "test" diff --git a/test/tsconfig.json b/test/tsconfig.json index 7eb5d7f53..786d64a68 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/transformation", "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..fd63233df 100644 --- a/test/unit/accessors.spec.ts +++ b/test/unit/accessors.spec.ts @@ -1,412 +1,409 @@ -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..85dcb5dcb 100644 --- a/test/unit/array.spec.ts +++ b/test/unit/array.spec.ts @@ -1,150 +1,138 @@ -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..41fb9899b 100644 --- a/test/unit/assignmentDestructuring.spec.ts +++ b/test/unit/assignmentDestructuring.spec.ts @@ -1,63 +1,53 @@ -import { Expect, Test, TestCase } from "alsatian"; -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; -import * as util from "../src/util"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; +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 deleted file mode 100644 index f5d5e0ddb..000000000 --- a/test/unit/assignments.spec.ts +++ /dev/null @@ -1,1196 +0,0 @@ -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"); - -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]), -]; - -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 { - 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"); - } - - @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};`; - 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};`; - 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};`; - 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"); - } - - @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});`; - 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"); - } - - @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});`; - 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"); - } - - @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});`; - 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}; - }`; - const err = isSelfConversion - ? TSTLErrors.UnsupportedSelfFunctionConversion(undefined) - : TSTLErrors.UnsupportedNoSelfFunctionConversion(undefined); - Expect(() => util.transpileString(code, undefined, false)).toThrowError(TranspileError, err.message); - } - - @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"); - } - - @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 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"); } - } - 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); - } - -} diff --git a/test/unit/assignments/assignments.spec.ts b/test/unit/assignments/assignments.spec.ts new file mode 100644 index 000000000..4102b6d26 --- /dev/null +++ b/test/unit/assignments/assignments.spec.ts @@ -0,0 +1,196 @@ +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 */ + 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 */ + 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 { + /** @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 { + /** @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 { + /** @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 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..e393d477c --- /dev/null +++ b/test/unit/assignments/functionExpressionTypeInference.spec.ts @@ -0,0 +1,344 @@ +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)).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..3c8108c18 --- /dev/null +++ b/test/unit/assignments/invalidFunctionAssignments.spec.ts @@ -0,0 +1,206 @@ +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..86b4ce230 --- /dev/null +++ b/test/unit/assignments/validFunctionAssignments.spec.ts @@ -0,0 +1,233 @@ +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); +}); diff --git a/test/unit/bindingpatterns.spec.ts b/test/unit/bindingpatterns.spec.ts index ad0e18638..6cc1b5bc3 100644 --- a/test/unit/bindingpatterns.spec.ts +++ b/test/unit/bindingpatterns.spec.ts @@ -1,83 +1,85 @@ -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); - } + 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}; @@ -85,7 +87,6 @@ export class BindingPatternTests { let ${bindingString} = call(); return ${returnVariable}; `); - Expect(result).toBe(true); - } - -} + expect(result).toBe(true); + }, +); diff --git a/test/unit/class.spec.ts b/test/unit/class.spec.ts index 314e91853..f8f305ea0 100644 --- a/test/unit/class.spec.ts +++ b/test/unit/class.spec.ts @@ -1,835 +1,748 @@ -import { Expect, Test, TestCase } from "alsatian"; - import * as ts from "typescript"; -import * as util from "../src/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; +import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; + +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(TSTLErrors.MissingClassName(util.nodeStub)); +}); + +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 { + 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); - } - - @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"); - } -} + 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( + TSTLErrors.InvalidExtendsExtension(util.nodeStub), + ); +}); + +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( + TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub), + ); +}); + +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..2e4f8d1d2 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(); - } - } -} +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; + +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..119a91365 100644 --- a/test/unit/compiler/configuration/mixed/index.spec.ts +++ b/test/unit/compiler/configuration/mixed/index.spec.ts @@ -1,46 +1,39 @@ -import { Expect, Test } from "alsatian"; 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"; -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..47bf9bedf 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 { LuaLibImportKind, LuaTarget } from "../../../../src/CompilerOptions"; +import * as util from "../../../util"; -import * as util from "../../../src/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 }; + const result = util.transpileString("~a", options); -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); + 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..6d79a37a8 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,232 +1,216 @@ -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 { - const result = util.transpileAndExecute( - `let input: number = ${inp}; - if (input === 0) { - return 0; - } - return 1;` - ); - - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 1) - @Test("ifelse") - public ifelse(inp: number, expected: number): void { +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( + `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; } else { return 1; - }` - ); - - // Assert - Expect(result).toBe(expected); - } - - @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;` - ); - - // 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) { - return 0; - } else if (input === 1){ - return 1; - } else if (input === 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; - } - 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; - } - 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; - } - 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;` + }`, ); - // Assert - Expect(result).toBe(expected); - } - - @TestCase(0, 0) - @TestCase(1, 2) - @TestCase(2, 2) - @Test("switchLocalScope") - public switchLocalScope(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 result: number = -1; @@ -246,157 +230,151 @@ export class LuaConditionalsTests { break; } } - return result;` + 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; + 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; + break; + case 1: + return 1; + case 2: + return 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 }, +])("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, -1) - @Test("switchWithBrackets") - public switchWithBrackets(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; - } + case 1: { + result = 1; + 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 2: { + result = 2; + 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; + } + 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; + } + case 1: { + result = 1; - for (let i = 0; i < 5; i++) { - result++; + if (result == 1) break; + } + case 2: { + result = 2; + break; + } + } + 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++; - if (i >= 2) { - break; - } + if (i >= 2) { + break; } } - case 1: { - result++; - 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."); - } -} + case 1: { + result++; + break; + } + case 2: { + result = 2; + break; + } + } + 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( + TSTLErrors.UnsupportedForTarget("Switch statements", LuaTarget.Lua51, util.nodeStub), + ); +}); 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..a4181b009 100644 --- a/test/unit/declarations.spec.ts +++ b/test/unit/declarations.spec.ts @@ -1,124 +1,94 @@ -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..9ff43c51d 100644 --- a/test/unit/decoratorCustomConstructor.spec.ts +++ b/test/unit/decoratorCustomConstructor.spec.ts @@ -1,52 +1,47 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; -import { TranspileError } from "../../src/TranspileError"; +test("CustomCreate", () => { + const luaHeader = ` + function Point2DCreate(x, y) + return {x = x, y = y} + end + `; -export class DecoratorCustomConstructor -{ - @Test("CustomCreate") - public customCreate(): void { - 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( + TSTLErrors.InvalidDecoratorArgumentNumber("@customConstructor", 0, 1, util.nodeStub), + ); +}); diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index 6fdedf191..eb574cc62 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -1,63 +1,51 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../src/util"; - -import { TranspileError } from "../../src/TranspileError"; import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; -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", () => { + expect(() => { + util.transpileString(` + /** @metaExtension */ + class LoadedExt { + public static test() { + return 5; } - ` - ); - }).toThrowError(TranspileError, expectedMessage); - } + } + `); + }).toThrowExactError(TSTLErrors.MissingMetaExtension(util.nodeStub)); +}); - @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(TSTLErrors.InvalidNewExpressionOnExtension(util.nodeStub)); +}); diff --git a/test/unit/enum.spec.ts b/test/unit/enum.spec.ts index d21b695c4..cbb0fbe15 100644 --- a/test/unit/enum.spec.ts +++ b/test/unit/enum.spec.ts @@ -1,191 +1,174 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/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" +import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; + +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(() => { + util.transpileString(` + enum TestEnum { + a, + b = "ok", + c, } - - 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}\`;` - ); - - 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(TSTLErrors.HeterogeneousEnum(util.nodeStub)); +}); + +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..f91a22269 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,37 +1,22 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util"; +import { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; -import { TranspileError } from "../../src/TranspileError"; +test("throwString", () => { + const lua = util.transpileString(`throw "Some Error"`); + expect(lua).toBe(`error("Some Error");`); +}); -export class LuaErrorTests { +test("throwError", () => { + expect(() => { + const lua = util.transpileString(`throw Error("Some Error")`); + }).toThrowExactError(TSTLErrors.InvalidThrowExpression(util.nodeStub)); +}); - @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."); - } - - @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}; +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 { @@ -53,26 +38,27 @@ export class LuaErrorTests { } catch (e) { result = (e as string)[(e as string).length - 1]; } - return result;`; + return result; + `; const result = util.transpileAndExecute(source); - Expect(result).toBe(expected); - } + 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..e1acbfa18 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -1,528 +1,554 @@ -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 { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; 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 +import * as util from "../util"; + +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( - "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 { + 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( + TSTLErrors.UnsupportedKind( + "right shift operator (use >>> instead)", + ts.SyntaxKind.GreaterThanGreaterThanToken, + util.nodeStub, + ), + ); +}); + +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 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); +}); + +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 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); +}); + +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 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); +}); + +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( + TSTLErrors.UnsupportedKind( + "unary postfix operator", + ts.SyntaxKind.AsteriskToken, + util.nodeStub, + ), + ); +}); + +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( + 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)).toThrowExactError( + TSTLErrors.UnsupportedForTarget( + "string property fromCodePoint", + LuaTarget.LuaJIT, + util.nodeStub, + ), + ); +}); + +test("Unknown string expression error", () => { + const transformer = util.makeTestTransformer(LuaTarget.LuaJIT); + + const identifier = ts.createIdentifier("abcd"); + expect(() => transformer.transformStringExpression(identifier)).toThrowExactError( + TSTLErrors.UnsupportedForTarget("string property abcd", LuaTarget.LuaJIT, util.nodeStub), + ); +}); + +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(TSTLErrors.UnsupportedProperty("array", "unknownFunction", util.nodeStub)); +}); + +test("Unsupported math property error", () => { + const transformer = util.makeTestTransformer(); + + expect(() => + transformer.transformMathExpression(ts.createIdentifier("unknownProperty")), + ).toThrowExactError(TSTLErrors.UnsupportedProperty("math", "unknownProperty", util.nodeStub)); +}); + +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( + 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 55161623b..d36dddcdf 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -1,104 +1,83 @@ -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 { - // 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 = (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 { +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);`); + + 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 @@ -106,253 +85,229 @@ export class FunctionTests { 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); - } + 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; - } +test("Class dot method call with parameter", () => { + const returnValue = 4; + const source = `class TestClass { + public dotMethod: (x: number) => number = x => 3 * x; + } - const classInstance = new TestClass(); - return classInstance.dotMethod(${returnValue});`; + const classInstance = new TestClass(); + return classInstance.dotMethod(${returnValue});`; - // Transpile - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - // Assert - Expect(result).toBe(3 * returnValue); - } + expect(result).toBe(3 * returnValue); +}); - @Test("Class static dot method") - public classDotMethodStatic(): void { - const returnValue = 4; - const source = `class TestClass { - public static dotMethod: () => number = () => ${returnValue}; - } +test("Class static dot method", () => { + const returnValue = 4; + const source = `class TestClass { + public static dotMethod: () => number = () => ${returnValue}; + } - return TestClass.dotMethod();`; + return TestClass.dotMethod();`; - // Transpile/Execute - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - // Assert - Expect(result).toBe(returnValue); - } + expect(result).toBe(returnValue); +}); - @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; - } +test("Class static dot method with parameter", () => { + const returnValue = 4; + const source = `class TestClass { + public static dotMethod: (x: number) => number = x => 3 * x; + } - return TestClass.dotMethod(${returnValue});`; + return TestClass.dotMethod(${returnValue});`; - // Transpile - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - // Assert - Expect(result).toBe(3 * returnValue); - } + expect(result).toBe(3 * returnValue); +}); - @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");`; +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");`; - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - Expect(result).toBe("4bc"); - } + expect(result).toBe("4bc"); +}); - @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"]);`; +test("Function apply", () => { + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } + return abc.apply({ a: 4 }, ["b"]);`; - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - Expect(result).toBe("4b"); - } + expect(result).toBe("4b"); +}); - @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");`; +test("Function call", () => { + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } + return abc.call({ a: 4 }, "b");`; - const result = util.transpileAndExecute(source); + const result = util.transpileAndExecute(source); - Expect(result).toBe("4b"); - } + expect(result).toBe("4b"); +}); - @Test("Invalid property access call transpilation") - public invalidPropertyCall(): void { - const transformer = util.makeTestTransformer(); +test("Invalid property access call transpilation", () => { + const transformer = util.makeTestTransformer(); - const mockObject: any = { - expression: ts.createLiteral("abc"), - }; + const mockObject: any = { + expression: ts.createLiteral("abc"), + }; - Expect(() => transformer.transformPropertyCall(mockObject as ts.CallExpression)) - .toThrowError(Error, "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") - public functionDeadCodeAfterReturn(): void { - const result = util.transpileAndExecute( - `function abc() { return 3; const a = 5; } return abc();`); +test("Function dead code after return", () => { + const result = util.transpileAndExecute( + `function abc() { return 3; const a = 5; } return abc();`, + ); - Expect(result).toBe(3); - } + expect(result).toBe(3); +}); - @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();`); +test("Method dead code after return", () => { + 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("Recursive function definition") - public recursiveFunctionDefinition(): void { - const result = util.transpileAndExecute( - `function f() { return typeof f; }; return f();`); +test("Recursive function definition", () => { + const result = util.transpileAndExecute(`function f() { return typeof f; }; return f();`); - Expect(result).toBe("function"); - } + expect(result).toBe("function"); +}); - @Test("Recursive function expression") - public recursiveFunctionExpression(): void { - const result = util.transpileAndExecute( - `let f = function() { return typeof f; }; return f();`); +test("Recursive function expression", () => { + const result = util.transpileAndExecute(`let f = function() { return typeof f; }; return f();`); - Expect(result).toBe("function"); - } + expect(result).toBe("function"); +}); - @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();`); +test("Wrapped recursive function expression", () => { + 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("Recursive arrow function") - public recursiveArrowFunction(): void { - const result = util.transpileAndExecute( - `let f = () => typeof f; return f();`); +test("Recursive arrow function", () => { + const result = util.transpileAndExecute(`let f = () => typeof f; return f();`); - Expect(result).toBe("function"); - } + expect(result).toBe("function"); +}); - @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();`); +test("Wrapped recursive arrow function", () => { + 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("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); - } - - @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("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(); - } - } - 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 result = util.transpileAndExecute( - `class MyClass { +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.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 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; } @@ -361,66 +316,67 @@ export class FunctionTests { } } 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 { + 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") - public elementAccessCallNoArgs(): void { - const code = `class C { + `; + 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"); - } + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("bar"); +}); - @Test("Complex element access call") - public elementAccessCallComplex(): void { - const code = `class C { +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"); - } + `; + const result = util.transpileAndExecute(code); + expect(result).toBe("foobar"); +}); - @Test("Complex element access call no args") - public elementAccessCallComplexNoArgs(): void { - const code = `class C { +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") - public elementAccessCallComplexStatement(): void { - const code = `let foo: string; + `; + 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; } @@ -428,54 +384,56 @@ export class FunctionTests { 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; `; 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 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); - } - - @TestCase(1, false) - @TestCase(2, true) - @Test("Generator functions done") - public generatorFunctionDone(iterations: number, expectedResult: boolean): void { - 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; + expect(result).toBe(expectedResult); + }, +); + +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 result = util.transpileAndExecute(code); - Expect(result).toBe(expectedResult); - } + expect(result).toBe(expectedResult); + }, +); - @Test("Generator for..of") - public generatorFunctionForOf(): void { - const code = `function* seq() { +test("Generator for..of", () => { + const code = ` + function* seq() { yield(1); yield(2); yield(3); @@ -486,41 +444,40 @@ export class FunctionTests { { result = result * 10 + i; } - 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"); - } - - @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"); - `); + return result + `; + const result = util.transpileAndExecute(code); + expect(result).toBe(123); +}); + +test("Function local overriding export", () => { + 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", () => { + 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 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..215d38c49 100644 --- a/test/unit/hoisting.spec.ts +++ b/test/unit/hoisting.spec.ts @@ -1,257 +1,245 @@ 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 { TSTLErrors } from "../../src/TSTLErrors"; +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, - `Identifier "${identifier}" was referenced before it was declared. The declaration ` + - "must be moved before the identifier's use, or hoisting must be enabled." - ); - } -} + } + 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( + TSTLErrors.ReferencedBeforeDeclaration(ts.createIdentifier(identifier)), + ); +}); diff --git a/test/unit/importexport.spec.ts b/test/unit/importexport.spec.ts index 7aca64caf..cd98b0b4f 100644 --- a/test/unit/importexport.spec.ts +++ b/test/unit/importexport.spec.ts @@ -1,17 +1,12 @@ -import { Expect, Test, TestCase } from "alsatian"; - -import * as util from "../src/util"; import { TSTLErrors } from "../../src/TSTLErrors"; -import { TranspileError } from "../../src/TranspileError"; +import * as util from "../util"; -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 => { + expect(() => util.transpileString(exportStatement)).toThrowExactError( + TSTLErrors.UnsupportedDefaultExport(util.nodeStub), + ); +}); diff --git a/test/unit/json.spec.ts b/test/unit/json.spec.ts index 7ac15a776..337e5676f 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 { TSTLErrors } from "../../src/TSTLErrors"; +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(TSTLErrors.InvalidJsonFileContent(util.nodeStub)); +}); diff --git a/test/unit/loops.spec.ts b/test/unit/loops.spec.ts index 153e243b2..d87f019fd 100644 --- a/test/unit/loops.spec.ts +++ b/test/unit/loops.spec.ts @@ -1,35 +1,25 @@ -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 - { - 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);` - ); - - // Assert - 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 - { +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( + `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; @@ -50,17 +40,16 @@ export class LuaLoopTests i++; } - return JSONStringify(arrTest);` + 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("dowhile with continue") - public dowhileWithContinue(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; @@ -81,49 +70,42 @@ export class LuaLoopTests i++; } while (i < arrTest.length) - return JSONStringify(arrTest);` + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @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);` - ); - // Assert - 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 - { + 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: number; for (i = 0 * 1; 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, 4], [0, 0, 2, 0, 4]) - @Test("for with continue") - public forWithContinue(inp: number[], expected: number[]): void - { - // Transpile +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)}; for (let i = 0; i < arrTest.length; i++) { @@ -138,68 +120,60 @@ export class LuaLoopTests arrTest[i] = j; } } - 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("forMirror") - public forMirror(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; arrTest.length > i; i++) { arrTest[i] = arrTest[i] + 1; } - return JSONStringify(arrTest);` + return JSONStringify(arrTest);`, ); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @TestCase([0, 1, 2, 3], [0, 1, 2, 3]) - @Test("forBreak") - public forBreak(inp: number[], expected: number[]): void - { - 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);` - ); - - // 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);` + 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("forNoCondition") - public forNoCondition(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; @@ -210,17 +184,16 @@ export class LuaLoopTests 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] }])( + "forNoPostExpression (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let arrTest = ${JSON.stringify(inp)}; let i = 0; @@ -233,79 +206,94 @@ export class LuaLoopTests i++; } - return JSONStringify(arrTest);` + return JSONStringify(arrTest);`, ); - // Assert - 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 - { - 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)); + }, +); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @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); - } - - @TestCase({ ["test1"]: 0, ["test2"]: 1, ["test3"]: 2 }, { ["test1"]: 1, ["test2"]: 2, ["test3"]: 3 }) - @Test("forin[Object]") - public forinObject(inp: any, expected: any): void +test.each([ + { inp: [0, 1, 2, 3], expected: [1, 2, 3, 4], header: "let i = 0; i < arrTest.length; i++" }, { - const result = util.transpileAndExecute( - `let objTest = ${JSON.stringify(inp)}; - for (let key in objTest) { - objTest[key] = objTest[key] + 1; - } - return JSONStringify(objTest);` - ); - - // 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."); - } - - @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 + 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(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 } }])( + "forin with continue (%p)", + ({ inp, expected }) => { const result = util.transpileAndExecute( `let obj = ${JSON.stringify(inp)}; for (let i in obj) { @@ -315,35 +303,29 @@ export class LuaLoopTests obj[i] = 0; } - return JSONStringify(obj); - ` - ); - - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @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 = []; @@ -351,34 +333,32 @@ export class LuaLoopTests for (value of objTest) { arrResultTest.push(value + 1) } - return JSONStringify(arrResultTest);` + 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);` + 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 = []; @@ -387,17 +367,16 @@ export class LuaLoopTests for ([a,b] of objTest) { arrResultTest.push(a + b) } - return JSONStringify(arrResultTest);` + 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; @@ -415,414 +394,416 @@ export class LuaLoopTests } a++; } - return JSONStringify(testArr);` + 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"); - } - - @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 */ + expect(result).toBe(JSON.stringify(expected)); + }, +); + +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( + TSTLErrors.UnsupportedNonDestructuringLuaIterator(util.nodeStub), + ); +}); + +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( + TSTLErrors.UnsupportedNonDestructuringLuaIterator(util.nodeStub), + ); +}); + +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..f4a6e2b45 100644 --- a/test/unit/lualib/inlining.spec.ts +++ b/test/unit/lualib/inlining.spec.ts @@ -1,50 +1,44 @@ -import { Expect, Test } from "alsatian"; -import * as util from "../../src/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); - } -} +import * as util from "../../util"; + +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..8c4052562 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -1,521 +1,486 @@ -import { Expect, Test, TestCase } from "alsatian"; -import * as ts from "typescript"; -import * as util from "../../src/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}; - }));` +import * as util from "../../util"; + +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)); - } + expect(result).toBe(expected); + }, +); - @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 - { - 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);` - ); - } +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);`, + ); - // Assert - if (deleteCount) { - inp.splice(start, deleteCount, ...newElements); - Expect(result).toBe(JSON.stringify(inp)); - } else { - inp.splice(start); - Expect(result).toBe(JSON.stringify(inp)); - } - } + expect(result).toBe(JSON.stringify([0].concat(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 +test.each([ + { array: "[1, 2, 3]", expected: [3, 2] }, + { array: "[1, 2, 3, null]", expected: [3, 2] }, +])("array.pop (%p)", ({ array, expected }) => { { - 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); - } - - @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)); + expect(result).toBe(expected[0]); } - - @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`); + let val = testArray.shift(); + return val`, + ); - // Assert - Expect(result).toBe(expected[1]); + expect(result).toBe(expectedValue); } } - - @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 +}); + +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}; - let val = testArray.reverse(); - return JSONStringify(testArray)`); - // Assert - Expect(result).toBe(JSON.stringify(expected)); - } - - @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); - } - } - } - @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 + array: ["4", "5", "3", "2", "1"], + compareStr: "tonumber(a) - tonumber(b)", + compareFn: (a: any, b: any) => Number(a) - Number(b), + }, { - const result = util.transpileAndExecute( - `let testArray = ${array}; - testArray.unshift(${toUnshift}); - return JSONStringify(testArray)`); - - // Assert - Expect(result).toBe(JSON.stringify(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("[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 - { - 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 - { - 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); - } - - @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..149ee258f 100644 --- a/test/unit/lualib/map.spec.ts +++ b/test/unit/lualib/map.spec.ts @@ -1,169 +1,149 @@ -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..1fce6ceb7 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.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 (%p)", ({ 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 a15b79664..51be6c70e 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); + `); - 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); + `); - 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..51b5df8d8 100644 --- a/test/unit/lualib/weakMap.spec.ts +++ b/test/unit/lualib/weakMap.spec.ts @@ -1,134 +1,122 @@ -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 (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 e4425618e..1b50a4756 100644 --- a/test/unit/lualib/weakSet.spec.ts +++ b/test/unit/lualib/weakSet.spec.ts @@ -1,87 +1,79 @@ -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 (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/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..c02f052de 100644 --- a/test/unit/modules.spec.ts +++ b/test/unit/modules.spec.ts @@ -1,78 +1,65 @@ -import { Expect, Test, TestCase } from "alsatian"; import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; +import { TSTLErrors } from "../../src/TSTLErrors"; +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(TSTLErrors.DefaultImportsNotSupported(util.nodeStub)); +}); -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..747ce7b7a 100644 --- a/test/unit/require.spec.ts +++ b/test/unit/require.spec.ts @@ -1,48 +1,113 @@ -import { Expect, FocusTest, Test, TestCase } from "alsatian"; +import * as util from "../util"; -import * as util from "../src/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..3bb7ff981 100644 --- a/test/unit/spreadElement.spec.ts +++ b/test/unit/spreadElement.spec.ts @@ -1,49 +1,37 @@ -import { Expect, Test, TestCase } from "alsatian"; +import { LuaLibImportKind, LuaTarget } from "../../src/CompilerOptions"; +import * as util from "../util"; -import { LuaTarget, LuaLibImportKind } from "../../src/CompilerOptions"; -import * as util from "../src/util"; +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)); + }, +); -export class SpreadElementTest { +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}));"); +}); - @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("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.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.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 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.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 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..2b7cd4362 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -1,340 +1,256 @@ -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 { TSTLErrors } from "../../src/TSTLErrors"; +import * as util from "../util"; + +test("Unsuported string function", () => { + expect(() => { + util.transpileString(`return "test".testThisIsNoMember()`); + }).toThrowExactError( + TSTLErrors.UnsupportedProperty("string", "testThisIsNoMember", util.nodeStub), + ); +}); + +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..6e1b0d9df 100644 --- a/test/unit/tshelper.spec.ts +++ b/test/unit/tshelper.spec.ts @@ -1,10 +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 { DecoratorKind } from "../../src/Decorator"; +import { TSHelper as tsHelper } from "../../src/TSHelper"; +import * as util from "../util"; enum TestEnum { testA = 1, @@ -12,149 +9,153 @@ 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 5de08527b..41fa43676 100644 --- a/test/unit/tuples.spec.ts +++ b/test/unit/tuples.spec.ts @@ -1,388 +1,353 @@ -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 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"); +}); + +test("Tuple Return on Type Alias", () => { + const code = ` + /** @tupleReturn */ type Fn = () => [number, number]; + const fn: Fn = () => [1, 2]; + const [a, b] = fn(); + return a + b; + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe(3); +}); + +test("Tuple Return on Interface", () => { + const code = ` + /** @tupleReturn */ interface Fn { (): [number, number]; } + const fn: Fn = () => [1, 2]; + const [a, b] = fn(); + return a + b; + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe(3); +}); + +test("Tuple Return on Interface Signature", () => { + const code = ` + interface Fn { + /** @tupleReturn */ (): [number, number]; + } + const fn: Fn = () => [1, 2]; + const [a, b] = fn(); + return a + b; + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe(3); +}); + +test("Tuple Return on Overload", () => { + const code = ` + function fn(a: number): number; + /** @tupleReturn */ function fn(a: string, b: string): [string, string]; + function fn(a: number | string, b?: string): number | [string, string] { + if (typeof a === "number") { + return a; + } else { + return [a, b as string]; } - return bar(...foo());`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("foobar"); - } - - @Test("Tuple Return on Type Alias") - public tupleReturnOnTypeAlias(): void { - const code = - `/** @tupleReturn */ type Fn = () => [number, number]; - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b;`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe(3); - } - - @Test("Tuple Return on Interface") - public tupleReturnOnInterface(): void { - const code = - `/** @tupleReturn */ interface Fn { (): [number, number]; } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b;`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe(3); - } - - @Test("Tuple Return on Interface Signature") - public tupleReturnOnInterfaceSignature(): void { - const code = - `interface Fn { - /** @tupleReturn */ (): [number, number]; + } + const a = fn(3); + const [b, c] = fn("foo", "bar"); + return a + b + c + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("3foobar"); +}); + +test("Tuple Return on Interface Overload", () => { + const code = ` + interface Fn { + (a: number): number; + /** @tupleReturn */ (a: string, b: string): [string, string]; + } + const fn = ((a: number | string, b?: string): number | [string, string] => { + if (typeof a === "number") { + return a; + } else { + return [a, b as string]; } - const fn: Fn = () => [1, 2]; - const [a, b] = fn(); - return a + b;`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe(3); - } - - @Test("Tuple Return on Overload") - public tupleReturnOnOverload(): void { - const code = - `function fn(a: number): number; - /** @tupleReturn */ function fn(a: string, b: string): [string, string]; - function fn(a: number | string, b?: string): number | [string, string] { + }) as Fn; + const a = fn(3); + const [b, c] = fn("foo", "bar"); + return a + b + c + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("3foobar"); +}); + +test("Tuple Return on Interface Method Overload", () => { + const code = ` + interface Foo { + foo(a: number): number; + /** @tupleReturn */ foo(a: string, b: string): [string, string]; + } + const bar = ({ + foo: (a: number | string, b?: string): number | [string, string] => { if (typeof a === "number") { return a; } else { return [a, b as string]; } } - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("3foobar"); - } - - @Test("Tuple Return on Interface Overload") - public tupleReturnOnInterfaceOverload(): void { - const code = - `interface Fn { - (a: number): number; - /** @tupleReturn */ (a: string, b: string): [string, string]; - } - const fn = ((a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - }) as Fn; - const a = fn(3); - const [b, c] = fn("foo", "bar"); - return a + b + c`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("3foobar"); - } - - @Test("Tuple Return on Interface Method Overload") - public tupleReturnOnInterfaceMethodOverload(): void { - const code = - `interface Foo { - foo(a: number): number; - /** @tupleReturn */ foo(a: string, b: string): [string, string]; - } - const bar = ({ - foo: (a: number | string, b?: string): number | [string, string] => { - if (typeof a === "number") { - return a; - } else { - return [a, b as string]; - } - } - }) as Foo; - const a = bar.foo(3); - const [b, c] = bar.foo("foo", "bar"); - return a + b + c`; - const lua = util.transpileString(code); - Expect(lua).not.toContain("unpack"); - const result = util.executeLua(lua); - Expect(result).toBe("3foobar"); - } - - @Test("Tuple Return vs Non-Tuple Return Overload") - public tupleReturnVsNonTupleReturnOverload(): void { - const luaHeader = - `function fn(a, b) - if type(a) == "number" then - return {a, a + 1} - else - return a, b - end - end`; - const tsHeader = - `declare function fn(this: void, a: number): [number, number]; - /** @tupleReturn */ declare function fn(this: void, a: string, b: string): [string, string];`; - const code = - `const [a, b] = fn(3); - const [c, d] = fn("foo", "bar"); - return (a + b) + c + d;`; - const result = util.transpileAndExecute(code, undefined, luaHeader, tsHeader); - Expect(result).toBe("7foobar"); - } -} + }) as Foo; + const a = bar.foo(3); + const [b, c] = bar.foo("foo", "bar"); + return a + b + c + `; + const lua = util.transpileString(code); + expect(lua).not.toContain("unpack"); + const result = util.executeLua(lua); + expect(result).toBe("3foobar"); +}); + +test("Tuple Return vs Non-Tuple Return Overload", () => { + const luaHeader = ` + function fn(a, b) + if type(a) == "number" then + return {a, a + 1} + else + return a, b + end + end + `; + const tsHeader = ` + declare function fn(this: void, a: number): [number, number]; + /** @tupleReturn */ declare function fn(this: void, a: string, b: string): [string, string]; + `; + const code = ` + const [a, b] = fn(3); + const [c, d] = fn("foo", "bar"); + return (a + b) + c + d; + `; + const result = util.transpileAndExecute(code, undefined, luaHeader, tsHeader); + expect(result).toBe("7foobar"); +}); diff --git a/test/unit/typechecking.spec.ts b/test/unit/typechecking.spec.ts index 533c0d3d0..e52337405 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 { 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(); - } -} +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};`); + + 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 {} + 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 {} + class childClass extends myClass{} + 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( + TSTLErrors.InvalidInstanceOfExtension(util.nodeStub), + ); +}); + +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..73d338434 100644 --- a/test/src/util.ts +++ b/test/util.ts @@ -1,47 +1,86 @@ +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"; + +export const nodeStub = ts.createNode(ts.SyntaxKind.Unknown); + +declare global { + namespace jest { + interface Matchers { + toThrowExactError(error: Error): void; + } + } +} -import { Expect } from "alsatian"; +expect.extend({ + toThrowExactError( + callback: () => 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 { + callback(); + } catch (err) { + executionError = err; + } -import {lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari"; + expect(() => { + if (executionError) throw executionError; + }).toThrowError(error.constructor as any); + expect(() => { + if (executionError) throw executionError; + }).toThrowError(error); -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 { + return compilerTranspileString( + str, + { + luaLibImport: LuaLibImportKind.Inline, + luaTarget: LuaTarget.Lua53, + noHeader: true, + skipLibCheck: true, + 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", + ], + ...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 +100,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 +114,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 +125,13 @@ export function transpileAndExecute( compilerOptions?: CompilerOptions, luaHeader?: string, tsHeader?: string, - ignoreDiagnosticsOverride = process.argv[2] === "--ignoreDiagnostics" -): any -{ +): 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, false)} return __runTest();`; return executeLua(lua); @@ -113,9 +141,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 +154,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 +178,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..178f3066d 100644 --- a/tslint.json +++ b/tslint.json @@ -1,55 +1,12 @@ { - "defaultSeverity": "error", + "extends": "./test/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" + ] + } }