From 4d56cfd11a777200eb520dbced988e90a1477178 Mon Sep 17 00:00:00 2001 From: Evgeniy Okolnov Date: Fri, 21 Apr 2023 15:18:53 +0300 Subject: [PATCH] TS Linter. Move sources to separate folder. Change-Id: I04f0666cea64bd796d6369a9dcd45ca913109e8e Signed-off-by: Evgeniy Okolnov --- linter/.gitattributes | 12 + linter/.gitignore | 9 + linter/README.md | 57 + linter/bin/tslinter.js | 4 + linter/package-lock.json | 1475 +++++ linter/package.json | 33 + linter/src/CommandLineParser.ts | 136 + linter/src/CookBookMsg.ts | 4351 ++++++++++++++ linter/src/LinterRunner.ts | 261 + linter/src/Problems.ts | 562 ++ linter/src/TestRunner.ts | 137 + linter/src/TypeScriptLinter.ts | 1512 +++++ linter/src/Utils.ts | 199 + .../cookbook_convertor/cookbook_convertor.ts | 354 ++ linter/src/cookbook_convertor/recipes.rst | 5100 +++++++++++++++++ linter/src/main.ts | 18 + linter/test/array_literals.ts | 86 + linter/test/array_literals.ts.relax.json | 78 + linter/test/array_literals.ts.strict.json | 278 + linter/test/bigint.ts | 22 + linter/test/bigint.ts.relax.json | 53 + linter/test/bigint.ts.strict.json | 53 + linter/test/binary_wrong_types.ts | 96 + linter/test/binary_wrong_types.ts.relax.json | 213 + linter/test/binary_wrong_types.ts.strict.json | 213 + linter/test/catch_clause.ts | 37 + linter/test/catch_clause.ts.relax.json | 43 + linter/test/catch_clause.ts.strict.json | 68 + linter/test/class_static_block.ts | 36 + linter/test/class_static_block.ts.relax.json | 21 + linter/test/class_static_block.ts.strict.json | 21 + linter/test/conditional_types.ts | 53 + linter/test/conditional_types.ts.relax.json | 93 + linter/test/conditional_types.ts.strict.json | 113 + linter/test/constructor_types.ts | 62 + linter/test/constructor_types.ts.relax.json | 28 + linter/test/constructor_types.ts.strict.json | 48 + linter/test/controlflow_non_boolean.ts | 46 + .../controlflow_non_boolean.ts.relax.json | 38 + .../controlflow_non_boolean.ts.strict.json | 68 + linter/test/delete_operator.ts | 44 + linter/test/delete_operator.ts.relax.json | 78 + linter/test/delete_operator.ts.strict.json | 128 + linter/test/destructuring.ts | 98 + linter/test/destructuring.ts.relax.json | 58 + linter/test/destructuring.ts.strict.json | 318 + linter/test/for_stmts.ts | 66 + linter/test/for_stmts.ts.relax.json | 103 + linter/test/for_stmts.ts.strict.json | 133 + linter/test/func_def_params.ts | 26 + linter/test/func_def_params.ts.relax.json | 28 + linter/test/func_def_params.ts.strict.json | 43 + linter/test/func_def_type_params.ts | 22 + .../test/func_def_type_params.ts.relax.json | 17 + .../test/func_def_type_params.ts.strict.json | 33 + linter/test/function_overload.ts | 100 + linter/test/function_overload.ts.relax.json | 218 + linter/test/function_overload.ts.strict.json | 248 + linter/test/function_spread_arg.ts | 21 + linter/test/function_spread_arg.ts.relax.json | 28 + .../test/function_spread_arg.ts.strict.json | 43 + linter/test/functions.ts | 116 + linter/test/functions.ts.relax.json | 58 + linter/test/functions.ts.strict.json | 213 + linter/test/generators.ts | 73 + linter/test/generators.ts.relax.json | 163 + linter/test/generators.ts.strict.json | 208 + linter/test/implements_class.ts | 31 + linter/test/implements_class.ts.relax.json | 41 + linter/test/implements_class.ts.strict.json | 41 + linter/test/infered_type.ts | 20 + linter/test/infered_type.ts.relax.json | 33 + linter/test/infered_type.ts.strict.json | 48 + linter/test/instanceof.ts | 30 + linter/test/instanceof.ts.relax.json | 38 + linter/test/instanceof.ts.strict.json | 38 + linter/test/interfaces_optional_props.ts | 30 + .../interfaces_optional_props.ts.relax.json | 43 + .../interfaces_optional_props.ts.strict.json | 48 + linter/test/interfaces_props.ts | 59 + linter/test/interfaces_props.ts.relax.json | 108 + linter/test/interfaces_props.ts.strict.json | 123 + linter/test/jsx.tsx | 25 + linter/test/jsx.tsx.relax.json | 38 + linter/test/jsx.tsx.strict.json | 63 + linter/test/mapped_types.ts | 65 + linter/test/mapped_types.ts.relax.json | 138 + linter/test/mapped_types.ts.strict.json | 138 + linter/test/modules.ts | 99 + linter/test/modules.ts.relax.json | 123 + linter/test/modules.ts.strict.json | 243 + linter/test/object_literals.ts | 96 + linter/test/object_literals.ts.relax.json | 68 + linter/test/object_literals.ts.strict.json | 363 ++ linter/test/object_runtime_check.ts | 52 + .../test/object_runtime_check.ts.relax.json | 253 + .../test/object_runtime_check.ts.strict.json | 293 + linter/test/object_spread.ts | 22 + linter/test/object_spread.ts.relax.json | 33 + linter/test/object_spread.ts.strict.json | 43 + linter/test/parameter_properties.ts | 35 + .../test/parameter_properties.ts.relax.json | 23 + .../test/parameter_properties.ts.strict.json | 38 + linter/test/string_literal_type.ts | 24 + linter/test/string_literal_type.ts.relax.json | 53 + .../test/string_literal_type.ts.strict.json | 58 + linter/test/switch_statements.ts | 52 + linter/test/switch_statements.ts.relax.json | 58 + linter/test/switch_statements.ts.strict.json | 63 + linter/test/template_literals.ts | 42 + linter/test/template_literals.ts.relax.json | 28 + linter/test/template_literals.ts.strict.json | 83 + linter/test/this_type.ts | 53 + linter/test/this_type.ts.relax.json | 58 + linter/test/this_type.ts.strict.json | 63 + linter/test/type_declarations.ts | 94 + linter/test/type_declarations.ts.relax.json | 118 + linter/test/type_declarations.ts.strict.json | 143 + linter/test/types.ts | 139 + linter/test/types.ts.relax.json | 298 + linter/test/types.ts.strict.json | 388 ++ linter/test/unary_wrong_types.ts | 33 + linter/test/unary_wrong_types.ts.relax.json | 78 + linter/test/unary_wrong_types.ts.strict.json | 78 + linter/test/unique_names.ts | 113 + linter/test/unique_names.ts.relax.json | 328 ++ linter/test/unique_names.ts.strict.json | 443 ++ linter/test/update-test-results.bat | 16 + linter/test/update-test-results.mjs | 73 + linter/test/update-test-results.sh | 18 + linter/test/var_declarations.ts | 37 + linter/test/var_declarations.ts.relax.json | 28 + linter/test/var_declarations.ts.strict.json | 78 + linter/test_linter.sh | 25 + linter/tsconfig.json | 15 + linter/tslinter.cmd | 18 + linter/tslinter.sh | 22 + linter/webpack.config.js | 14 + 138 files changed, 24985 insertions(+) create mode 100644 linter/.gitattributes create mode 100644 linter/.gitignore create mode 100644 linter/README.md create mode 100644 linter/bin/tslinter.js create mode 100644 linter/package-lock.json create mode 100644 linter/package.json create mode 100644 linter/src/CommandLineParser.ts create mode 100644 linter/src/CookBookMsg.ts create mode 100644 linter/src/LinterRunner.ts create mode 100644 linter/src/Problems.ts create mode 100644 linter/src/TestRunner.ts create mode 100644 linter/src/TypeScriptLinter.ts create mode 100644 linter/src/Utils.ts create mode 100644 linter/src/cookbook_convertor/cookbook_convertor.ts create mode 100644 linter/src/cookbook_convertor/recipes.rst create mode 100644 linter/src/main.ts create mode 100644 linter/test/array_literals.ts create mode 100644 linter/test/array_literals.ts.relax.json create mode 100644 linter/test/array_literals.ts.strict.json create mode 100644 linter/test/bigint.ts create mode 100644 linter/test/bigint.ts.relax.json create mode 100644 linter/test/bigint.ts.strict.json create mode 100644 linter/test/binary_wrong_types.ts create mode 100644 linter/test/binary_wrong_types.ts.relax.json create mode 100644 linter/test/binary_wrong_types.ts.strict.json create mode 100644 linter/test/catch_clause.ts create mode 100644 linter/test/catch_clause.ts.relax.json create mode 100644 linter/test/catch_clause.ts.strict.json create mode 100644 linter/test/class_static_block.ts create mode 100644 linter/test/class_static_block.ts.relax.json create mode 100644 linter/test/class_static_block.ts.strict.json create mode 100644 linter/test/conditional_types.ts create mode 100644 linter/test/conditional_types.ts.relax.json create mode 100644 linter/test/conditional_types.ts.strict.json create mode 100644 linter/test/constructor_types.ts create mode 100644 linter/test/constructor_types.ts.relax.json create mode 100644 linter/test/constructor_types.ts.strict.json create mode 100644 linter/test/controlflow_non_boolean.ts create mode 100644 linter/test/controlflow_non_boolean.ts.relax.json create mode 100644 linter/test/controlflow_non_boolean.ts.strict.json create mode 100644 linter/test/delete_operator.ts create mode 100644 linter/test/delete_operator.ts.relax.json create mode 100644 linter/test/delete_operator.ts.strict.json create mode 100644 linter/test/destructuring.ts create mode 100644 linter/test/destructuring.ts.relax.json create mode 100644 linter/test/destructuring.ts.strict.json create mode 100644 linter/test/for_stmts.ts create mode 100644 linter/test/for_stmts.ts.relax.json create mode 100644 linter/test/for_stmts.ts.strict.json create mode 100644 linter/test/func_def_params.ts create mode 100644 linter/test/func_def_params.ts.relax.json create mode 100644 linter/test/func_def_params.ts.strict.json create mode 100644 linter/test/func_def_type_params.ts create mode 100644 linter/test/func_def_type_params.ts.relax.json create mode 100644 linter/test/func_def_type_params.ts.strict.json create mode 100644 linter/test/function_overload.ts create mode 100644 linter/test/function_overload.ts.relax.json create mode 100644 linter/test/function_overload.ts.strict.json create mode 100644 linter/test/function_spread_arg.ts create mode 100644 linter/test/function_spread_arg.ts.relax.json create mode 100644 linter/test/function_spread_arg.ts.strict.json create mode 100644 linter/test/functions.ts create mode 100644 linter/test/functions.ts.relax.json create mode 100644 linter/test/functions.ts.strict.json create mode 100644 linter/test/generators.ts create mode 100644 linter/test/generators.ts.relax.json create mode 100644 linter/test/generators.ts.strict.json create mode 100644 linter/test/implements_class.ts create mode 100644 linter/test/implements_class.ts.relax.json create mode 100644 linter/test/implements_class.ts.strict.json create mode 100644 linter/test/infered_type.ts create mode 100644 linter/test/infered_type.ts.relax.json create mode 100644 linter/test/infered_type.ts.strict.json create mode 100644 linter/test/instanceof.ts create mode 100644 linter/test/instanceof.ts.relax.json create mode 100644 linter/test/instanceof.ts.strict.json create mode 100644 linter/test/interfaces_optional_props.ts create mode 100644 linter/test/interfaces_optional_props.ts.relax.json create mode 100644 linter/test/interfaces_optional_props.ts.strict.json create mode 100644 linter/test/interfaces_props.ts create mode 100644 linter/test/interfaces_props.ts.relax.json create mode 100644 linter/test/interfaces_props.ts.strict.json create mode 100644 linter/test/jsx.tsx create mode 100644 linter/test/jsx.tsx.relax.json create mode 100644 linter/test/jsx.tsx.strict.json create mode 100644 linter/test/mapped_types.ts create mode 100644 linter/test/mapped_types.ts.relax.json create mode 100644 linter/test/mapped_types.ts.strict.json create mode 100644 linter/test/modules.ts create mode 100644 linter/test/modules.ts.relax.json create mode 100644 linter/test/modules.ts.strict.json create mode 100644 linter/test/object_literals.ts create mode 100644 linter/test/object_literals.ts.relax.json create mode 100644 linter/test/object_literals.ts.strict.json create mode 100644 linter/test/object_runtime_check.ts create mode 100644 linter/test/object_runtime_check.ts.relax.json create mode 100644 linter/test/object_runtime_check.ts.strict.json create mode 100644 linter/test/object_spread.ts create mode 100644 linter/test/object_spread.ts.relax.json create mode 100644 linter/test/object_spread.ts.strict.json create mode 100644 linter/test/parameter_properties.ts create mode 100644 linter/test/parameter_properties.ts.relax.json create mode 100644 linter/test/parameter_properties.ts.strict.json create mode 100644 linter/test/string_literal_type.ts create mode 100644 linter/test/string_literal_type.ts.relax.json create mode 100644 linter/test/string_literal_type.ts.strict.json create mode 100644 linter/test/switch_statements.ts create mode 100644 linter/test/switch_statements.ts.relax.json create mode 100644 linter/test/switch_statements.ts.strict.json create mode 100644 linter/test/template_literals.ts create mode 100644 linter/test/template_literals.ts.relax.json create mode 100644 linter/test/template_literals.ts.strict.json create mode 100644 linter/test/this_type.ts create mode 100644 linter/test/this_type.ts.relax.json create mode 100644 linter/test/this_type.ts.strict.json create mode 100644 linter/test/type_declarations.ts create mode 100644 linter/test/type_declarations.ts.relax.json create mode 100644 linter/test/type_declarations.ts.strict.json create mode 100644 linter/test/types.ts create mode 100644 linter/test/types.ts.relax.json create mode 100644 linter/test/types.ts.strict.json create mode 100644 linter/test/unary_wrong_types.ts create mode 100644 linter/test/unary_wrong_types.ts.relax.json create mode 100644 linter/test/unary_wrong_types.ts.strict.json create mode 100644 linter/test/unique_names.ts create mode 100644 linter/test/unique_names.ts.relax.json create mode 100644 linter/test/unique_names.ts.strict.json create mode 100644 linter/test/update-test-results.bat create mode 100644 linter/test/update-test-results.mjs create mode 100644 linter/test/update-test-results.sh create mode 100644 linter/test/var_declarations.ts create mode 100644 linter/test/var_declarations.ts.relax.json create mode 100644 linter/test/var_declarations.ts.strict.json create mode 100644 linter/test_linter.sh create mode 100644 linter/tsconfig.json create mode 100644 linter/tslinter.cmd create mode 100644 linter/tslinter.sh create mode 100644 linter/webpack.config.js diff --git a/linter/.gitattributes b/linter/.gitattributes new file mode 100644 index 000000000..49fa7aca7 --- /dev/null +++ b/linter/.gitattributes @@ -0,0 +1,12 @@ +#Set defaul end of lines for all files +* text eol=lf + +# Denote all image files as binary +*.png binary +*.jpg binary +*.gif binary + +# Denote library files as binary +*.jar binary +*.dll binary +*.lib binary \ No newline at end of file diff --git a/linter/.gitignore b/linter/.gitignore new file mode 100644 index 000000000..2173b2130 --- /dev/null +++ b/linter/.gitignore @@ -0,0 +1,9 @@ +build +dist +bundle +node_modules +*.tsbuildinfo +.vs +.vscode +.cache +test/**/results \ No newline at end of file diff --git a/linter/README.md b/linter/README.md new file mode 100644 index 000000000..42ceb68e4 --- /dev/null +++ b/linter/README.md @@ -0,0 +1,57 @@ +# TypeScript linter +Typescript linter ( further mentioned as 'linter' ) is a tool to check typescript sources and find language elements +and constructions which are deprecated to use in a purpose to migrate sources to STS. +The linter is currently under development. + +## Prerequisits + +### Visual Studio Code +For development, it's recommended to use `VS Code`, as it has a full built-in support for TypeScript language. + +### NodeJS and NPM +Install the latest stable version of `NodeJS` and `NPM`. It is recommended using a `Node version manager` to install Node and NPM ([nvm](https://github.com/nvm-sh/nvm) for Linux; [nvm-windows](https://github.com/coreybutler/nvm-windows) for windows - v1.1.9 is the most stable). You can also follow the [official guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). + +## Building + +Run the following command to install all project dependencies and build the project: + +```bash +npm install +``` + +Run the following command to only build project sources: + +```bash +npm run build +``` + +## Running +Run the following command from the same directory: +```bash +node dist/tslinter.ts [options] [input files] +``` + +You can also use command files `tslinter.sh` or `tslinter.cmd` with same arguments as for direct launch. + +Possible command options: + +`--deveco-plugin-mode` - this options defines special mode to launch from IDE and shouldn't be used when running from command line. + +`--strict` - defines 'strict' mode in which all problematic TypeScript language elements are counted; if this option is not set, linter works in 'relax' mode in which counts only elements that cannot be transpiled by TypeScript migrator. + +`--project-folder ` - defines path to folder with TypeScript sources and subfolders which linter walks recurscevely. This option may be repeated in command line with different paths. + +`-p, --project ` - defines path to TS project configuration file (commonly known as tsconfig.json). + +`-E, --TSC_Errors` - enables logging messages about compilation errors and unresolved symbols. + +All other command line arguments are considered as paths to TypeScript files. + +To prevent command line buffer overflow, response file may be used. It is specified by adding `@` prefix to file name (e.g.: `tslinter.sh @response-file.txt` ). Response file should contain TypeScript source paths (one at each line). The response file argument should be the last command argument (any following argument will be ignored). + +## Running tests + +Run the following command: +```bash +node test +``` diff --git a/linter/bin/tslinter.js b/linter/bin/tslinter.js new file mode 100644 index 000000000..f0084059d --- /dev/null +++ b/linter/bin/tslinter.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +"use strict" + +require("../dist/tslinter.js") diff --git a/linter/package-lock.json b/linter/package-lock.json new file mode 100644 index 000000000..234107d9b --- /dev/null +++ b/linter/package-lock.json @@ -0,0 +1,1475 @@ +{ + "name": "@panda/ts-linter", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@panda/ts-linter", + "version": "1.0.0", + "bundleDependencies": [ + "typescript" + ], + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "typescript": "4.8.4" + }, + "bin": { + "ts-linter": "bin/tslinter.js" + }, + "devDependencies": { + "@types/node": "18.11.7", + "rimraf": "^3.0.2", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@types/eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.7.tgz", + "integrity": "sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", + "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", + "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", + "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", + "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", + "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", + "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", + "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", + "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", + "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", + "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", + "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/helper-wasm-section": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-opt": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5", + "@webassemblyjs/wast-printer": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", + "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", + "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", + "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", + "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001480", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz", + "integrity": "sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.368", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.368.tgz", + "integrity": "sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", + "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", + "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "inBundle": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.80.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", + "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.13.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + } +} diff --git a/linter/package.json b/linter/package.json new file mode 100644 index 000000000..6ba8c9a97 --- /dev/null +++ b/linter/package.json @@ -0,0 +1,33 @@ +{ + "name": "@panda/tslinter", + "version": "1.0.0", + "main": "dist/tslinter.js", + "bin": "bin/tslinter.js", + "files": [ + "dist/*" + ], + "private": true, + "license": "Apache-2.0", + "scripts": { + "tsc": "tsc", + "webpack":"webpack -t node --config webpack.config.js", + "clean": "rimraf build dist bundle", + "compile": "npm run tsc", + "build": "npm run clean && npm run compile && npm run webpack && npm run pack:linter", + "postinstall": "npm run build", + "pack:linter": "rimraf bundle && mkdir bundle && npm pack --pack-destination bundle", + "test": "npm run compile && rimraf test/results && node build/TestRunner.js" + }, + "dependencies": { + "typescript": "4.8.4" + }, + "devDependencies": { + "@types/node": "18.11.7", + "rimraf": "^3.0.2", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1" + }, + "bundledDependencies": [ + "typescript" + ] +} diff --git a/linter/src/CommandLineParser.ts b/linter/src/CommandLineParser.ts new file mode 100644 index 000000000..adbda0320 --- /dev/null +++ b/linter/src/CommandLineParser.ts @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; +import * as fs from "node:fs"; + +const TS_EXT = ".ts"; +const TSX_EXT = ".tsx"; + +export interface CommandLineOptions { + Strict_Mode?: boolean; + IDE_Mode?: boolean; + TSC_Errors?: boolean; + ParsedConfigFile?: ts.ParsedCommandLine; + InputFiles: string[]; +} + +var getFiles = (dir: string): string[] => { + let resultFiles: string[] = []; + + var files = fs.readdirSync(dir); + for (var i in files){ + var name = dir + '/' + files[i]; + if (fs.statSync(name).isDirectory()) { + resultFiles.push(...getFiles(name)); + } else { + name = name.trimEnd(); + if(name.endsWith(TS_EXT) || name.endsWith(TSX_EXT)) + resultFiles.push(name); + } + } + + return resultFiles; +}; + +export function parseCommandLine(commandLineArgs: string[]): CommandLineOptions { + let opts: CommandLineOptions = { InputFiles: [] }; + + let argc = 0; + while (argc < commandLineArgs.length) { + let arg = commandLineArgs[argc]; + + if (arg[0] === '@') { + // Process arguments from the specified response file. Any following + // argument on the command-line will be ignored. + // Note: The 'filter(e => e)' call is used to remove empty strings + // from parsed argument list. + try { + commandLineArgs = fs.readFileSync(arg.slice(1)).toString().split("\n").filter(e => e.trimEnd()); + argc = 0; + continue; + } catch (error: any) { + console.error("Failed to read response file: " + (error.message ?? error)); + } + } + else if(arg === "--project-folder") { + ++argc; + if (argc >= commandLineArgs.length) { + console.log("Command line error: no argument for option:", arg); + process.exit(-1); + } + + try { + opts.InputFiles.push(...getFiles(commandLineArgs[argc])); + } catch (error: any) { + console.error("Failed to read folder: " + (error.message ?? error)); + process.exit(-1); + } + } + else if (arg === "--strict") { + opts.Strict_Mode = true; + } + else if (arg ==="-E" || arg ==="--TSC_Errors") { + opts.TSC_Errors = true; + } + else if (arg === "--deveco-plugin-mode") { + opts.IDE_Mode = true; + } + else if (arg === "-p" || arg === "--project") { + ++argc; + if (argc >= commandLineArgs.length) { + console.log("Command line error: no argument for option:", arg); + process.exit(-1); + } + + // Process project file (tsconfig.json) and retrieve config arguments. + let configFile = commandLineArgs[argc]; + + let host: ts.ParseConfigFileHost = ts.sys as any; + let diagnostics: ts.Diagnostic[] = []; + + try { + host.onUnRecoverableConfigFileDiagnostic = (diagnostic: ts.Diagnostic) => { diagnostics.push(diagnostic); }; + opts.ParsedConfigFile = ts.getParsedCommandLineOfConfigFile(configFile, {}, host); + host.onUnRecoverableConfigFileDiagnostic = undefined; + + diagnostics.push(...ts.getConfigFileParsingDiagnostics(opts.ParsedConfigFile)); + if (diagnostics.length > 0) { + // Log all diagnostic messages and exit program. + console.log("Failed to read config file."); + diagnostics.forEach(diagnostic => { + if (diagnostic.file) { + let { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); + let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } else { + console.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); + } + }); + process.exit(-1); + } + } catch (error: any) { + console.error("Failed to read config file: " + (error.message ?? error)); + process.exit(-1); + } + } + else { + opts.InputFiles.push(arg); + } + argc++; + } + + return opts; +} \ No newline at end of file diff --git a/linter/src/CookBookMsg.ts b/linter/src/CookBookMsg.ts new file mode 100644 index 000000000..bac1ac478 --- /dev/null +++ b/linter/src/CookBookMsg.ts @@ -0,0 +1,4351 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export var cookBookMsg: string[] = []; + +export var cookBookTag: string[] = []; + +cookBookMsg[ 1 ] = " \ + #1: Objects with property names that are not identifiers are not supported
\ +
Rule
\ + \ +ArkTS does not support Objects with name properties that are numbers or \ +strings. Use classes to access data by property names. Use arrays to access data \ +by numeric indices. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +   var x = {\"name\": 1, 2: 3}
\ +
\ +   console.log(x[\"name\"])
\ +   console.log(x[2])
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class X {
\ +        public name: number
\ +    }
\ +    let x = {name: 1}
\ +    console.log(x.name)
\ +
\ +    let y = [1, 2, 3]
\ +    console.log(y[2])
\ +
\ +    // If you still need a container to store keys of different types,
\ +    // use Map:
\ +    let z = new Map()
\ +    z.set(\"name\", 1)
\ +    z.set(2, 2)
\ +    console.log(z.get(\"name\"))
\ +    console.log(z.get(2))
\ +
\ +

\ +"; + +cookBookMsg[ 2 ] = " \ + #2: Symbol() API is not supported
\ +
Rule
\ + \ +ArkTS does not support Symbol() API. \ + \ +
\ +
TypeScript
\ + \ +TypeScript has Symbol() API, which can be used among other things to generate \ +unique property names at runtime: \ + \ + \ +
\ +    const sym = Symbol()
\ +    let o = {
\ +       [sym]: \"value\"
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ +ArkTS does not support Symbol() API because its most popular use cases \ +make no sense in the statically typed environment. In particular, the object \ +layout is defined at compile time and cannot be changed at runtime. \ + \ +"; + +cookBookMsg[ 3 ] = " \ + #3: Private '#' identifiers are not supported
\ +
Rule
\ + \ +ArkTS does not private identifiers started with # symbol, use private keyword instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class C {
\ +      foo = 1
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class C {
\ +      private foo = 1
\ +    }
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 4 ] = " \ + #4: Use unique names for types, namespaces, etc.
\ +
Rule
\ + \ +Names for types, namespaces and so on must be unique and distinct from other \ +names, e.g., variable names. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let X: string
\ +    type X = number[] // Type alias with the same name as the variable
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let X: string
\ +    type T = number[] // X is not allowed here to avoid name collisions
\ +
\ +

\ +"; + +cookBookMsg[ 5 ] = " \ + #5: Use let instead of var
\ +
Rule
\ + \ +ArkTS does not support var, always use let instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function f(shouldInitialize: boolean) {
\ +        if (shouldInitialize) {
\ +           var x = 10
\ +        }
\ +        return x
\ +    }
\ +
\ +    console.log(f(true)) // 10
\ +    console.log(f(false)) // undefined
\ +
\ +    let upper_let = 0
\ +    {
\ +        var scoped_var = 0
\ +        let scoped_let = 0
\ +        upper_let = 5
\ +    }
\ +    scoped_var = 5 // Visible
\ +    scoped_let = 5 // Compile-time error
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function f(shouldInitialize: boolean): Object {
\ +        let x: Object = new Object();
\ +        if (shouldInitialize) {
\ +            x = 10
\ +        }
\ +        return x
\ +    }
\ +
\ +   console.log(f(true)); // 10
\ +   console.log(f(false)); // {}
\ +
\ +    let upper_let = 0
\ +    let scoped_var = 0
\ +    {
\ +        let scoped_let = 0
\ +        upper_let = 5
\ +    }
\ +    scoped_var = 5
\ +    scoped_let = 5 // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 8 ] = " \ + #8: Use explicit types instead of any, undefined, unknown
\ +
Rule
\ + \ +ArkTS does not support any, undefined, and unknown types. \ +Specify types explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    var x
\ +    console.log(x) // undefined
\ +
\ +    var y: any
\ +    console.log(y) // undefined
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // All variables should have their types specified explicitly:
\ +    let x: Object = {}
\ +    console.log(x) // {}
\ +
\ +

\ +"; + +cookBookMsg[ 9 ] = " \ + #9: You can extend your TypeScript code with more numeric types
\ +
Rule
\ + \ +ArkTS supports different numeric types on top of just number. \ + \ +
\ +
TypeScript
\ + \ +TypeScript supports number as the only numeric type: \ + \ + \ +
\ +    let x: number = 1
\ +
\ +

\ +
ArkTS
\ + \ +ArkTS supports several numeric types: \ + \ ++-----------+----------+-------------------------------------------------------------+ \ +| Type | Size | Range | \ ++===========+==========+=============================================================+ \ +|byte | 8 bits |[-128 .. 127] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|short | 16 bits |[-32,768 .. 32,767] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|int | 32 bits |[-2,147,483,648 .. 2,147,483,647] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|long | 64 bits |[-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807]| \ ++-----------+----------+-------------------------------------------------------------+ \ +|ubyte | 8 bits |[0 .. 255] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|ushort | 16 bits |[0 .. 65,535] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|uint | 32 bits |[0 .. 4,294,967,295] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|ulong | 64 bits |[0 .. 18,446,744,073,709,551,615] | \ ++-----------+----------+-------------------------------------------------------------+ \ +|float | 32 bits |3.4E +/- 38 (7 digits) | \ ++-----------+----------+-------------------------------------------------------------+ \ +|double | 64 bits |1.7E +/- 308 (15 digits) | \ ++-----------+----------+-------------------------------------------------------------+ \ + \ +Additionally, ArkTS supports the following types: \ + \ +* Character type char (the range of values is the same as ushort) \ +* Boolean type boolean (values: true, false) \ + \ + \ +
\ +    let x: int = 1
\ +    let y: boolean = true
\ +    let z: char = 'a'
\ +
\ +

\ +"; + +cookBookMsg[ 10 ] = " \ + #10: Use long instead of bigint
\ +
Rule
\ + \ +Use long to work with 64-bit integers. \ + \ +
\ +
TypeScript
\ + \ +TypeScript supports bigint data type, but this feature is available only since \ +ES2020 and requires n suffix for numeric literals: \ + \ + \ +
\ +    let a: bigint = 1n
\ +
\ +

\ +
ArkTS
\ + \ +ArkTS provides long data type to work with 64-bit \ +integers, n suffix is not supported: \ + \ + \ +
\ +    let x: long = 1
\ +
\ +

\ +"; + +cookBookMsg[ 11 ] = " \ + #11: Use enum instead of string literal types
\ +
Rule
\ + \ +ArkTS does not support string literal types. Use enum instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    type Easing = \"ease-in\" | \"ease-out\" | \"ease-in-out\";
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    enum Easing {EaseIn, EaseOut, EaseInOut}
\ +
\ +

\ +"; + +cookBookMsg[ 12 ] = " \ + #12: Use T[] instead of Array to declare arrays
\ +
Rule
\ + \ +In TypeScript, arrays can be declared as either Array or T[]. Currently, \ +ArkTS supports only the second syntax for array declaration. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // These are equivalent in TypeScript:
\ +    let y: Array = [\"1\", \"2\", \"3\"]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +   let x: string[] = [\"1\", \"2\", \"3\"];
\ +   let y: string[] = [\"1\", \"2\", \"3\"]; // Array is not supported currently
\ +
\ +

\ +"; + +cookBookMsg[ 13 ] = " \ + #13: Use Object[] instead of tuples
\ +
Rule
\ + \ +Currently, ArkTS does not support tuples. You can use arrays of Object \ +(Object[]) to emulate tuples. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    var t: [number, string] = [3, \"three\"]
\ +    var n = t[0]
\ +    var s = t[1]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let t: Object[] = [3, \"three\"]
\ +    let n = t[0]
\ +    let s = t[1]
\ +
\ +

\ +"; + +cookBookMsg[ 14 ] = " \ + #14: Use class instead of a type with call signature
\ +
Rule
\ + \ +ArkTS does not support call signatures in object types. Use classes instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    type DescribableFunction = {
\ +        description: string
\ +        (someArg: number): string // call signature
\ +    }
\ +
\ +    function doSomething(fn: DescribableFunction): void {
\ +        console.log(fn.description + \" returned \" + fn(6))
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class DescribableFunction {
\ +        description: string;
\ +        public invoke(someArg: number): string {
\ +            return someArg.toString()
\ +        }
\ +        constructor() {
\ +            this.description = \"desc\"
\ +        }
\ +    }
\ +
\ +    function doSomething(fn: DescribableFunction): void {
\ +        console.log(fn.description + \" returned \" + fn.invoke(6))
\ +    }
\ +
\ +    doSomething(new DescribableFunction());
\ +
\ +

\ +"; + +cookBookMsg[ 15 ] = " \ + #15: Use class instead of a type with constructor signature
\ +
Rule
\ + \ +ArkTS does not support constructor signatures in object types. Use classes \ +instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class SomeObject {}
\ +
\ +    type SomeConstructor = {
\ +        new (s: string): SomeObject
\ +    }
\ +
\ +    function fn(ctor: SomeConstructor) {
\ +        return new ctor(\"hello\");
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class SomeObject {
\ +        public f: string
\ +        constructor (s: string) {
\ +            this.f = s
\ +        }
\ +    }
\ +
\ +    function fn(s: string): SomeObject {
\ +        return new SomeObject(s)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 16 ] = " \ + #16: Only one static block is supported
\ +
Rule
\ + \ +ArkTS does not allow to have sevaral static block for class initialization, combine static blocks statements to the one static block. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class C {
\ +        static s: string
\ +
\ +        static {
\ +            C.s = \"aa\"
\ +        }
\ +        static {
\ +            C.s = C.s + \"bb\"
\ +        }
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +
\ +    class C {
\ +        static s: string
\ +
\ +        static {
\ +            C.s = \"aa\"
\ +            C.s = C.s + \"bb\"
\ +        }
\ +    }
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 17 ] = " \ + #17: Indexed signatures are not supported
\ +
Rule
\ + \ +ArkTS does not allow indexed signatures, use arrays instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // Interface with an indexed signature:
\ +    interface StringArray {
\ +        [index: number]: string
\ +    }
\ +
\ +    const myArray: StringArray = getStringArray()
\ +    const secondItem = myArray[1]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class X {
\ +        public f: string[]
\ +    }
\ +
\ +    let myArray: X = new X()
\ +    const secondItem = myArray.f[1]
\ +
\ +

\ +"; + +cookBookMsg[ 18 ] = " \ + #18: Use Object instead of union types
\ +
Rule
\ + \ +Currently, ArkTS provides limited support for union types; \ +nullable types are supported only in the form T | null. \ +You can use Object to emulate the behaviour of the unions in standard TypeScript. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    var x: string | number
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let x: Object
\ +
\ +    x = 2
\ +    console.log(x)
\ +
\ +    x = \"2\"
\ +    console.log(x)
\ +
\ +

\ +"; + +cookBookMsg[ 19 ] = " \ + #19: Use inheritance instead of intersection types
\ +
Rule
\ + \ +Currently, ArkTS does not support intersection types. You can use inheritance \ +as a work-around. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface Identity {
\ +        id: number
\ +        name: string
\ +    }
\ +
\ +    interface Contact {
\ +        email: string
\ +        phone: string
\ +    }
\ +
\ +    type Employee = Identity & Contact
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface Identity {
\ +        id: number
\ +        name: string
\ +    }
\ +
\ +    interface Contact {
\ +        email: string
\ +        phone: string
\ +    }
\ +
\ +    interface Employee extends Identity, Contact {}
\ +
\ +

\ +"; + +cookBookMsg[ 20 ] = " \ + #20: Default values for type parameters in generics are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support default values for type parameters. Use \ +generic parameters without default values instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // Declare a generic function:
\ +    function foo() {...}
\ +
\ +    // Call the function:
\ +    foo() // foo() will be called
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // Declare a generic function:
\ +    function foo() {...}
\ +
\ +    // Call the function:
\ +    foo() // N and S should be specified explicitly
\ +
\ +

\ +"; + +cookBookMsg[ 21 ] = " \ + #21: Returning this type is not supported
\ +
Rule
\ + \ +ArkTS does not support the returning this type. Use explicit type instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface ListItem {
\ +        getHead(): this
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface ListItem {
\ +        getHead(): ListItem
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 23 ] = " \ + #22: Conditional types are not supported
\ +
Rule
\ + \ +ArkTS does not support conditional type aliases. Introduce a new type with constraints explicitly or rewrite logic with use of Object. \ +infer keyword is not supported. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    type X = T extends number ? T : never
\ +
\ +    type Y = T extends Array ? Item : never
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // Provide explicit contraints within type alias
\ +    type X1 = T
\ +
\ +    // Rewrite with Object. Less type control, need more type checks for safety
\ +    type X2 = Object
\ +
\ +    // Item has to be used as a generic parameter and need to be properly instantiated
\ +    type YI> = Item
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 24 ] = " \ + #24: Optional arguments are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support optional parameters. Specify an \ +optional parameter as a parameter of a nullable type with the \ +default value null. Default parameter values are supported for all types. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // x is an optional parameter:
\ +    function f(x?: number) {
\ +        console.log(x) // log undefined or number
\ +    }
\ +
\ +    // x is a required parameter with the default value:
\ +    function g(x: number = 1) {
\ +        console.log(x)
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // Optional parameters are not supported,
\ +    // but you can assign a default value ``null`` for the parameter:
\ +    function f(x: number | null = null) {
\ +        console.log(x); // log null or number
\ +    }
\ +
\ +    // x is a required argument with the default value:
\ +    function g(x: number = 1) {
\ +        console.log(x);
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 25 ] = " \ + #25: Declaring fields in constructor is not supported
\ +
Rule
\ + \ +ArkTS does not support declaring class fields in the constructor. \ +You must declare them inside the class declaration instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Person {
\ +        constructor(
\ +            protected ssn: string,
\ +            private firstName: string,
\ +            private lastName: string
\ +        ) {
\ +            this.ssn = ssn
\ +            this.firstName = firstName
\ +            this.lastName = lastName
\ +        }
\ +
\ +        getFullName(): string {
\ +            return this.firstName + \" \" + this.lastName
\ +        }
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +   class Person {
\ +        protected ssn: string
\ +        private firstName: string
\ +        private lastName: string
\ +
\ +        constructor(ssn: string, firstName: string, lastName: string) {
\ +            this.ssn = ssn
\ +            this.firstName = firstName
\ +            this.lastName = lastName
\ +        }
\ +
\ +        getFullName(): string {
\ +            return this.firstName + \" \" + this.lastName
\ +        }
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 26 ] = " \ + #26: Specialized signatures are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support specialized signatures as a form of \ +overloading with special type notation (string literal instead of type). \ +Use other patterns (e.g., interfaces) instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    inteface Document {
\ +        createElement(tagname: \"div\"): HTMLDivElement
\ +        createElement(tagname: \"span\"): HTMLDivElement
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class HTMLElement {
\ +        // ...
\ +    }
\ +
\ +    class HTMLDivElement extends HTMLElement {
\ +        // ...
\ +    }
\ +
\ +    class HTMLSpanElement extends HTMLElement {
\ +        // ...
\ +    }
\ +
\ +    interface Document {
\ +        createElement(tagName: string): HTMLElement
\ +    }
\ +
\ +    class D implements Document {
\ +        createElement(tagName: string): HTMLElement {
\ +            switch (tagname) {
\ +                case \"div\": return new HTMLDivElement()
\ +                case \"span\": return new HTMLSpanElement()
\ +                ...
\ +            }
\ +        }
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 27 ] = " \ + #27: Construct signatures not supported in interfaces
\ +
Rule
\ + \ +ArkTS does not support construct signatures. Use methods instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface I {
\ +        new (s: string): I
\ +    }
\ +
\ +    function fn(i: I) {
\ +        return new i(\"hello\");
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface I {
\ +        create(s: string): I
\ +    }
\ +
\ +    function fn(i: I) {
\ +        return i.create(\"hello\")
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 28 ] = " \ + #28: Indexed access types are not supported
\ +
Rule
\ + \ +ArkTS does not support indexed access types. Use the type name instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    type Point = {x: number, y: number}
\ +    type N = Point[\"x\"] // is equal to number
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point {x: number = 0; y: number = 0}
\ +    type N = number
\ +
\ +

\ +"; + +cookBookMsg[ 29 ] = " \ + #29: Indexed access is not supported for fields
\ +
Rule
\ + \ +ArkTS does not support indexed access for class fields. Use dot notation instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Point {x: number = 0; y: number = 0}
\ +    let p: Point = {x: 1, y: 2}
\ +    let x = p[\"x\"]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point {x: number = 0; y: number = 0}
\ +    let p: Point = {x: 1, y: 2}
\ +    let x = p.x
\ +
\ +

\ +"; + +cookBookMsg[ 30 ] = " \ + #30: Structural identity is not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support structural identity, i.e., the compiler \ +cannot compare two types' public APIs and decide whether such types are \ +identical. Use other mechanisms (inheritance, interfaces or type aliases) \ +instead. \ + \ +In TypeScript, types X and Y are equal (interchangeble), while in ArkTS \ +they are not. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface X {
\ +        f(): string
\ +    }
\ +
\ +    interface Y { // Y is equal to X
\ +        f(): string
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ +ArkTS does not support structural identity. In the static environment the \ +compiler checks if two classes or interfaces are equal, but there is no way \ +to compare unrelated (by inheritance or interface) classes that are \ +structurally equivalent. \ + \ + \ +
\ +    interface X {
\ +        f(): string
\ +    }
\ +
\ +    type Y = X // Y is equal to X
\ +
\ +

\ +"; + +cookBookMsg[ 31 ] = " \ + #31: Structural typing is not supported for subtyping / supertyping
\ +
Rule
\ + \ +Currently, ArkTS does not check structural equivalence for type inference, i.e., \ +the compiler cannot compare two types' public APIs and decide whether such types \ +are identical. \ +Use other mechanisms (inheritance or interfaces) instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class X {
\ +        public foo: number
\ +
\ +        constructor() {
\ +            this.foo = 0
\ +        }
\ +    }
\ +
\ +    class Y {
\ +        public foo: number
\ +
\ +        constructor() {
\ +            this.foo = 0
\ +        }
\ +    }
\ +
\ +    let x = new X()
\ +    let y = new Y()
\ +
\ +    console.log(\"Assign X to Y\")
\ +    y = x
\ +
\ +    console.log(\"Assign Y to X\")
\ +    x = y
\ +
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class X {
\ +        public foo: number
\ +
\ +        constructor() {
\ +            this.foo = 0
\ +        }
\ +    }
\ +
\ +    // Y is derived from X, which explicitly set subtype / supertype relations:
\ +    class Y extends X {
\ +        constructor() {
\ +            super()
\ +        }
\ +    }
\ +
\ +    let x = new X()
\ +    let y = new Y()
\ +
\ +    console.log(\"Assign X to Y\")
\ +    y = x // ok, X is the super class of X
\ +
\ +    // Cannot assign Y to X
\ +    //x = y - compile-time error
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 32 ] = " \ + #32: Structural typing is not supported for assignability checks
\ +
Rule
\ + \ +Currently, ArkTS does not check structural equivalence when checking if types \ +are assignable to each other, i.e., the compiler cannot compare two types' \ +public APIs and decide whether such types are identical. Use other mechanisms \ +(inheritance or interfaces) instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class X {
\ +        public foo: number
\ +
\ +        constructor() {
\ +           this.foo = 0
\ +        }
\ +    }
\ +
\ +    class Y {
\ +        public foo: number
\ +        constructor() {
\ +            this.foo = 0
\ +        }
\ +    }
\ +
\ +    let x = new X()
\ +    let y = new Y()
\ +
\ +    console.log(\"Assign X to Y\")
\ +    y = x
\ +
\ +    console.log(\"Assign Y to X\")
\ +    x = y
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface Z {
\ +       foo: number
\ +    }
\ +
\ +    // X implements interface Z, which makes relation between X and Y explicit.
\ +    class X implements Z {
\ +        public foo: number
\ +
\ +        constructor() {
\ +           this.foo = 0
\ +        }
\ +    }
\ +
\ +    // Y implements interface Z, which makes relation between X and Y explicit.
\ +    class Y implements Z {
\ +        public foo: number
\ +
\ +        constructor() {
\ +           this.foo = 0
\ +        }
\ +    }
\ +
\ +    let x: Z = new X()
\ +    let y: Z = new Y()
\ +
\ +    console.log(\"Assign X to Y\")
\ +    y = x // ok, both are of the same type
\ +
\ +    console.log(\"Assign Y to X\")
\ +    x = y // ok, both are of the same type
\ +
\ +

\ +"; + +cookBookMsg[ 33 ] = " \ + #33: Optional properties are not supported
\ +
Rule
\ + \ +ArkTS does not support optional properties. Use properties with default values. \ +Use properties of nullable types and the default null value to distinguish \ +whether a value is set or not. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface CompilerOptions {
\ +        strict?: boolean
\ +        sourcePath?: string
\ +        targetPath?: string
\ +    }
\ +
\ +    var options: CompilerOptions = {
\ +        strict: true,
\ +        sourcepath: \"./src\",
\ +    }
\ +    if option.targetPath == undefined {
\ +        // set default
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface CompilerOptions {
\ +        strict: boolean = false
\ +        sourcePath: string = \"\"
\ +        targetPath: string | null = null
\ +    }
\ +
\ +    let options: CompilerOptions = {
\ +        strict: true,
\ +        sourcepath: \"./src\",
\ +    }
\ +    if option.targetPath == null {
\ +        // set default
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 34 ] = " \ + #34: Generic functions must be called with explicit type specialization
\ +
Rule
\ + \ +Currently, ArkTS does not support inference of type parameters in case of calls \ +to generic functions. If a function is declared generic, all calls must specify \ +type parameters explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function choose(x: T, y: T): T {
\ +        return Math.random() < 0.5 ? x : y
\ +    }
\ +
\ +    let x = choose(10, 20) // Ok
\ +    let y = choose(\"10\", 20) // Compile-time error
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function choose(x: T, y: T): T {
\ +        return Math.random() < 0.5 ? x : y
\ +    }
\ +
\ +    let x = choose(10, 20) // Ok
\ +    let y = choose(\"10\", 20) // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 35 ] = " \ + #35: Structural typing is not supported for type inference
\ +
Rule
\ + \ +Currently, ArkTS does not support structural typing, i.e., the compiler cannot \ +compare two types' public APIs and decide whether such types are identical. \ +Use inheritance and interfaces to specify the relation between the types \ +explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class X {
\ +        public foo: number
\ +        private s: string
\ +
\ +        constructor (f: number) {
\ +            this.foo = f
\ +            this.s = \"\"
\ +        }
\ +
\ +        public say(): void {
\ +           console.log(\"X = \", this.foo)
\ +        }
\ +    }
\ +
\ +    class Y {
\ +        public foo: number
\ +
\ +        constructor (f: number) {
\ +            this.foo = f
\ +        }
\ +        public say(): void {
\ +            console.log(\"Y = \", this.foo)
\ +        }
\ +    }
\ +
\ +    function bar(z: X): void {
\ +        z.say()
\ +    }
\ +
\ +    // X and Y are equivalent because their public API is equivalent.
\ +    // Thus the second call is allowed:
\ +    bar(new X(1));
\ +    bar(new Y(2));
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface Z {
\ +       say(): void
\ +    }
\ +
\ +    class X implements Z {
\ +        public foo: number
\ +        private s: string
\ +
\ +        constructor (f: number) {
\ +            this.foo = f
\ +            this.s = \"\"
\ +        }
\ +        public say(): void {
\ +            console.log(\"X = \", this.foo)
\ +        }
\ +    }
\ +
\ +    class Y implements Z {
\ +        public foo: number
\ +
\ +        constructor (f: number) {
\ +            this.foo = f
\ +        }
\ +        public say(): void {
\ +            console.log(\"Y = \", this.foo)
\ +        }
\ +    }
\ +
\ +    function bar(z: Z): void {
\ +        z.say()
\ +    }
\ +
\ +    // X and Y implement the same interface Z, thus both calls are allowed:
\ +    bar(new X(1))
\ +    bar(new Y(2))
\ +
\ +

\ +"; + +cookBookMsg[ 36 ] = " \ + #36: Type widening is not supported
\ +
Rule
\ + \ +ArkTS does not support widened types because in most cases type widening \ +is applied to the currently unsupported types any, unknown \ +and undefined. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    var a = null
\ +    var b = undefined
\ +    var c = {c: 0, y: null}
\ +    var d = [null, undefined]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class C {
\ +        public c: number = 0
\ +        public y: Object | null
\ +    }
\ +
\ +    let a: Object | null = null
\ +    let b: Object
\ +    let c: C = {c: 0, y: null}
\ +    let d: Object[] = [null, null]
\ +
\ +

\ +"; + +cookBookMsg[ 37 ] = " \ + #37: RegExp literals are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support RegExp literals. Use library call with string \ +literals instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +   let regex: RegExp = /bc*d/
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +   let regex: RegExp = new RegExp(\"/bc*d/\")
\ +
\ +

\ +"; + +cookBookMsg[ 38 ] = " \ + #38: Object literal must correspond to explicitly declared class or interface
\ +
Rule
\ + \ +ArkTS supports the usage of object literals if the compiler can infer \ +to what classes or interfaces such literals correspond to. \ +Otherwise, a compile-time error occurs. \ + \ +The class or interface can be specified as a type annotation for a variable. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +   let x = {f: 1}
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class O {
\ +       f: number
\ +    }
\ +
\ +    let x: O = {f: 1} // OK
\ +    let y = {f: 1} // Compile-time error, cannot infer object literal type
\ +    let z: Object = {f: 2} // Compile-time error, class 'Object' does not have field 'f'
\ +
\ +

\ +"; + +cookBookMsg[ 39 ] = " \ + #39: Object literals must correspond to explicitly declared class or interface
\ +
Rule
\ + \ +ArkTS supports the usage of object literals if the compiler can infer to what \ +classes or interfaces such literals correspond to. Otherwise, a compile-time \ +error occurs. \ + \ +The class or interface can be inferred from a type of the corresponding function parameter. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function foo(x: any) {}
\ +    foo({f: 1})
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class S {
\ +        f: number
\ +    }
\ +
\ +    function foo(s: S) {}
\ +
\ +    foo({f: 2}) // ok
\ +    foo({ff: 2}) // Compile-time error, class 'S' does not have field 'ff'
\ +
\ +

\ +"; + +cookBookMsg[ 40 ] = " \ + #40: Object literals cannot be used as type declarations
\ +
Rule
\ + \ +ArkTS does not support the usage of object literals to declare \ +types in place. Declare classes and interfaces explicitly instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let o: {x: number, y: number} = {
\ +        x: 2,
\ +        y: 3
\ +    }
\ +
\ +    type T = G<{x: number, y: number}>
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class O {
\ +        x: number
\ +        y: number
\ +    }
\ +
\ +    let o: O = {x: 2, y: 3}
\ +
\ +    type T = G
\ +
\ +

\ +"; + +cookBookMsg[ 42 ] = " \ + #42: Array literals must correspond to known array types
\ +
Rule
\ + \ +ArkTS supports the usage of array literals if the compiler can infer \ +to what array types such literals correspond to. Otherwise, a compile-time \ +error occurs. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +   let x = [\"aa\", \"bb\"]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +   let x: string[] = [\"aa\", \"bb\"]
\ +
\ +

\ +"; + +cookBookMsg[ 43 ] = " \ + #43: Untyped array literals are not supported
\ +
Rule
\ + \ +ArkTS does not support the usage of untyped array literals. The type of an \ +array element must be inferred from the context. Use the type Object to \ +define mixed types array. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let x = [1, 2]
\ +    let y = [1, \"aa\"]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let x: Object[] = [new Int(1), new Int(2)]
\ +
\ +    // Implicit boxing of primitive int to object Int
\ +    let x1: Object[] = [1, 2]
\ +
\ +    let y: Object[] = [1, \"aa\"]
\ +
\ +

\ +"; + +cookBookMsg[ 44 ] = " \ + #44: Template literals are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support template literals. You may use a + \ +concatenation as a work-around. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    const a = 5
\ +    const b = 10
\ +    console.log(`Fifteen is ${a + b}`)
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    const a = 5
\ +    const b = 10
\ +
\ +    // (a + b) is converted to Int and then toString() method is called:
\ +    console.log(\"Fifteen is \" + (a + b))
\ +
\ +

\ +"; + +cookBookMsg[ 45 ] = " \ + #45: Lambdas require explicit type annotation for parameters
\ +
Rule
\ + \ +Currently, ArkTS requires the types of lambda parameters \ +to be explicitly specified. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let f = (s) => { // type any is assumed
\ +            console.log(s)
\ +        }
\ +
\ +

\ +
ArkTS
\ + \ +Explicit types for lambda parameters are mandatory. \ + \ + \ +
\ +    let f =
\ +        (s: string) => {
\ +            console.log(s)
\ +        }
\ +
\ +

\ +"; + +cookBookMsg[ 46 ] = " \ + #46: Use arrow functions instead of function expressions
\ +
Rule
\ + \ +ArkTS does not support function expressions, use arrow functions instead \ +to be explicitly specified. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let f = function (s: string) {
\ +            console.log(s)
\ +        }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let f = (s: string) => {
\ +            console.log(s)
\ +        }
\ +
\ +

\ +"; + +cookBookMsg[ 47 ] = " \ + #47: Return type must be specified for lambdas explicitly
\ +
Rule
\ + \ +An explicit return type is mandatory for a lambda expression. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let f = (s: string) => { // return type is implicit
\ +            return s.toLowerCase()
\ +        }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let f = (s: string): string => { // return type is explicit
\ +            return s.toLowerCase()
\ +        }
\ +
\ +

\ +"; + +cookBookMsg[ 48 ] = " \ + #48: Shortcut syntax for lambdas is not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support shortcut syntax for lambdas. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = (x: number) => { return x }
\ +    let b = (x: number) => x
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a: (x: number) => number =
\ +        (x: number): number => { return x }
\ +
\ +    let b: (x: number) => number =
\ +        (x: number): number => { return x }
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 50 ] = " \ + #50: Class literals are not supported
\ +
Rule
\ + \ +ArkTS does not support class literals. A new named class type must be \ +introduced explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    const Rectangle = class {
\ +        constructor(height: number, width: number) {
\ +            this.heigth = height
\ +            this.width = width
\ +        }
\ +
\ +        heigth
\ +        width
\ +    }
\ +
\ +    const rectangle = new Rectangle(0.0, 0.0)
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Rectangle {
\ +        constructor(height: number, width: number) {
\ +            this.heigth = height
\ +            this.width = width
\ +        }
\ +
\ +        heigth: number
\ +        width: number
\ +    }
\ +
\ +    const rectangle = new Rectangle(0.0, 0.0)
\ +
\ +

\ +"; + +cookBookMsg[ 51 ] = " \ + #51: Classes cannot be specified in implements clause
\ +
Rule
\ + \ +ArkTS does not allow to specify a class in implements clause. Only interfaces may be specified. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class C {
\ +      foo() {}
\ +    }
\ +    
\ +    class C1 implements C {
\ +      foo() {}
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface C {
\ +      foo()
\ +    }
\ +    
\ +    class C1 implements C {
\ +      foo() {}
\ +    }
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 52 ] = " \ + #52: Attempt to access an undefined property is a compile-time error
\ +
Rule
\ + \ +ArkTS supports accessing only those class properties that are either declared \ +in the class, or accessible via inheritance. Accessing any other properties is \ +prohibited and causes compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let person = {name: \"Bob\", isEmployee: true}
\ +
\ +    let n = typ[\"name\"]
\ +    let e = typ[\"isEmployee\"]
\ +    let s = typ[\"office\"] // undefined
\ +
\ +

\ +
ArkTS
\ + \ +Use proper types to check property existence during compilation. \ + \ + \ +
\ +    class Person {
\ +        constructor(name: string, isEmployee: boolean) {
\ +            this.name = name
\ +            this.isEmployee = isEmployee
\ +        }
\ +
\ +        name: string
\ +        isEmployee: boolean
\ +    }
\ +
\ +    let person = new Person(\"Bob\", true)
\ +    let n = typ.name
\ +    let e = typ.isEmployee
\ +    let s = typ.office // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 53 ] = " \ + #53: Only as T syntax is supported for type casts
\ +
Rule
\ + \ +ArkTS supports as keyword as the only syntax for type casts. \ +Incorrect cast causes a compile-time error or runtime ClassCastException. \ + syntax for type casts is not supported. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Shape {}
\ +    class Circle extends Shape {x: number = 5}
\ +    class Square extends Shape {y: string = \"a\"}
\ +
\ +    function createShape(): Shape {
\ +        return new Circle()
\ +    }
\ +
\ +    let c1 = createShape()
\ +
\ +    let c2 = createShape() as Circle
\ +
\ +    // No report is provided during compilation
\ +    // nor during runtime if cast is wrong:
\ +    let c3 = createShape() as Square
\ +    console.log(c3.y) // undefined
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Shape {}
\ +    class Circle extends Shape {x: number = 5}
\ +    class Square extends Shape {y: string = \"a\"}
\ +
\ +    function createShape(): Shape {
\ +        return new Circle()
\ +    }
\ +
\ +    let c2 = createShape() as Circle
\ +
\ +    // ClassCastException during runtime is thrown:
\ +    let c3 = createShape() as Square
\ +
\ +

\ +"; + +cookBookMsg[ 54 ] = " \ + #54: JSX expressions are not supported
\ +
Rule
\ + \ +Do not use JSX since no alternative is provided to rewrite it. \ + \ +
\ +"; + +cookBookMsg[ 55 ] = " \ + #55: Unary operators +, - and ~ work only on numbers
\ +
Rule
\ + \ +ArkTS allows unary operators to work on numeric types only. A compile-time \ +error occurs if these operators are applied to a non-numeric type. Unlike in \ +TypeScript, implicit casting of strings in this context is not supported and must \ +be done explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = +5 // 5 as number
\ +    let b = +\"5\" // 5 as number
\ +    let c = -5 // -5 as number
\ +    let d = -\"5\" // -5 as number
\ +    let e = ~5 // -6 as number
\ +    let f = ~\"5\" // -6 as number
\ +    let g = +\"string\" // NaN as number
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = +5 // 5 as int
\ +    let b = +\"5\" // Compile-time error
\ +    let c = -5 // -5 as int
\ +    let d = -\"5\" // Compile-time error
\ +    let e = ~5 // -6 as int
\ +    let f = ~\"5\" // Compile-time error
\ +    let g = +\"string\" // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 56 ] = " \ + #56: Unary + cannot be used for casting to number
\ +
Rule
\ + \ +ArkTS does not support casting from any type to a numeric type \ +by using the unary + operator, which can be applied only to \ +numeric types. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function returnTen(): string {
\ +        return \"-10\"
\ +    }
\ +
\ +    function returnString(): string {
\ +        return \"string\"
\ +    }
\ +
\ +    let a = +returnTen() // -10 as number
\ +    let b = +returnString() // NaN
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function returnTen(): string {
\ +        return \"-10\"
\ +    }
\ +
\ +    function returnString(): string {
\ +        return \"string\"
\ +    }
\ +
\ +    let a = +returnTen() // Compile-time error
\ +    let b = +returnString() // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 57 ] = " \ + #57: ! operator works only on values of the boolean type
\ +
Rule
\ + \ +ArkTS supports using ! operator only for values of the boolean type. \ +Explicit cast from some type to the boolean (or Boolean) is mandatory. \ +Implicit casts are prohibited and cause compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = !true // false
\ +    let b = !\"true\" // false
\ +    let c = !\"rnd_str\" // false
\ +    let d = !\"false\" // false
\ +    let e = !5 // false
\ +    let f = !0 // true
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = !true // false
\ +    let b = !\"true\" // Compile-time error
\ +    let c = !\"false\" // Compile-time error
\ +    let d = !\"rnd_str\" // Compile-time error
\ +    let e = !5 // Compile-time error
\ +    let f = !0 // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 59 ] = " \ + #59: delete operator is not supported
\ +
Rule
\ + \ +ArkTS assumes that object layout is known at compile time and cannot be \ +changed at runtime. Thus the operation of deleting a property makes no sense. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Point {
\ +        x?: number = 0.0
\ +        y?: number = 0.0
\ +    }
\ +
\ +    let p = new Point()
\ +    delete p.y
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // To mimic the original semantics, you may declare a nullable type
\ +    // and assign null to mark value absence:
\ +
\ +    class Point {
\ +        x: number | null
\ +        y: number | null
\ +    }
\ +
\ +    let p = new Point()
\ +    p.y = null
\ +
\ +

\ +"; + +cookBookMsg[ 60 ] = " \ + #60: typeof operator is not supported
\ +
Rule
\ + \ +ArkTS does not support typeof operator and requires explicit typing. \ +Use instanceof as a work-around where applicable. Type can be inferred \ +from the initalizer, but the initial value can be not a default one. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    console.log(typeof 5) // \"number\"
\ +    console.log(typeof \"string\") // \"string\"
\ +    let s = \"hello\"
\ +    let n: typeof s // n type is string, n == \"\"
\ +    let b = typeof s == \"string\" // true
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let s = \"hello\"
\ +    let n = s
\ +    let b = s instanceof string // true
\ +
\ +

\ +"; + +cookBookMsg[ 61 ] = " \ + #61: Binary operators *, /, %, -, <<, >>, >>>, &, ^ and | work only on numeric types
\ +
Rule
\ + \ +ArkTS allows applying binary operators *, /, %, -, <<, \ +>>, >>>, &, ^ and | only to values of numeric types. \ +Implicit casts from other types to numeric types are prohibited and cause \ +compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = (5 & 5) // 5
\ +    let b = (5.5 & 5.5) // 5, not 5.5
\ +    let c = (5 | 5) // 5
\ +    let d = (5.5 | 5.5) // 5, not 5.5
\ +
\ +    enum Direction {
\ +        Up = -1,
\ +        Down
\ +    }
\ +    let e = Direction.Up >> 1 // -1
\ +    let f = Direction.Up >>> 1 // 2147483647
\ +
\ +    let g = (\"10\" as any) << 1 // 20
\ +    let h = (\"str\" as any) << 1 // 0
\ +
\ +    let i = 10 * 5
\ +    let j = 10 / 5
\ +    let k = 10 % 5
\ +    let l = 10 - 5
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = (5 & 5) // 5
\ +    let b = (5.5 & 5.5) // Compile-time error
\ +    let c = (5 | 5) // 5
\ +    let d = (5.5 | 5.5) // Compile-time error
\ +
\ +    enum Direction {
\ +        Up, // TBD: explicit start value
\ +        Down
\ +    }
\ +
\ +    let e = Direction.Up >> 1 // 0
\ +    let f = Direction.Up >>> 1 // 0
\ +
\ +    let i = 10 * 5
\ +    let j = 10 / 5
\ +    let k = 10 % 5
\ +    let l = 10 - 5
\ +
\ +

\ +"; + +cookBookMsg[ 62 ] = " \ + #62: Binary operators <<, >>, >>>, &, ^ and | work only on integral numeric types
\ +
Rule
\ + \ +ArkTS expects an explicit cast to an integral type for logical binary \ +operations. Implicit casts are prohibited and cause compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let b = (5.5 & 5.5) // 5, not 5.5
\ +    let d = (5.5 | 5.5) // 5, not 5.5
\ +
\ +    let g = (\"10\" as any) << 1 // 20
\ +    let h = (\"str\" as any) << 1 // 0
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let b = (5.5 & 5.5) // Compile-time error
\ +    let d = (5.5 | 5.5) // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 63 ] = " \ + #63: Binary + operator supports implicit casts only for numbers and strings
\ +
Rule
\ + \ +ArkTS supports implicit casts for + only for strings and numbers. \ +Elsewhere, any form of an explicit cast to string is required. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    enum E { E1, E2 }
\ +
\ +    let a = 10 + 32 // 42
\ +    let b = E.E1 + 10 // 10
\ +    let c = 10 + \"5\" // \"105\"
\ +
\ +    let d = \"5\" + E.E2 // \"51\"
\ +    let e = \"Hello, \" + \"world!\" // \"Hello, world!\"
\ +    let f = \"string\" + true // \"stringtrue\"
\ +
\ +    let g = (new Object()) + \"string\" // \"[object Object]string\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    enum E { E1, E2 }
\ +
\ +    let a = 10 + 32 // 42
\ +    let b = E.E1 + 10 // 10
\ +    let c = 10 + \"5\" // \"105\"
\ +
\ +    let d = \"5\" + E.E2 // \"51\"
\ +    let e = \"Hello, \" + \"world!\" // \"Hello, world!\"
\ +    let f = \"string\" + true // \"stringtrue\"
\ +
\ +    let g = (new Object()).toString() + \"string\"
\ +
\ +

\ +"; + +cookBookMsg[ 64 ] = " \ + #64: Binary + operator requires explicit casts for non-numbers and non-strings
\ +
Rule
\ + \ +ArkTS supports implicit casts for + only for strings and numbers. \ +Elsewhere, any form of an explicit cast to string is required. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // \"[object Object][object Object]\"
\ +    let o = ({x: 5} as any) + {y: 6}
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let o = (new Object()).toString() + new Int(5) // \"5\"
\ +
\ +

\ +"; + +cookBookMsg[ 66 ] = " \ + #66: in operator is not supported
\ +
Rule
\ + \ +ArkTS does not support the in operator. However, this operator makes \ +little sense since the object layout is known at compile time and cannot \ +be modified at runtime. Use instanceof as a work-around if you still need \ +to check whether certain class members exist. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Person {
\ +        name: string = \"\"
\ +    }
\ +    let p = new Person()
\ +
\ +    let b = \"name\" in p // true
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Person {
\ +        name: string = \"\"
\ +    }
\ +    let p = new Person()
\ +
\ +    let b = p instanceof Person // true, and \"name\" is guaranteed to be present
\ +
\ +

\ +"; + +cookBookMsg[ 67 ] = " \ + #67: Operators && and || work on values of the boolean type only
\ +
Rule
\ + \ +ArkTS supports using && and || operators only for the values of the \ +boolean type. Explicit cast from some type to the boolean (or Boolean) is \ +mandatory. Implicit casts are prohibited and cause compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = true && false // false
\ +    let b = 5 || 0 // 5
\ +    let c = 5 && 0 // 0
\ +    let d = \"\" && 5 // \"\"
\ +    let e = \"\" || \"abcd\" // \"abcd\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = true && false // false
\ +    let b = 5 || 0 // Compile-time error
\ +    let c = 5 && 0 // Compile-time error
\ +    let d = \"\" && 5 // Compile-time error
\ +    let e = \"\" || \"abcd\" // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 68 ] = " \ + #68: Using of && and || on non-boolean types is not supported
\ +
Rule
\ + \ +ArkTS supports the usage of && and || operators only for the values \ +of the boolean type. Explicit cast from some type to the boolean (or Boolean) \ +is mandatory. Implicit casts are prohibited and cause compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = true && false // false
\ +    let b = 5 || 0 // 5
\ +    let c = 5 && 0 // 0
\ +    let d = \"\" && 5 // \"\"
\ +    let e = \"\" || \"abcd\" // \"abcd\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = true && false // false
\ +    let b = 5 || 0 // Compile-time error
\ +    let c = 5 && 0 // Compile-time error
\ +    let d = \"\" && 5 // Compile-time error
\ +    let e = \"\" || \"abcd\" // Compile-time error
\ +
\ +

\ +"; + +cookBookMsg[ 69 ] = " \ + #69: Destructuring assignment is not supported
\ +
Rule
\ + \ +ArkTS does not support destructuring assignment. Other idioms (e.g., \ +using a temporary variable, where applicable) can be used for replacement. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let [one, two] = [1, 2]
\ +    [one, two] = [two, one]
\ +
\ +    let head, tail
\ +    [head, ...tail] = [1, 2, 3, 4]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let arr: number[] = [1, 2]
\ +    let one = arr[0]
\ +    let two = arr[1]
\ +
\ +    let tmp = one
\ +    one = two
\ +    two = tmp
\ +
\ +    let data: Number[] = [1,2,3,4]
\ +    let head = data[0]
\ +    let tail = new Number[data.length - 1]
\ +    for (let i = 1; i < data.length; ++i) {
\ +        tail[i-1] = data[i]
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 71 ] = " \ + #71: The comma operator , is supported only in for loops
\ +
Rule
\ + \ +ArkTS supports the comma operator , only in for loops. Otherwise, \ +it is useless as it makes the execution order harder to understand. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    for (let i = 0, j = 0; i < 10; ++i, j += 2) {
\ +        console.log(i, j)
\ +    }
\ +
\ +    let x = 0
\ +    x = (++x, x++) // 1
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    for (let i = 0, j = 0; i < 10; ++i, j += 2) {
\ +        console.log(i, j)
\ +    }
\ +
\ +    // Use explicit execution order instead of the comma operator:
\ +    let x = 0
\ +    ++x
\ +    x = x++
\ +
\ +

\ +"; + +cookBookMsg[ 73 ] = " \ + #74: Destructuring variable declarations are not supported
\ +
Rule
\ + \ +ArkTS does not support destructuring variable declarations. This is a dynamic \ +feature relying on structural compatibility. In addition, names in destructuring \ +declarations must be equal to properties within destructured classes. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Point {
\ +        x: number = 0.0
\ +        y: number = 0.0
\ +    }
\ +
\ +    function returnZeroPoint(): Point {
\ +        return new Point()
\ +    }
\ +
\ +    let {x, y} = returnZeroPoint()
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point {
\ +        x: number = 0.0
\ +        y: number = 0.0
\ +    }
\ +
\ +    function returnZeroPoint(): Point {
\ +        return new Point()
\ +    }
\ +
\ +    // Create an intermediate object and work with it field by field
\ +    // without name restrictions:
\ +    let zp = returnZeroPoint()
\ +    let x = zp.x
\ +    let y = zp.y
\ +
\ +

\ +"; + +cookBookMsg[ 76 ] = " \ + #76: Inference of implied types is not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support inference of implied types. Use explicit \ +type notation instead. Use Object[] if you need containers that hold \ +data of mixed types. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let [a, b, c] = [1, \"hello\", true]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a = 1
\ +    let b = \"hello\"
\ +    let c = true
\ +
\ +    let arr: Object[] = [1, \"hello\", true]
\ +    let a1 = arr[0]
\ +    let b1 = arr[1]
\ +    let c1 = arr[2]
\ +
\ +

\ +"; + +cookBookMsg[ 78 ] = " \ + #78: Implicit casts to the boolean are not supported in if, do and while
\ +
Rule
\ + \ +ArkTS supports only values of the boolean type in if, do and while \ +statements. Implicit casts from other types to the boolean are prohibited and \ +cause compile-time errors. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    if (true) {}
\ +    do {} while (false)
\ +
\ +    let a = new Boolean(true)
\ +    if (a) {}
\ +    do {break} while (a)
\ +    while (a) {break}
\ +
\ +    let b = 42
\ +    if (b) {}
\ +    do {break} while (b)
\ +    while (b) {break}
\ +
\ +    let c = \"str\"
\ +    if (c) {}
\ +    do {break} while (c)
\ +    while (c) {break}
\ +
\ +    let d = new Object()
\ +    if (d) {}
\ +    do {break} while (d)
\ +    while (d) {break}
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    if (true) {}
\ +    do {} while (false)
\ +
\ +    let a = new Boolean(true)
\ +    if (a) {}
\ +    do {break} while (a)
\ +    while (a) {break}
\ +
\ +    let b = 42
\ +    if (b != 0) {}
\ +    do {break} while (b != 0)
\ +    while (b != 0) {break}
\ +
\ +    let c = \"str\"
\ +    if (c.length != 0) {}
\ +    do {break} while (c.length != 0)
\ +    while (c.length != 0) {break}
\ +
\ +    let d = new Object()
\ +    if (d != null) {}
\ +    do {break} while (d != null)
\ +    while (d != null) {break}
\ +
\ +

\ +"; + +cookBookMsg[ 79 ] = " \ + #79: Type annotation in catch clause is not supported
\ +
Rule
\ + \ +In TypeScript catch clause variable type annotation must be any or unknown if specified. \ +As ArkTS does not support these types, a type annotation should be omitted. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    try {
\ +        // some code
\ +    }
\ +    catch (a: unknown) {}
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    try {
\ +        // some code
\ +    }
\ +    catch (a) {}
\ +
\ +

\ +"; + +cookBookMsg[ 80 ] = " \ + #80: for .. in is not supported
\ +
Rule
\ + \ +ArkTS does not support the iteration over object contents by the \ +for .. in loop. For objects, iteration over properties at runtime is \ +considered redundant because object layout is known at compile time and cannot \ +change at runtime. For arrays, you can iterate with the regular for loop. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a: number[] = [1.0, 2.0, 3.0]
\ +    for (let i in a) {
\ +        console.log(a[i])
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a: number[] = [1.0, 2.0, 3.0]
\ +    for (let i = 0; i < a.length; ++i) {
\ +        console.log(a[i])
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 81 ] = " \ + #81: Iterable interfaces are not supported
\ +
Rule
\ + \ +ArkTS does not support the Symbol API, Symbol.iterator and \ +eventually iterable interfaces. Use arrays and library-level containers to \ +iterate over data. \ + \ +
\ +"; + +cookBookMsg[ 82 ] = " \ + #82: for-of is supported only for arrays
\ +
Rule
\ + \ +ArkTS supports the iteration over arrays by the for .. of loop, \ +but does not support the iteration of objects content. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a: string[] = [\"a\", \"b\", \"c\"]
\ +    for (let s of a) {
\ +        console.log(s)
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let a: string[] = [\"a\", \"b\", \"c\"]
\ +    for (let s of a) {
\ +        console.log(s)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 83 ] = " \ + #83: Mapped type expression is not supported
\ +
Rule
\ + \ +ArkTS does not support mapped types. Use other language idioms and regular classes \ +to achieve the same behaviour. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +   type OptionsFlags = {
\ +       [Property in keyof Type]: boolean;
\ +   }
\ +
\ +

\ +"; + +cookBookMsg[ 84 ] = " \ + #84: with statement is not supported
\ +
Rule
\ + \ +ArkTS does not support the with statement. Use other language idioms \ +(including fully qualified names of functions) to achieve the same behaviour. \ + \ +
\ +"; + +cookBookMsg[ 85 ] = " \ + #85: Values computed at runtime are not supported in case statements
\ +
Rule
\ + \ +ArkTS supports case statements that contain only compile-time values. \ +Use if statements as an alternative. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let x = 2
\ +    let y = 3
\ +    switch (x) {
\ +        case 1:
\ +            console.log(1)
\ +            break
\ +        case 2:
\ +            console.log(2)
\ +            break
\ +        case y:
\ +            console.log(y)
\ +            break
\ +        default:
\ +            console.log(\"other\")
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let x = 2
\ +    switch (x) {
\ +        case 1:
\ +            console.log(1)
\ +            break
\ +        case 2:
\ +            console.log(2)
\ +            break
\ +        case 3:
\ +            console.log(3)
\ +            break
\ +        default:
\ +            console.log(\"other\")
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 86 ] = " \ + #86: switch statements cannot accept values of arbitrary types
\ +
Rule
\ + \ +ArkTS supports the values of the types char, byte, short, int, \ +long, Char, Byte, Short, Int, Long, String or \ +enum in switch statements. Use if statements in other cases. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Point {
\ +        x: number = 0
\ +        y: number = 0
\ +    }
\ +
\ +    let a = new Point()
\ +
\ +    switch (a) {
\ +        case null: break;
\ +        default: console.log(\"not null\")
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point {
\ +        x: number = 0
\ +        y: number = 0
\ +    }
\ +
\ +    let a = new Point()
\ +
\ +    if (a != null) {
\ +        console.log(\"not null\")
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 87 ] = " \ + #87: throw statements cannot accept values of arbitrary types
\ +
Rule
\ + \ +ArkTS supports throwing only objects of the class Error or any \ +derived class. Throwing an arbitrary type (i.e., a number or string) \ +is prohibited. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    throw 4
\ +    throw \"\"
\ +    throw new Error()
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    throw new Error()
\ +
\ +

\ +"; + +cookBookMsg[ 88 ] = " \ + #88: Each overloaded function should have its body
\ +
Rule
\ + \ +ArkTS does not support the TypeScript style of overloading signatures with one \ +function body. Define each overloading function with its own body instead of \ +one body for a list of signatures. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function add(x: number, y: number): number
\ +    function add(x: string, y: string): string
\ +    function add(x: any, y: any): any {
\ +        return x + y
\ +    }
\ +
\ +    console.log(add(2, 3)) // returns 5
\ +    console.log(add(\"hello\", \"world\")) // returns \"helloworld\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function add(x: number, y: number): number {
\ +        return x + y
\ +    }
\ +
\ +    function add(x: string, y: string): string {
\ +        return x + y
\ +    }
\ +
\ +    function main() {
\ +        console.log(add(2, 3)) // returns 5
\ +        console.log(add(\"hello\", \"world\")) // returns \"helloworld\"
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 89 ] = " \ + #89: Each overloaded function with optional parameters should have its body
\ +
Rule
\ + \ +ArkTS does not support the TypeScript style of overloading signatures with one \ +function body. Write a separate body for each overloaded signature instead of \ +an optional parameter like `value?` for a single body in TypeScript. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function foo(name: string): number
\ +    function foo(name: string, value: string): Accessor
\ +    function foo(name: any, value?: string): any {
\ +        // one body here
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function foo(name: string): string {
\ +        return name
\ +    }
\ +
\ +    function foo(name: string, value: string): Accessor {
\ +        return new Accessor()
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 90 ] = " \ + #90: Function must have explicit return type
\ +
Rule
\ + \ +ArkTS requires all functions to have explicit return types. For corner cases, \ +use `Object` when it is difficult to determine the return type. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function f(x: number) {
\ +        if (x <= 0) {
\ +            return x
\ +        }
\ +        return g(x)
\ +    }
\ +
\ +    function g(x: number) {
\ +        return f(x - 1)
\ +    }
\ +
\ +    function doOperation(x: number, y: number) {
\ +        return x + y
\ +    }
\ +
\ +    console.log(f(10))
\ +    console.log(doOperation(2, 3))
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function f(x: number): Object {
\ +        if (x <= 0) {
\ +            return x
\ +        }
\ +        return g(x)
\ +    }
\ +
\ +    function g(x: number): Object {
\ +        return f(x - 1)
\ +    }
\ +
\ +    function doOperation(x: number, y: number): Object {
\ +        let z = x + y
\ +        return z
\ +    }
\ +
\ +    function main(): void {
\ +        console.log(f(-10) as number) // returns -10
\ +        console.log(doOperation(2, 3)) // returns 5
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 92 ] = " \ + #92: Nested functions are not supported
\ +
Rule
\ + \ +ArkTS does not support nested functions. Use lambdas instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function addNum(a: number, b: number): void {
\ +
\ +        // nested function:
\ +        function logToConsole(message: String): void {
\ +            console.log(message)
\ +        }
\ +
\ +        let result = a + b
\ +
\ +        // Invoking the nested function:
\ +        logToConsole(\"result is \" + result)
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function addNum(a: number, b: number): void {
\ +
\ +        // Use lambda instead of a nested function:
\ +        let logToConsole: (message: String): void = (message: String): void => {
\ +            console.println(message)
\ +        }
\ +
\ +        let result = a + b
\ +
\ +        logToConsole(\"result is \" + result)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 93 ] = " \ + #93: Using this inside stand-alone functions is not supported
\ +
Rule
\ + \ +ArkTS does not support the usage of this inside stand-alone functions. \ +this can be used in methods only. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function foo(i: number) {
\ +        this.count = i
\ +    }
\ +
\ +    class A {
\ +        count: number = 1
\ +        m = foo
\ +    }
\ +
\ +    let a = new A()
\ +    console.log(a.count) // prints \"1\"
\ +    a.m(2)
\ +    console.log(a.count) // prints \"2\"
\ +
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class A {
\ +        count: number = 1
\ +        m(i: number): void {
\ +            this.count = i
\ +        }
\ +    }
\ +
\ +    function main(): void {
\ +        let a = new A()
\ +        console.log(a.count) // prints \"1\"
\ +        a.m(2)
\ +        console.log(a.count) // prints \"2\"
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 94 ] = " \ + #94: Generator functions are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support generator functions. \ +Use the async / await mechanism for multitasking. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function* counter(start: number, end: number) {
\ +        for (let i = start; i <= end; i++) {
\ +            yield i
\ +        }
\ +    }
\ +
\ +    for (let num of counter(1, 5)) {
\ +        console.log(num)
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    for (let i = 1; i <= 5; ++i) {
\ +        console.log(i)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 95 ] = " \ + #95: Asynchronous functions are partially supported
\ +
Rule
\ + \ +ArkTS partially supports asynchronous functions. \ +Using the launch mechanism (ArkTS extension to TypeScript) \ +is recommended for multitasking. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    async function sum(numbers: number[]): Promise {
\ +        let sum = 0
\ +        for (let num of numbers) {
\ +            sum += await num
\ +        }
\ +        return sum
\ +    }
\ +
\ +    ...
\ +    const result = await sum(5, 10)
\ +    ...
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function sum(numbers: number[]): number {
\ +        let sum = 0
\ +        for (let i = 0; i < numbers.length; ++i) {
\ +            sum += numbers[i]
\ +        }
\ +        return sum
\ +    }
\ +
\ +    ...
\ +    const result = launch sum(5, 10) // `result` will be of type `Promise`
\ +    ...
\ +
\ +NOT recommended:
\ +
\ +

\ +"; + +cookBookMsg[ 96 ] = " \ + #96: Type guarding is supported with instanceof and as
\ +
Rule
\ + \ +ArkTS does not support the is operator, which must be replaced by the \ +instanceof operator. Note that the fields of an object must be cast to the \ +appropriate type with the as operator before use. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Foo {
\ +        foo: number = 0
\ +        common: string = \"\"
\ +    }
\ +
\ +    class Bar {
\ +        bar: number = 0
\ +        common: string = \"\"
\ +    }
\ +
\ +    function isFoo(arg: any): arg is Foo {
\ +        return arg.foo !== undefined
\ +    }
\ +
\ +    function doStuff(arg: Foo | Bar) {
\ +        if (isFoo(arg)) {
\ +            console.log(arg.foo) // OK
\ +            console.log(arg.bar) // Error!
\ +        }
\ +        else {
\ +            console.log(arg.foo) // Error!
\ +            console.log(arg.bar) // OK
\ +        }
\ +    }
\ +
\ +    doStuff({ foo: 123, common: '123' })
\ +    doStuff({ bar: 123, common: '123' })
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Foo {
\ +        foo: number = 0
\ +        common: string = \"\"
\ +    }
\ +
\ +    class Bar {
\ +        bar: number = 0
\ +        common: string = \"\"
\ +    }
\ +
\ +    function isFoo(arg: Object): boolean {
\ +        return arg instanceof Foo
\ +    }
\ +
\ +    function doStuff(arg: Object): void {
\ +        if (isFoo(arg)) {
\ +            let fooArg = arg as Foo
\ +            console.log(fooArg.foo) // OK
\ +            console.log(arg.bar) // Error!
\ +        }
\ +        else {
\ +            let barArg = arg as Bar
\ +            console.log(arg.foo) // Error!
\ +            console.log(barArg.bar) // OK
\ +        }
\ +    }
\ +
\ +    function main(): void {
\ +        doStuff(new Foo())
\ +        doStuff(new Bar())
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 97 ] = " \ + #97: `keyof` operator is not supported
\ +
Rule
\ + \ +ArkTS has no `keyof` operator because the object layout is defined \ +at compile time and cannot be changed at runtime. Object fields can only be \ +accessed directly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Point {
\ +        x: number = 1
\ +        y: number = 2
\ +    }
\ +
\ +    type PointKeys = keyof Point // The type of PointKeys is \"x\" | \"y\"
\ +
\ +    function getPropertyValue(obj: Point, key: PointKeys) {
\ +        return obj[key]
\ +    }
\ +
\ +    let obj = new Point()
\ +    console.log(getPropertyValue(obj, \"x\")) // prints \"1\"
\ +    console.log(getPropertyValue(obj, \"y\")) // prints \"2\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point {
\ +        x: number = 1
\ +        y: number = 2
\ +    }
\ +
\ +    function getPropertyValue(obj: Point, key: string): number {
\ +        if (key.equals(\"x\")) {
\ +            return obj.x
\ +        }
\ +        if (key.equals(\"y\")) {
\ +            return obj.y
\ +        }
\ +        throw new Error() // No such property
\ +        return 0
\ +    }
\ +
\ +    function main(): void {
\ +        let obj = new Point()
\ +        console.log(getPropertyValue(obj, \"x\")) // prints \"1\"
\ +        console.log(getPropertyValue(obj, \"y\")) // prints \"2\"
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 98 ] = " \ + #98: Spreading an array into function arguments is not supported
\ +
Rule
\ + \ +ArkTS does not support the spread operator. \ +\"Unpack\" data from an array to a callee manually. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    function foo(x, y, z) {}
\ +
\ +    let args = [0, 1, 2]
\ +    foo(...args)
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    function foo(x: number, y: number, z: number): void {}
\ +
\ +    function main(): void {
\ +        let args: number[] = [0, 1, 2]
\ +        foo(args[0], args[1], args[2])
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 99 ] = " \ + #99: Spread operator is not supported
\ +
Rule
\ + \ +ArkTS does not support the spread operator. \ +\"Unpack\" data from arrays indices manually where necessary. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let list = [1, 2]
\ +    list = [...list, 3, 4]
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let list: number[] = [1, 2]
\ +    list = [list[0], list[1], 3, 4]
\ +
\ +

\ +"; + +cookBookMsg[ 100 ] = " \ + #100: Spreading an object is not supported
\ +
Rule
\ + \ +ArkTS does not support the spread operator. \ +\"Unpack\" data from an object to a callee manually, field by field. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    const point2d = {x: 1, y: 2}
\ +    const point3d = {...point2d, z: 3}
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Point2D {
\ +        x: number
\ +        y: number
\ +
\ +        constructor(x: number, y: number) {
\ +            this.x = x
\ +            this.y = y
\ +        }
\ +    }
\ +
\ +    class Point3D {
\ +        x: number
\ +        y: number
\ +        z: number
\ +
\ +        constructor(x: number, y: number, z: number) {
\ +            this.x = x
\ +            this.y = y
\ +            this.z = z
\ +        }
\ +    }
\ +
\ +    function main(): void {
\ +        const point2d = new Point2D(1, 2)
\ +        const point3d = new Point3D(point2d.x, point2d.y, 3)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 103 ] = " \ + #103: Declaration merging is not supported
\ +
Rule
\ + \ +ArkTS does not support merging declratations. All definitions of classes, \ +interfaces and so on must be kept compact in the code base. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    interface Document {
\ +        createElement(tagName: any): Element
\ +    }
\ +
\ +    interface Document {
\ +        createElement(tagName: string): HTMLElement
\ +    }
\ +
\ +    interface Document {
\ +        createElement(tagName: number): HTMLDivElement
\ +        createElement(tagName: boolean): HTMLSpanElement
\ +        createElement(tagName: string, value: number): HTMLCanvasElement
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface Document {
\ +        createElement(tagName: number): HTMLDivElement
\ +        createElement(tagName: boolean): HTMLSpanElement
\ +        createElement(tagName: string, value: number): HTMLCanvasElement
\ +        createElement(tagName: string): HTMLElement
\ +        createElement(tagName: Object): Element
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 104 ] = " \ + #104: Interfaces cannot extend classes
\ +
Rule
\ + \ +ArkTS does not support interfaces that extend classes. Interfaces can extend \ +only interfaces. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Control {
\ +        state: number = 0
\ +    }
\ +
\ +    interface SelectableControl extends Control {
\ +        select(): void
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    interface Control {
\ +        state: number = 0
\ +    }
\ +
\ +    interface SelectableControl extends Control {
\ +        select(): void
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 105 ] = " \ + #105: Property-based runtime type checks are not supported
\ +
Rule
\ + \ +ArkTS requires that object layout is determined in compile-time and cannot \ +be changed at runtime. There for no runtime property-based checks are supported. \ +If you need to do a type cast, use as operator and use desired properties \ +and methods. If some property doesn't exist then an attempt to reference it \ +will result in a compile-time error. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class A {
\ +        foo() {}
\ +        bar() {}
\ +    }
\ +
\ +    function getSomeObject() {
\ +        return new A()
\ +    }
\ +
\ +    let obj: any = getSomeObject()
\ +    if (obj && obj.foo && obj.bar) {
\ +        console.log(\"Yes\") // prints \"Yes\" in this example
\ +    } else {
\ +        console.log(\"No\")
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class A {
\ +        foo(): void {}
\ +        bar(): void {}
\ +    }
\ +
\ +    function getSomeObject(): A {
\ +        return new A()
\ +    }
\ +
\ +    function main(): void {
\ +        let tmp: Object = getSomeObject()
\ +        let obj: A = tmp as A
\ +        obj.foo() // OK
\ +        obj.bar() // OK
\ +        obj.some_foo() // Compile-time error: Method some_foo does not exist on this type
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 106 ] = " \ + #106: Constructor function type is not supported
\ +
Rule
\ + \ +ArkTS does not support the usage of the constructor function type. \ +Use lambdas instead, as they can be generalized to several types of objects. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Person {
\ +        constructor(
\ +            name: string,
\ +            age: number
\ +        ) {}
\ +    }
\ +
\ +    type PersonConstructor = new (name: string, age: number) => Person
\ +
\ +    function createPerson(Ctor: PersonConstructor, name: string, age: number): Person {
\ +        return new Ctor(name, age)
\ +    }
\ +
\ +    const person = createPerson(Person, 'John', 30)
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Person {
\ +        constructor(
\ +            name: string,
\ +            age: number
\ +        ) {}
\ +    }
\ +
\ +    let PersonConstructor: (name: string, age: number): Person = (name: string, age: number): Person => {
\ +        return new Person(name, age)
\ +    }
\ +
\ +    function createPerson(Ctor: (name: string, age: number): Person, name: string, age: number): Person {
\ +        return PersonConstructor(name, age)
\ +    }
\ +
\ +    function main(): void {
\ +        const person = createPerson(PersonConstructor, \"John\", 30)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 107 ] = " \ + #107: Constructor declarations
\ +
Rule
\ + \ +ArkTS does not support optional parameters in constructors. \ +Constructors are not inherited from a superclass to a subclass. Use overloading \ +constructors instead of constructors with optional parameters: \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Foo {
\ +      constructor(bar: string = 'default', baz?: number) {}
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Foo {
\ +        constructor(bar: string) {}
\ +        constructor(bar: string, baz: number) {}
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 108 ] = " \ + #108: Overloaded constructors with shared body are not supported
\ +
Rule
\ + \ +ArkTS does not support sharing a body between function overloads. \ +The shared body feature for constructor is not supported, either. \ +Overload constructor with a separate body for each signature. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Person {
\ +        name: string
\ +        age: number
\ +
\ +        constructor(name: string, age?: number) {
\ +            this.name = name
\ +            if (age) {
\ +                this.age = age
\ +            } else {
\ +                this.age = 0
\ +            }
\ +        }
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Person {
\ +        name: string
\ +        age: number
\ +
\ +        constructor(name: string, age: number) {
\ +            this.name = name
\ +            this.age = age
\ +        }
\ +
\ +        constructor(name: string) {
\ +            this.name = name
\ +            this.age = 0
\ +        }
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 109 ] = " \ + #109: Dynamic property declaration is not supported
\ +
Rule
\ + \ +ArkTS does not support dynamic property declaration. All object properties must \ +be declared immediately in the class. While it can be replaced with an array \ +of objects, it is still better to adhere to the static language paradigm and \ +declare fields, their names and types explicitly. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class Person {
\ +        name: string = \"\"
\ +        age: number = 0
\ +        [key: string]: string | number
\ +    }
\ +
\ +    const person: Person = {
\ +        name: \"John\",
\ +        age: 30,
\ +        email: \"john@example.com\",
\ +        phone: 1234567890,
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    class Person {
\ +        name: string
\ +        age: number
\ +        email: string
\ +        phone: number
\ +
\ +        constructor(name: string, age: number, email: string, phone: number) {
\ +            this.name = name
\ +            this.age = age
\ +            this.email = email
\ +            this.phone = phone
\ +        }
\ +    }
\ +
\ +    function main(): void {
\ +        const person: Person = new Person(\"John\", 30, \"john@example.com\", 1234567890)
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 111 ] = " \ + #111: Explicit values for enumeration constants are not supported
\ +
Rule
\ + \ +Currently, ArkTS does not support assigning explicit values for enums. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    enum E {
\ +        A,
\ +        B,
\ +        C = 10,
\ +        D
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    enum E {
\ +        A,
\ +        B,
\ +        C = 10, // Compile-time error: assigning out of order values for enums is not supported
\ +        D
\ +    }
\ +
\ +    enum E_fixed {
\ +        A,
\ +        B,
\ +        C, // OK
\ +        D
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 112 ] = " \ +"; + +cookBookMsg[ 113 ] = " \ + #113: enum declaration merging is not supported
\ +
Rule
\ + \ +ArkTS does not support merging declratations for enum. \ +The declaration of each enum must be kept compact in the code base. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    enum Color {
\ +        RED,
\ +        GREEN
\ +    }
\ +    enum Color {
\ +        YELLOW
\ +    }
\ +    enum Color {
\ +        BLACK,
\ +        BLUE
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    enum Color {
\ +        RED,
\ +        GREEN,
\ +        YELLOW,
\ +        BLACK,
\ +        BLUE
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 114 ] = " \ + #114: Namespaces cannot be used as objects
\ +
Rule
\ + \ +ArkTS does not support the usage of namespaces as objects. \ +Classes or modules can be interpreted as analogues of namespaces. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    namespace MyNamespace {
\ +        export let x: number
\ +    }
\ +
\ +    let m = MyNamespace
\ +    m.x = 2
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    namespace MyNamespace {
\ +        export let x: number
\ +    }
\ +
\ +    MyNamespace.x = 2
\ +
\ +

\ +"; + +cookBookMsg[ 115 ] = " \ + #115: Scripts and modules
\ +
Rule
\ + \ +In general, scripts and modules in ArkTS are very close to TypeScript. \ +Differences are described in separate recipes. \ + \ +
\ +"; + +cookBookMsg[ 116 ] = " \ + #116: Non-declaration statements in namespaces are not supported
\ +
Rule
\ + \ +ArkTS does not support statements in namespaces. Use a function to exectute statements. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    namespace A {
\ +        export let x: number
\ +        x = 1
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ +Initialization function should be called to execute statements. \ + \ + \ +
\ +    namespace A {
\ +        export let x: number
\ +
\ +        export function init() {
\ +          x = 1
\ +        }
\ +    }
\ +    A.init()
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 117 ] = " \ + #117: Statement as top-level element
\ +
Rule
\ + \ +ArkTS does not support statements as top-level elements. Statements must be \ +placed in a block {}. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    let a = 1
\ +    let b = 2
\ +    if (b == a) {
\ +        console.log(\"a EQ b\")
\ +    } else {
\ +        console.log(\"a NEQ b\")
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // A block can be a top-level element,
\ +    // put statements inside one or several blocks:
\ +    {
\ +        let a = 1
\ +        let b = 2
\ +    }
\ +
\ +    {
\ +        if (b == a) {
\ +            console.log(\"a EQ b\")
\ +        } else {
\ +            console.log(\"a NEQ b\")
\ +        }
\ +    }
\ +
\ +
\ +

\ +"; + +cookBookMsg[ 118 ] = " \ + #118: Special import type declarations are not supported
\ +
Rule
\ + \ +ArkTS does not have a special notation for importing types. \ +Use ordinary import instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // Re-using the same import
\ +    import { APIResponseType } from \"./api\"
\ +
\ +    // Explicitly use import type
\ +    import type { APIResponseType } from \"./api\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    import { APIResponseType } from \"./api\"
\ +
\ +

\ +"; + +cookBookMsg[ 119 ] = " \ + #119: Importing a module for side-effects only is not supported
\ +
Rule
\ + \ +ArkTS does not support global variables like window to avoid \ +side-effects during module importing. All variables marked as export can be \ +accessed through the * syntax. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // === module at \"path/to/module.ts\"
\ +    export const EXAMPLE_VALUE = 42
\ +
\ +    // Set a global variable
\ +    window.MY_GLOBAL_VAR = \"Hello, world!\"
\ +
\ +    // ==== using this module:
\ +    import \"path/to/module\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    import * from \"path/to/module\"
\ +
\ +

\ +"; + +cookBookMsg[ 120 ] = " \ + #120: import default as ... is not supported
\ +
Rule
\ + \ +ArkTS does not support import default as ... syntax. \ +Use explicit import ... from ... instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    import { default as d } from \"mod\"
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    import d from \"mod\"
\ +
\ +

\ +"; + +cookBookMsg[ 121 ] = " \ + #121: require is not supported
\ +
Rule
\ + \ +ArkTS does not support importing via require. Use import instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    import m = require(\"mod\")
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    import * as m from \"mod\"
\ +
\ +

\ +"; + +cookBookMsg[ 122 ] = " \ + #122: export default is not supported
\ +
Rule
\ + \ +ArkTS does not support export default. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // file1.ts
\ +    export default class MyClass {
\ +        // ...
\ +    }
\ +
\ +    // file2.ts
\ +    // Can write just `MyClass` instead of `{ MyClass }` in case of default export
\ +    import MyClass from './file1'
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // module1
\ +    export class MyClass {
\ +        // ...
\ +    }
\ +
\ +    // module2
\ +    // Use explicit name in import
\ +    import { MyClass } from \"./module1\"
\ +
\ +

\ +"; + +cookBookMsg[ 123 ] = " \ + #123: Renaming in export declarations is not supported
\ +
Rule
\ + \ +ArkTS does not support renaming in export declarations. Similar effect \ +can be achieved through setting an alias for the exported entity. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // file1.ts
\ +    class MyClass {
\ +        // ...
\ +    }
\ +
\ +    export { MyClass as RenamedClass }
\ +
\ +    // file2.ts
\ +    import { RenamedClass } from \"./file1\"
\ +
\ +    function main(): void {
\ +        const myObject = new RenamedClass()
\ +        // ...
\ +    }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // module1
\ +    class MyClass {
\ +        // ...
\ +    }
\ +
\ +    export RenamedClass = MyClass
\ +
\ +    // module2
\ +    import RenamedClass from \"./module1\"
\ +
\ +    function main(): void {
\ +        const myObject = new RenamedClass()
\ +        // ...
\ +    }
\ +
\ +

\ +"; + +cookBookMsg[ 124 ] = " \ + #124: Export list declaration is not supported
\ +
Rule
\ + \ +ArkTS does not support syntax of export list declarations. All exported \ +entities must be explicitly annotated with the export keyword. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    export { x }
\ +    export { x } from \"mod\"
\ +    export { x, y as b, z as c }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    let x = 1
\ +    class MyClass {}
\ +    export let y = x, z: number = 2
\ +    export RenamedClass = MyClass
\ +
\ +

\ +"; + +cookBookMsg[ 125 ] = " \ + #125: Re-exporting is not supported
\ +
Rule
\ + \ +ArkTS does not support re-exporting. All desired entities must be \ +imported explicitly from the modules that export them. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // module1
\ +    export class MyClass {
\ +        // ...
\ +    }
\ +
\ +    // module2
\ +    export { MyClass } from \"module1\"
\ +
\ +    // consumer module
\ +    import { MyClass } from \"module2\"
\ +
\ +    const myInstance = new MyClass()
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // module1
\ +    export class MyClass {
\ +      // ...
\ +    }
\ +
\ +    // module2
\ +    // some stuff
\ +
\ +    // consumer module
\ +    import MyClass from \"module1\"
\ +    import * from \"module2\"
\ +
\ +    const myInstance = new MyClass()
\ +
\ +

\ +"; + +cookBookMsg[ 126 ] = " \ + #126: export = ... assignment is not supported
\ +
Rule
\ + \ +ArkTS does not support export = ... syntax. \ +Use regular export / import instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    // module1
\ +    export = Point
\ +
\ +    class Point {
\ +        constructor(x: number, y: number) {}
\ +        static origin = new Point(0, 0)
\ +    }
\ +
\ +    // module2
\ +    import Pt = require(\"module1\")
\ +
\ +    let p = Pt.origin
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    // module1
\ +    export class Point {
\ +        constructor(x: number, y: number) {}
\ +        static origin = new Point(0, 0)
\ +    }
\ +
\ +    // module2
\ +    import * as Pt from \"module1\"
\ +
\ +    let p = Pt.origin
\ +
\ +

\ +"; + +cookBookMsg[ 127 ] = " \ + #127: Special export type declarations are not supported
\ +
Rule
\ + \ +ArkTS does not have a special notation for exporting types. \ +Use ordinary export instead. \ + \ +
\ +
TypeScript
\ + \ + \ +
\ +    class C {}
\ +    export type { C }
\ +
\ +

\ +
ArkTS
\ + \ + \ +
\ +    export class C {}
\ +    
\ +
\ +

\ +"; + +cookBookTag[ 1 ] = "#1: Objects with property names that are not identifiers are not supported"; +cookBookTag[ 2 ] = "#2: 'Symbol()' API is not supported"; +cookBookTag[ 3 ] = "#3: Private '#' identifiers are not supported"; +cookBookTag[ 4 ] = "#4: Use unique names for types, namespaces, etc."; +cookBookTag[ 5 ] = "#5: Use 'let' instead of 'var'"; +cookBookTag[ 6 ] = ""; +cookBookTag[ 7 ] = ""; +cookBookTag[ 8 ] = "#8: Use explicit types instead of 'any', 'undefined', 'unknown'"; +cookBookTag[ 9 ] = "#9: You can extend your TypeScript code with more numeric types"; +cookBookTag[ 10 ] = "#10: Use 'long' instead of 'bigint'"; +cookBookTag[ 11 ] = "#11: Use 'enum' instead of string literal types"; +cookBookTag[ 12 ] = "#12: Use 'T[]' instead of 'Array' to declare arrays"; +cookBookTag[ 13 ] = "#13: Use 'Object[]' instead of tuples"; +cookBookTag[ 14 ] = "#14: Use 'class' instead of a type with call signature"; +cookBookTag[ 15 ] = "#15: Use 'class' instead of a type with constructor signature"; +cookBookTag[ 16 ] = "#16: Only one static block is supported"; +cookBookTag[ 17 ] = "#17: Indexed signatures are not supported"; +cookBookTag[ 18 ] = "#18: Use 'Object' instead of union types"; +cookBookTag[ 19 ] = "#19: Use inheritance instead of intersection types"; +cookBookTag[ 20 ] = "#20: Default values for type parameters in generics are not supported"; +cookBookTag[ 21 ] = "#21: Returning 'this' type is not supported"; +cookBookTag[ 22 ] = ""; +cookBookTag[ 23 ] = "#22: Conditional types are not supported"; +cookBookTag[ 24 ] = "#24: Optional arguments are not supported"; +cookBookTag[ 25 ] = "#25: Declaring fields in 'constructor' is not supported"; +cookBookTag[ 26 ] = "#26: Specialized signatures are not supported"; +cookBookTag[ 27 ] = "#27: Construct signatures not supported in interfaces"; +cookBookTag[ 28 ] = "#28: Indexed access types are not supported"; +cookBookTag[ 29 ] = "#29: Indexed access is not supported for fields"; +cookBookTag[ 30 ] = "#30: Structural identity is not supported"; +cookBookTag[ 31 ] = "#31: Structural typing is not supported for subtyping / supertyping"; +cookBookTag[ 32 ] = "#32: Structural typing is not supported for assignability checks"; +cookBookTag[ 33 ] = "#33: Optional properties are not supported"; +cookBookTag[ 34 ] = "#34: Generic functions must be called with explicit type specialization"; +cookBookTag[ 35 ] = "#35: Structural typing is not supported for type inference"; +cookBookTag[ 36 ] = "#36: Type widening is not supported"; +cookBookTag[ 37 ] = "#37: RegExp literals are not supported"; +cookBookTag[ 38 ] = "#38: Object literal must correspond to explicitly declared class or interface"; +cookBookTag[ 39 ] = "#39: Object literals must correspond to explicitly declared class or interface"; +cookBookTag[ 40 ] = "#40: Object literals cannot be used as type declarations"; +cookBookTag[ 41 ] = ""; +cookBookTag[ 42 ] = "#42: Array literals must correspond to known array types"; +cookBookTag[ 43 ] = "#43: Untyped array literals are not supported"; +cookBookTag[ 44 ] = "#44: Template literals are not supported"; +cookBookTag[ 45 ] = "#45: Lambdas require explicit type annotation for parameters"; +cookBookTag[ 46 ] = "#46: Use arrow functions instead of function expressions"; +cookBookTag[ 47 ] = "#47: Return type must be specified for lambdas explicitly"; +cookBookTag[ 48 ] = "#48: Shortcut syntax for lambdas is not supported"; +cookBookTag[ 49 ] = ""; +cookBookTag[ 50 ] = "#50: Class literals are not supported"; +cookBookTag[ 51 ] = "#51: Classes cannot be specified in 'implements' clause"; +cookBookTag[ 52 ] = "#52: Attempt to access an undefined property is a compile-time error"; +cookBookTag[ 53 ] = "#53: Only 'as T' syntax is supported for type casts"; +cookBookTag[ 54 ] = "#54: JSX expressions are not supported"; +cookBookTag[ 55 ] = "#55: Unary operators '+', '-' and '~' work only on numbers"; +cookBookTag[ 56 ] = "#56: Unary '+' cannot be used for casting to 'number'"; +cookBookTag[ 57 ] = "#57: '!' operator works only on values of the boolean type"; +cookBookTag[ 58 ] = ""; +cookBookTag[ 59 ] = "#59: 'delete' operator is not supported"; +cookBookTag[ 60 ] = "#60: 'typeof' operator is not supported"; +cookBookTag[ 61 ] = "#61: Binary operators '*', '/', '%', '-', '<<', '>>', '>>>', '&', '^' and '|' work only on numeric types"; +cookBookTag[ 62 ] = "#62: Binary operators '<<', '>>', '>>>', '&', '^' and '|' work only on integral numeric types"; +cookBookTag[ 63 ] = "#63: Binary '+' operator supports implicit casts only for numbers and strings"; +cookBookTag[ 64 ] = "#64: Binary '+' operator requires explicit casts for non-numbers and non-strings"; +cookBookTag[ 65 ] = ""; +cookBookTag[ 66 ] = "#66: 'in' operator is not supported"; +cookBookTag[ 67 ] = "#67: Operators '&&' and '||' work on values of the boolean type only"; +cookBookTag[ 68 ] = "#68: Using of '&&' and '||' on non-boolean types is not supported"; +cookBookTag[ 69 ] = "#69: Destructuring assignment is not supported"; +cookBookTag[ 70 ] = ""; +cookBookTag[ 71 ] = "#71: The comma operator ',' is supported only in 'for' loops"; +cookBookTag[ 72 ] = ""; +cookBookTag[ 73 ] = "#74: Destructuring variable declarations are not supported"; +cookBookTag[ 74 ] = ""; +cookBookTag[ 75 ] = ""; +cookBookTag[ 76 ] = "#76: Inference of implied types is not supported"; +cookBookTag[ 77 ] = ""; +cookBookTag[ 78 ] = "#78: Implicit casts to the boolean are not supported in 'if', 'do' and 'while'"; +cookBookTag[ 79 ] = "#79: Type annotation in catch clause is not supported"; +cookBookTag[ 80 ] = "#80: 'for .. in' is not supported"; +cookBookTag[ 81 ] = "#81: Iterable interfaces are not supported"; +cookBookTag[ 82 ] = "#82: 'for-of' is supported only for arrays"; +cookBookTag[ 83 ] = "#83: Mapped type expression is not supported"; +cookBookTag[ 84 ] = "#84: 'with' statement is not supported"; +cookBookTag[ 85 ] = "#85: Values computed at runtime are not supported in 'case' statements"; +cookBookTag[ 86 ] = "#86: 'switch' statements cannot accept values of arbitrary types"; +cookBookTag[ 87 ] = "#87: 'throw' statements cannot accept values of arbitrary types"; +cookBookTag[ 88 ] = "#88: Each overloaded function should have its body"; +cookBookTag[ 89 ] = "#89: Each overloaded function with optional parameters should have its body"; +cookBookTag[ 90 ] = "#90: Function must have explicit return type"; +cookBookTag[ 91 ] = ""; +cookBookTag[ 92 ] = "#92: Nested functions are not supported"; +cookBookTag[ 93 ] = "#93: Using 'this' inside stand-alone functions is not supported"; +cookBookTag[ 94 ] = "#94: Generator functions are not supported"; +cookBookTag[ 95 ] = "#95: Asynchronous functions are partially supported"; +cookBookTag[ 96 ] = "#96: Type guarding is supported with 'instanceof' and 'as'"; +cookBookTag[ 97 ] = "#97: `keyof` operator is not supported"; +cookBookTag[ 98 ] = "#98: Spreading an array into function arguments is not supported"; +cookBookTag[ 99 ] = "#99: Spread operator is not supported"; +cookBookTag[ 100 ] = "#100: Spreading an object is not supported"; +cookBookTag[ 101 ] = ""; +cookBookTag[ 102 ] = ""; +cookBookTag[ 103 ] = "#103: Declaration merging is not supported"; +cookBookTag[ 104 ] = "#104: Interfaces cannot extend classes"; +cookBookTag[ 105 ] = "#105: Property-based runtime type checks are not supported"; +cookBookTag[ 106 ] = "#106: Constructor function type is not supported"; +cookBookTag[ 107 ] = "#107: Constructor declarations"; +cookBookTag[ 108 ] = "#108: Overloaded constructors with shared body are not supported"; +cookBookTag[ 109 ] = "#109: Dynamic property declaration is not supported"; +cookBookTag[ 110 ] = ""; +cookBookTag[ 111 ] = "#111: Explicit values for enumeration constants are not supported"; +cookBookTag[ 112 ] = ""; +cookBookTag[ 113 ] = "#113: 'enum' declaration merging is not supported"; +cookBookTag[ 114 ] = "#114: Namespaces cannot be used as objects"; +cookBookTag[ 115 ] = "#115: Scripts and modules"; +cookBookTag[ 116 ] = "#116: Non-declaration statements in namespaces are not supported"; +cookBookTag[ 117 ] = "#117: Statement as top-level element"; +cookBookTag[ 118 ] = "#118: Special import type declarations are not supported"; +cookBookTag[ 119 ] = "#119: Importing a module for side-effects only is not supported"; +cookBookTag[ 120 ] = "#120: 'import default as ...' is not supported"; +cookBookTag[ 121 ] = "#121: 'require' is not supported"; +cookBookTag[ 122 ] = "#122: 'export default' is not supported"; +cookBookTag[ 123 ] = "#123: Renaming in export declarations is not supported"; +cookBookTag[ 124 ] = "#124: Export list declaration is not supported"; +cookBookTag[ 125 ] = "#125: Re-exporting is not supported"; +cookBookTag[ 126 ] = "#126: 'export = ...' assignment is not supported"; +cookBookTag[ 127 ] = "#127: Special export type declarations are not supported"; diff --git a/linter/src/LinterRunner.ts b/linter/src/LinterRunner.ts new file mode 100644 index 000000000..33e1040e5 --- /dev/null +++ b/linter/src/LinterRunner.ts @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; +import { TypeScriptLinter } from "./TypeScriptLinter"; +import { NodeType } from "./Problems"; +import { parseCommandLine, CommandLineOptions } from "./CommandLineParser"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as readline from "node:readline"; +import * as path from "node:path" + +const BAD_SYNTAX_NUM = NodeType.LAST_NODE_TYPE; + +const { pipeline } = require('node:stream'); +const tmpFileName = os.tmpdir() + "/linter_tmp_file.ts"; + +function console_log(...data: string[] | any []) { + if(TypeScriptLinter.IDE_mode) + return; + + let k = 0; + let outLine = ''; + while(k < data.length) { + outLine += `${data[k]}`; + k++ + } + + console.log(outLine) +} + +function compile(createProgramOptions: ts.CreateProgramOptions): ts.Program { + let program = ts.createProgram(createProgramOptions); + + // Log Tsc errors if needed + if(TypeScriptLinter.TSC_Errors) { + let diagnostics = ts.getPreEmitDiagnostics(program); + diagnostics.forEach(diagnostic => { + if (diagnostic.file) { + let { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); + let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + console_log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } else { + console_log(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); + } + }); + } + + return program; +} + +export function lint(cmdOptions: CommandLineOptions): number { + TypeScriptLinter.STRICT_mode = !!cmdOptions.Strict_Mode; + TypeScriptLinter.TSC_Errors = !!cmdOptions.TSC_Errors; + + let tsProgramOptions: ts.CreateProgramOptions; + if (cmdOptions.ParsedConfigFile) { + tsProgramOptions = { + rootNames: cmdOptions.ParsedConfigFile.fileNames, + options: cmdOptions.ParsedConfigFile.options, + projectReferences: cmdOptions.ParsedConfigFile.projectReferences, + configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(cmdOptions.ParsedConfigFile) + }; + } else { + tsProgramOptions = { + rootNames: cmdOptions.InputFiles, + options: { + target: ts.ScriptTarget.Latest, + module: ts.ModuleKind.CommonJS + } + }; + } + const tsProgram = compile(tsProgramOptions); + + // Prepare list of input files for linter and retrieve AST for those files. + let linterInputFiles: string[]; + if (cmdOptions.ParsedConfigFile) { + linterInputFiles = cmdOptions.ParsedConfigFile.fileNames; + + if (cmdOptions.InputFiles.length > 0) { + // Apply linter only to the project source files that are specified + // as a command-line arguments. Other source files will be discarded. + let cmdInputsResolvedPaths = cmdOptions.InputFiles.map(x => path.resolve(x)); + let configInputsResolvedPaths = linterInputFiles.map(x => path.resolve(x)); + linterInputFiles = configInputsResolvedPaths.filter(x => cmdInputsResolvedPaths.some(y => x === y)); + } + } + else { + linterInputFiles = cmdOptions.InputFiles; + } + + let tsSrcFiles = linterInputFiles.map((val, idx, array) => tsProgram.getSourceFile(val)); + + let problemFileCounter = 0; + console_log("\n\n\n"); + for (let tsSrcFile of tsSrcFiles) { + let currentNodes = TypeScriptLinter.nodeCntr; + let currentLines = TypeScriptLinter.commonLineCounter; + TypeScriptLinter.lineNumbersString = ""; + TypeScriptLinter.lineNumbersStringPosCntr = 0; + TypeScriptLinter.specificNodeLineNumbers = ""; + TypeScriptLinter.specificNodeLineNumbersPosCntr = 0; + let nodeCounters: number[] = [ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0 ]; + let lineCounters: number[] = [ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0 ]; + + for (let i = 0 ; i < BAD_SYNTAX_NUM; i++) { + nodeCounters[i] = TypeScriptLinter.nodeCounters[i]; + lineCounters[i] = TypeScriptLinter.lineCounters[i]; + } + + let linter = new TypeScriptLinter(tsSrcFile, tsProgram); + + linter.lint(); + + // print results for current file + let currentFileNodes = TypeScriptLinter.nodeCntr - currentNodes; + let currentFileLines = TypeScriptLinter.commonLineCounter - currentLines; + + let badNodes = 0; + let badLines = 0; + for (let i = 0 ; i< BAD_SYNTAX_NUM; i++) { + badNodes += TypeScriptLinter.nodeCounters[i] - nodeCounters[i]; + badLines += TypeScriptLinter.lineCounters[i] - lineCounters[i]; + } + + if (badNodes > 0) { + problemFileCounter++; + console_log( tsSrcFile.fileName, ": ", + "\n\tProblem lines: ", TypeScriptLinter.lineNumbersString, + "\n\tuntranslated nodes (%): ", + (badNodes / currentFileNodes * 100).toFixed(2), + "\t[ of ", currentFileNodes, " nodes ], \t", + currentFileLines, " lines"); + console_log("\tUnion types at lines: ", TypeScriptLinter.specificNodeLineNumbers,"\n") + } + + // Printing of the used decorator is a temporary functionality. It's just to collec statistic of used decorator types. + if (linter.decorators.size) { + console_log("Used decorators:"); + linter.decorators.forEach((v: number, key: String) => { console_log("\t", key, "\t\t", v); }); + } + else + console_log("No decorators used."); + + //let xmlString = stsCompUnit.toXML(); + //let xmlFile = tsSrcFile.fileName + ".xml"; + //writeFileSync(xmlFile, xmlString); + } + + console_log("\nFiles scanned: ", tsSrcFiles.length, " . Files with untranslatable syntax: ", problemFileCounter); + + let badNodes = 0; + let sumLines = 0; + for (let i = 0 ; i < BAD_SYNTAX_NUM; i++) { + // if Strict mode - count all cases + if (TypeScriptLinter.STRICT_mode || TypeScriptLinter.printInRelaxModeFlags[i]) { + badNodes += TypeScriptLinter.nodeCounters[i]; + sumLines += TypeScriptLinter.lineCounters[i]; + } + } + + console_log("\nTotal untranslateble nodes (%): ", + (badNodes / TypeScriptLinter.nodeCntr * 100).toFixed(2), + "\t[ of ", TypeScriptLinter.nodeCntr, " nodes ], \t", + TypeScriptLinter.commonLineCounter, " lines\n") + + console_log("\nPercent by features: "); + + for (let i = 0 ; i< BAD_SYNTAX_NUM; i++) { + // if Strict mode - count all cases + if (!TypeScriptLinter.STRICT_mode && !TypeScriptLinter.printInRelaxModeFlags[i]) + continue; + + console_log(TypeScriptLinter.nodeDescription[i], + (TypeScriptLinter.nodeCounters[i] / TypeScriptLinter.nodeCntr * 100).toFixed(2), + "\t[",TypeScriptLinter.nodeCounters[i], + " nodes / ",TypeScriptLinter.lineCounters[i], + " lines]" ); + + // Commenting this out, as it's not a problem any more but a part of STS language. + // if( i === NodeType.UnionType ) { + // console_log( "\t\t\t union nodes of kind T | null : ", TypeScriptLinter.unionTNull); + // console_log( "\t\t\t union nodes of kind T | any : ", TypeScriptLinter.unionTAny); + // console_log( "\t\t\t union nodes of kind T | undefined : ", TypeScriptLinter.unionTUndefined); + // } + + if( i === NodeType.ObjectLiteralNoContextType ) { + console_log( "\t\t\t object literal nodes which are not function parameters : ", TypeScriptLinter.objLiteralNotParameter); + } + } + return badNodes; +} + +export function run() { + let commandLineArgs = process.argv.slice(2); + if (commandLineArgs.length === 0) { + console.log("Command line error: no arguments"); + process.exit(-1); + } + let cmdOptions = parseCommandLine(commandLineArgs); + + if(!cmdOptions.IDE_Mode) { + let result = lint(cmdOptions); + process.exit(result > 0 ? 1 : 0); + } else { + run_IDE_mode(cmdOptions); + } +} + +function run_IDE_mode(cmdOptions: CommandLineOptions) { + TypeScriptLinter.IDE_mode = true; + + // read data from stdin + let writeStream = fs.createWriteStream(tmpFileName, {flags: 'w'} ); + + const rl = readline.createInterface({ + input: process.stdin, + output: writeStream, + terminal: false + }); + + rl.on('line', (line:string) => { + fs.appendFileSync(tmpFileName, line + '\n'); + }); + let ready = false + rl.once('close', () => { + // end of input + writeStream.close(); + + cmdOptions.InputFiles = [tmpFileName]; + if (cmdOptions.ParsedConfigFile) { + cmdOptions.ParsedConfigFile.fileNames.push(tmpFileName); + } + + lint(cmdOptions); + + let jsonMessage = TypeScriptLinter.badNodeInfos.map(x => ({ + line: x.line, + column: x.column, + start: x.start, + end: x.end, + type: x.type, + suggest: x.suggest, + rule: x.rule + })); + console.log("{\"linter messages\":" + JSON.stringify(jsonMessage) + "}"); + fs.unlinkSync(tmpFileName); + }); +} \ No newline at end of file diff --git a/linter/src/Problems.ts b/linter/src/Problems.ts new file mode 100644 index 000000000..a33bd62cc --- /dev/null +++ b/linter/src/Problems.ts @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; +import { cookBookMsg } from "./CookBookMsg"; + +export enum NodeType { + AnyType, + SymbolType, + UnionType, + TupleType, + ObjectLiteralNoContextType, + ArrayLiteralNoContextType, + ComputedPropertyName, + LiteralAsPropertyName, + TypeOfExpression, + TupleLiteral, + UnionLiteral, + RegexLiteral, + IsOperator, + DestructuringParameter, + YieldExpression, + InterfaceOrEnumMerging, + InterfaceExtendsClass, + IndexMember, + WithStatement, + ThrowStatement, + IndexedAccessType, + UndefinedType, + UnknownType, + ForInStatement, + InOperator, + SpreadOperator, + KeyOfOperator, + ImportFromPath, + FunctionExpression, + + TypeParameterWithDefaultValue, + IntersectionType, + ObjectTypeLiteral, + LogicalWithNonBoolean, + AddWithWrongType, + BitOpWithWrongType, + CommaOperator, + TopLevelStmt, + + IfWithNonBoolean, + DoWithNonBoolean, + WhileWithNonBoolean, + FuncWithoutReturnType, + ArrowFunctionWithOmittedTypes, + LambdaWithTypeParameters, + ClassExpression, + DestructuringAssignment, + DestructuringDeclaration, + + ForOfNonArray, + VarDeclaration, + CatchWithUnsupportedType, + + DeleteOperator, + DeclWithDuplicateName, + FuncOptionalParams, + + UnaryArithmNotNumber, + LogNotWithNotBool, + ConstructorType, + CallSignature, + TemplateLiteral, + TypeAssertion, + FunctionOverload, + ConstructorOverload, + + PrivateIdentifier, + LocalFunction, + SwitchSelectorInvalidType, + CaseExpressionNonConst, + ConditionalType, + MappedType, + NamespaceAsObject, + NonDeclarationInNamespace, + GeneratorFunction, + FunctionContainsThis, + PropertyAccessByIndex, + JsxElement, + EnumMemberWithInitializer, + + ImplementsClass, + MultipleStaticBlocks, + //Decorators, // It's not a problem and counted temporary just to have statistic of decorators use. + ThisType, + InferType, + SpreadAssignment, + IntefaceExtendDifProps, + DynamicTypeCheck, + + TypeOnlyImport, + TypeOnlyExport, + DefaultImport, + DefaultExport, + ExportRenaming, + ExportListDeclaration, + ReExporting, + ExportAssignment, + ImportAssignment, + + ObjectRuntimeCheck, + GenericCallNoTypeArgs, + + BigIntType, + BigIntLiteral, + StringLiteralType, + InterfaceOptionalProp, + ParameterProperties, + InstanceofUnsupported, + GenericArrayType, + + LAST_NODE_TYPE // this should always be last enum` +} + +export class TsProblemInfo { + tag?: string; + suggestion?: string; + printInRelaxMode?: boolean = true; + cookBookRef: string; + } + +export var problemList: TsProblemInfo[] = []; + +problemList[NodeType.AnyType] = { + cookBookRef: "8" +} + +problemList[NodeType.SymbolType] = { + cookBookRef: "2" +} + +problemList[NodeType.UnionType] = { + cookBookRef: "18" +} + +problemList[NodeType.TupleType] = { + cookBookRef: "13" +} + +problemList[NodeType.ObjectLiteralNoContextType] = { + printInRelaxMode: false, + cookBookRef: "38" +} + +problemList[NodeType.ArrayLiteralNoContextType] = { + printInRelaxMode: false, + cookBookRef: "42" +} + +problemList[NodeType.ComputedPropertyName] = { + cookBookRef: "1" +} + +problemList[NodeType.LiteralAsPropertyName] = { + cookBookRef: "1" +} + +problemList[NodeType.TypeOfExpression] = { + cookBookRef: "60" +} + +problemList[NodeType.TupleLiteral] = { + cookBookRef: "13" +} + +problemList[NodeType.UnionLiteral] = { + cookBookRef: "18" +} + +problemList[NodeType.RegexLiteral] = { + cookBookRef: "37" +} + +problemList[NodeType.IsOperator] = { + cookBookRef: "96" +} + +problemList[NodeType.DestructuringParameter] = { + cookBookRef: "91" +} + +problemList[NodeType.YieldExpression] = { + cookBookRef: "94" +} + +problemList[NodeType.InterfaceOrEnumMerging] = { + cookBookRef: "103" +} + +problemList[NodeType.InterfaceExtendsClass] = { + cookBookRef: "104" +} + +problemList[NodeType.IndexMember] = { + cookBookRef: "17" +} + +problemList[NodeType.WithStatement] = { + cookBookRef: "84" +} + +problemList[NodeType.ThrowStatement] = { + printInRelaxMode: false, + cookBookRef: "87" +} + +problemList[NodeType.IndexedAccessType] = { + cookBookRef: "28" +} + +problemList[NodeType.UndefinedType] = { + cookBookRef: "8" +} + +problemList[NodeType.UnknownType] = { + cookBookRef: "8" +} + +problemList[NodeType.ForInStatement] = { + cookBookRef: "80" +} + +problemList[NodeType.InOperator] = { + cookBookRef: "66" +} + +problemList[NodeType.SpreadOperator] = { + cookBookRef: "98" +} + +problemList[NodeType.KeyOfOperator] = { + cookBookRef: "97" +} + +problemList[NodeType.ImportFromPath] = { + cookBookRef: "119" +} + +problemList[NodeType.FunctionExpression] = { + printInRelaxMode: false, + cookBookRef: "46" +} + +problemList[NodeType.TypeParameterWithDefaultValue] = { + printInRelaxMode: false, + cookBookRef: "20" +} + +problemList[NodeType.IntersectionType] = { + cookBookRef: "19" +} + +problemList[NodeType.ObjectTypeLiteral] = { + cookBookRef: "40" +} + +problemList[NodeType.LogicalWithNonBoolean] = { + cookBookRef: "67" +} + +problemList[NodeType.AddWithWrongType] = { + cookBookRef: "63" +} + +problemList[NodeType.BitOpWithWrongType] = { + cookBookRef: "61" +} + +problemList[NodeType.CommaOperator] = { + cookBookRef: "71" +} + +problemList[NodeType.TopLevelStmt] = { + cookBookRef: "117" +} + +problemList[NodeType.IfWithNonBoolean] = { + printInRelaxMode: false, + cookBookRef: "78" +} + +problemList[NodeType.DoWithNonBoolean] = { + printInRelaxMode: false, + cookBookRef: "78" +} + +problemList[NodeType.WhileWithNonBoolean] = { + printInRelaxMode: false, + cookBookRef: "78" +} + +problemList[NodeType.FuncWithoutReturnType] = { + printInRelaxMode: false, + cookBookRef: "90" +} + +problemList[NodeType.ArrowFunctionWithOmittedTypes] = { + printInRelaxMode: false, + cookBookRef: "45" +} + +problemList[NodeType.LambdaWithTypeParameters] = { + cookBookRef: "49" +} + +problemList[NodeType.ClassExpression] = { + printInRelaxMode: false, + cookBookRef: "50" +} + +problemList[NodeType.DestructuringAssignment] = { + printInRelaxMode: false, + cookBookRef: "69" +} + +problemList[NodeType.DestructuringDeclaration] = { + printInRelaxMode: false, + cookBookRef: "74" +} + +problemList[NodeType.ForOfNonArray] = { + printInRelaxMode: false, + cookBookRef: "82" +} + +problemList[NodeType.VarDeclaration] = { + printInRelaxMode: false, + cookBookRef: "5" +} + +problemList[NodeType.CatchWithUnsupportedType] = { + printInRelaxMode: false, + cookBookRef: "79" +} + +problemList[NodeType.DeleteOperator] = { + cookBookRef: "59" +} + +problemList[NodeType.DeclWithDuplicateName] = { + cookBookRef: "4" +} + +problemList[NodeType.FuncOptionalParams] = { + cookBookRef: "24" +} + +problemList[NodeType.UnaryArithmNotNumber] = { + cookBookRef: "55" +} + +problemList[NodeType.LogNotWithNotBool] = { + cookBookRef: "57" +} + +problemList[NodeType.ConstructorType] = { + cookBookRef: "15" +} + +problemList[NodeType.CallSignature] = { + cookBookRef: "14" +} + +problemList[NodeType.TemplateLiteral] = { + printInRelaxMode: false, + cookBookRef: "44" +} + +problemList[NodeType.TypeAssertion] = { + cookBookRef: "53" +} + +problemList[NodeType.FunctionOverload] = { + cookBookRef: "88" +} + + +problemList[NodeType.ConstructorOverload] = { + cookBookRef: "108" +} + +problemList[NodeType.PrivateIdentifier] = { + printInRelaxMode: false, + cookBookRef: "3" +} + +problemList[NodeType.LocalFunction] = { + printInRelaxMode: false, + cookBookRef: "92" +} + +problemList[NodeType.SwitchSelectorInvalidType] = { + cookBookRef: "86" +} + +problemList[NodeType.CaseExpressionNonConst] = { + cookBookRef: "85" +} + +problemList[NodeType.ConditionalType] = { + cookBookRef: "22" +} + +problemList[NodeType.MappedType] = { + cookBookRef: "83" +} + +problemList[NodeType.NamespaceAsObject] = { + cookBookRef: "114" +} + +problemList[NodeType.NonDeclarationInNamespace] = { + cookBookRef: "116" +} + +problemList[NodeType.GeneratorFunction] = { + cookBookRef: "94" +} + +problemList[NodeType.FunctionContainsThis] = { + cookBookRef: "93" +} + +problemList[NodeType.PropertyAccessByIndex] = { + cookBookRef: "29" +} + +problemList[NodeType.JsxElement] = { + cookBookRef: "54" +} + +problemList[NodeType.EnumMemberWithInitializer] = { + cookBookRef: "111" +} + +problemList[NodeType.ImplementsClass] = { + cookBookRef: "51" +} + +problemList[NodeType.MultipleStaticBlocks] = { + cookBookRef: "16" +} + +problemList[NodeType.ThisType] = { + cookBookRef: "21" +} + +problemList[NodeType.InferType] = { + cookBookRef: "76" +} + +problemList[NodeType.SpreadAssignment] = { + cookBookRef: "100" +} + +problemList[NodeType.IntefaceExtendDifProps] = { + cookBookRef: "102" +} + +problemList[NodeType.DynamicTypeCheck] = { + cookBookRef: "30" +} + +problemList[NodeType.TypeOnlyImport] = { + printInRelaxMode: false, + cookBookRef: "118" +} + +problemList[NodeType.TypeOnlyExport] = { + printInRelaxMode: false, + cookBookRef: "127" +} + +problemList[NodeType.DefaultImport] = { + printInRelaxMode: false, + cookBookRef: "120" +} + +problemList[NodeType.DefaultExport] = { + printInRelaxMode: false, + cookBookRef: "122" +} + +problemList[NodeType.ExportRenaming] = { + printInRelaxMode: false, + cookBookRef: "123" +} + +problemList[NodeType.ExportListDeclaration] = { + printInRelaxMode: false, + cookBookRef: "124" +} + +problemList[NodeType.ReExporting] = { + cookBookRef: "125" +} + +problemList[NodeType.ExportAssignment] = { + cookBookRef: "126" +} + +problemList[NodeType.ImportAssignment] = { + cookBookRef: "121" +} + +problemList[NodeType.ObjectRuntimeCheck] = { + cookBookRef: "105" +} + +problemList[NodeType.GenericCallNoTypeArgs] = { + printInRelaxMode: false, + cookBookRef: "34" +} + +problemList[NodeType.BigIntType] = { + cookBookRef: "10" +} + +problemList[NodeType.BigIntLiteral] = { + cookBookRef: "10" +} + +problemList[NodeType.StringLiteralType] = { + cookBookRef: "11" +} + +problemList[NodeType.InterfaceOptionalProp] = { + cookBookRef: "33" +} + +problemList[NodeType.ParameterProperties] = { + printInRelaxMode: false, + cookBookRef: "25" +} + +problemList[NodeType.GenericArrayType] = { + printInRelaxMode: false, + cookBookRef: "12" +} + +problemList[NodeType.InstanceofUnsupported] = { + cookBookRef: "65" +} + diff --git a/linter/src/TestRunner.ts b/linter/src/TestRunner.ts new file mode 100644 index 000000000..0d9c43923 --- /dev/null +++ b/linter/src/TestRunner.ts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TypeScriptLinter } from "./TypeScriptLinter"; +import { lint } from "./LinterRunner"; +import { parseCommandLine } from "./CommandLineParser"; +import * as fs from "node:fs"; + +const TS_EXT = ".ts" +const TSX_EXT = ".tsx" +const JSON_EXT = ".json" +const STRICT_EXT = ".strict"; +const RELAX_EXT = ".relax"; +const TEST_DIR = "test"; + +const TAB = " "; + +interface TestNodeInfo { + line: number, + column: number, + problem: string +} + +function runTests(): number { + let hasComparisonFailures = false; + + // Set the IDE mode manually to enable storing information + // about found bad nodes and also disable the log output. + TypeScriptLinter.IDE_mode = true; + + // Get tests from test directory + let testFiles: string[] = fs.readdirSync(TEST_DIR).filter(x => x.trimEnd().endsWith(TS_EXT) || x.trimEnd().endsWith(TSX_EXT)); + + if (!testFiles || testFiles.length == 0) { + console.log("No tests to run!"); + process.exit(0); + } + + let passed = 0, failed = 0; + + // Run each test in Strict and Relax mode: + for (let testFile of testFiles) { + let result = runTest(testFile, false); + if (result) failed++; + else passed++; + hasComparisonFailures ||= result; + + result = runTest(testFile, true); + if (result) failed++; + else passed++; + hasComparisonFailures ||= result; + } + + console.log(`\nSUMMARY:`); + console.log(`${TAB}${passed} passed`); + console.log(`${TAB}${failed} failed`); + + /*console.log(`\nSUMMARY:`); + if (passed > 0) + console.log(`${TAB}${passed} passed`); + if (failed > 0) + console.log(`${TAB}${failed} failed`); +*/ + process.exit(hasComparisonFailures ? -1 : 0); +} + +function runTest(testFile: string, strictMode: boolean): boolean { + let testFailed = false; + + console.log(`Running test ${testFile} (${strictMode ? "Strict" : "Relax"} mode)`); + + // Clear node info collection from the previous test run. + TypeScriptLinter.badNodeInfos = []; + + // Configure test parameters and run linter. + let args: string[] = [ TEST_DIR + '/' + testFile ]; + if (strictMode) args.push("--strict"); + lint(parseCommandLine(args)); + + let resultExt = (strictMode ? STRICT_EXT : RELAX_EXT) + JSON_EXT; + let testResultFileName = testFile + resultExt; + + // Get list of bad nodes from the current run. + let resultNodes: TestNodeInfo[] = TypeScriptLinter.badNodeInfos.map(x => ({ line: x.line, column: x.column, problem: x.problem })); + + // Read file with expected test result. + let expectedResult: { nodes: TestNodeInfo[] }; + try { + let expectedResultFile = fs.readFileSync(TEST_DIR + '/' + testResultFileName).toString(); + expectedResult = JSON.parse(expectedResultFile); + + if (!expectedResult || !expectedResult.nodes || expectedResult.nodes.length !== resultNodes.length) { + testFailed = true; + } else { + // Compare expected and actual results. + for (let i = 0; i < resultNodes.length; i++) { + if (resultNodes[i].line !== expectedResult.nodes[i].line + || resultNodes[i].column !== expectedResult.nodes[i].column + || resultNodes[i].problem !== expectedResult.nodes[i].problem) { + testFailed = true; + break; + } + } + } + + if (testFailed) { + console.log(`${TAB}Test failed. Expected and actual results differ.`); + } + } catch (error) { + testFailed = true; + console.log(`${TAB}Test failed. ${error.message ?? error}`); + } + + // Write file with actual test results. + let actualResultsDir = TEST_DIR + "/results"; + if (!fs.existsSync(actualResultsDir)) { + fs.mkdirSync(actualResultsDir); + } + let actualResultJSON = JSON.stringify({ nodes: resultNodes }, null, 4); + fs.writeFileSync(actualResultsDir + '/' + testFile + resultExt, actualResultJSON); + + return testFailed; +} + +runTests(); \ No newline at end of file diff --git a/linter/src/TypeScriptLinter.ts b/linter/src/TypeScriptLinter.ts new file mode 100644 index 000000000..1e1c4d106 --- /dev/null +++ b/linter/src/TypeScriptLinter.ts @@ -0,0 +1,1512 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; +import * as Utils from "./Utils"; +import { NodeType, TsProblemInfo, problemList } from "./Problems"; +import { cookBookMsg, cookBookTag } from "./CookBookMsg"; + +class BadNodeInfo { + line: number; + column: number; + start: number; + end: number; + type: string; + problem: string; + suggest: string; + rule: string; +} + + +export class TypeScriptLinter { + static IDE_mode: boolean = false; + static STRICT_mode: boolean = false; + static TSC_Errors: boolean = false; + static nodeCntr = 0; + static nodeCounters: number[] = []; + static lineCounters: number[] = []; + static printInRelaxModeFlags: boolean[] = []; // Set flag to 'false' only for features that should NOT be printed in Relax mode! + static nodeDescription: string[] = []; + static lineNumbersString: string = ""; + static lineNumbersStringPosCntr: number = 0; + static specificNodeLineNumbers: string = ""; + static specificNodeLineNumbersPosCntr: number = 0; + static commonLineCounter = 0; + // static unionTNull = 0; // It's now a part of STS language --> not a problem any more. + // static unionTAny = 0; + // static unionTUndefined = 0; + static objLiteralNotParameter = 0; + + // The SyntaxKind enum defines additional elements at the end of the enum + // that serve as markers (FirstX/LastX). Those elements are initialized + // with indices of the previously defined elements. As result, the enum + // may return incorrect name for a certain kind index (e.g. 'FirstStatement' + // instead of 'VariableStatement'). + // The following code creates a map with correct syntax kind names. + // It can be used when need to print name of syntax kind of certain + // AST node in diagnostic messages. + private static tsSyntaxKindNames: string[]; + static { + let newArray: string[] = []; + let keys = Object.keys(ts.SyntaxKind); + let values = Object.values(ts.SyntaxKind); + + for(let i = 0; i < values.length; i++) { + let val = values[i]; + let kindNum = typeof(val) === 'string' ? parseInt(val) : val; + if (kindNum && !newArray[kindNum]) { + newArray[kindNum] = keys[i]; + } + } + + TypeScriptLinter.tsSyntaxKindNames = newArray; + } + + static { + for (let i = 0; i < NodeType.LAST_NODE_TYPE; i++) { + TypeScriptLinter.nodeCounters[i] = 0; + TypeScriptLinter.lineCounters[i] = 0; + TypeScriptLinter.printInRelaxModeFlags[i] = true; + } + } + + static { + // Set the feature descriptions (for the output). + TypeScriptLinter.nodeDescription[NodeType.AnyType] = "'Any' type nodes "; + TypeScriptLinter.nodeDescription[NodeType.SymbolType] = "'Symbol' type nodes "; + TypeScriptLinter.nodeDescription[NodeType.UnionType] = "Union type nodes "; + TypeScriptLinter.nodeDescription[NodeType.TupleType] = "Tuple type nodes "; + TypeScriptLinter.nodeDescription[NodeType.ObjectLiteralNoContextType] = "Object literals with no context Class type "; + TypeScriptLinter.nodeDescription[NodeType.ArrayLiteralNoContextType] = "Array literals with no context Array type "; + TypeScriptLinter.nodeDescription[NodeType.ComputedPropertyName] = "Computed property nodes "; + TypeScriptLinter.nodeDescription[NodeType.LiteralAsPropertyName] = "String or integer literal as property name "; + TypeScriptLinter.nodeDescription[NodeType.TypeOfExpression] = "'typeof' operations "; + TypeScriptLinter.nodeDescription[NodeType.TupleLiteral] = "tuple literals "; + TypeScriptLinter.nodeDescription[NodeType.UnionLiteral] = "union type literals "; + TypeScriptLinter.nodeDescription[NodeType.RegexLiteral] = "regex literals "; + TypeScriptLinter.nodeDescription[NodeType.IsOperator] = "'is' operations "; + TypeScriptLinter.nodeDescription[NodeType.DestructuringParameter] = "destructuring parameters "; + TypeScriptLinter.nodeDescription[NodeType.YieldExpression] = "'yield' operations "; + TypeScriptLinter.nodeDescription[NodeType.InterfaceOrEnumMerging] = "merging interfaces or enums "; + TypeScriptLinter.nodeDescription[NodeType.InterfaceExtendsClass] = "interfaces inherited from classes "; + TypeScriptLinter.nodeDescription[NodeType.IndexMember] = "index members "; + TypeScriptLinter.nodeDescription[NodeType.WithStatement] = "'with' statements "; + TypeScriptLinter.nodeDescription[NodeType.ThrowStatement] = "'throw' statements "; + TypeScriptLinter.nodeDescription[NodeType.IndexedAccessType] = "Indexed access type nodes "; + TypeScriptLinter.nodeDescription[NodeType.UndefinedType] = "'undef' type nodes "; + TypeScriptLinter.nodeDescription[NodeType.UnknownType] = "'unknown' type nodes "; + TypeScriptLinter.nodeDescription[NodeType.ForInStatement] = "'For-In' statements "; + TypeScriptLinter.nodeDescription[NodeType.InOperator] = "'in' operators "; + TypeScriptLinter.nodeDescription[NodeType.SpreadOperator] = "'spread' operations "; + TypeScriptLinter.nodeDescription[NodeType.KeyOfOperator] = "'keyof' operations "; + TypeScriptLinter.nodeDescription[NodeType.ImportFromPath] = "imports from path nodes "; + + TypeScriptLinter.nodeDescription[NodeType.FunctionExpression] = "function expression nodes "; + TypeScriptLinter.nodeDescription[NodeType.TypeParameterWithDefaultValue] = "type parameters with default value "; + TypeScriptLinter.nodeDescription[NodeType.IntersectionType] = "intersection types and type literals "; + TypeScriptLinter.nodeDescription[NodeType.ObjectTypeLiteral] = "Object type literals "; + TypeScriptLinter.nodeDescription[NodeType.LogicalWithNonBoolean] = "'&&' or '||' with non-'boolean' operand "; + TypeScriptLinter.nodeDescription[NodeType.AddWithWrongType] = "binary '+' with wrong operand "; + TypeScriptLinter.nodeDescription[NodeType.BitOpWithWrongType] = "bit operation with wrong operand "; + TypeScriptLinter.nodeDescription[NodeType.CommaOperator] = "comma operator "; + TypeScriptLinter.nodeDescription[NodeType.TopLevelStmt] = "statement at top level "; + + TypeScriptLinter.nodeDescription[NodeType.IfWithNonBoolean] = "'If' with non-'boolean' condition "; + TypeScriptLinter.nodeDescription[NodeType.DoWithNonBoolean] = "'Do' with non-'boolean' condition "; + TypeScriptLinter.nodeDescription[NodeType.WhileWithNonBoolean] = "'While' with non-'boolean' condition "; + TypeScriptLinter.nodeDescription[NodeType.FuncWithoutReturnType] = "Functions without return type "; + TypeScriptLinter.nodeDescription[NodeType.ArrowFunctionWithOmittedTypes] = "Arrow functions with omitted types "; + TypeScriptLinter.nodeDescription[NodeType.LambdaWithTypeParameters] = "Lambda function with type parameters "; + TypeScriptLinter.nodeDescription[NodeType.ClassExpression] = "Class expression nodes "; + TypeScriptLinter.nodeDescription[NodeType.DestructuringAssignment] = "Destructuring assignments "; + TypeScriptLinter.nodeDescription[NodeType.DestructuringDeclaration] = "Destructuring variable declarations "; + + TypeScriptLinter.nodeDescription[NodeType.ForOfNonArray] = "'For-of' statemens for non-array object "; + TypeScriptLinter.nodeDescription[NodeType.VarDeclaration] = "'var' declarations "; + TypeScriptLinter.nodeDescription[NodeType.CatchWithUnsupportedType] = "'catch' with unsuported type "; + + TypeScriptLinter.nodeDescription[NodeType.DeleteOperator] = "'delete' operators "; + TypeScriptLinter.nodeDescription[NodeType.DeclWithDuplicateName] = "Declarations with duplicate name "; + TypeScriptLinter.nodeDescription[NodeType.FuncOptionalParams] = "Optional parameters in function "; + + TypeScriptLinter.nodeDescription[NodeType.UnaryArithmNotNumber] = "Unary arithmetics with not-numeric values "; + TypeScriptLinter.nodeDescription[NodeType.LogNotWithNotBool] = "Logical not with not-boolean values "; + TypeScriptLinter.nodeDescription[NodeType.ConstructorType] = "Constructor type nodes "; + TypeScriptLinter.nodeDescription[NodeType.CallSignature] = "Call signatures "; + TypeScriptLinter.nodeDescription[NodeType.TemplateLiteral] = "Template literals "; + TypeScriptLinter.nodeDescription[NodeType.TypeAssertion] = "Type Assertion expressions "; + TypeScriptLinter.nodeDescription[NodeType.FunctionOverload] = "Function overload in TS style "; + TypeScriptLinter.nodeDescription[NodeType.ConstructorOverload] = "Constructor overload in TS style "; + TypeScriptLinter.nodeDescription[NodeType.PrivateIdentifier] = "Private identifiers (with '#' prefix) "; + TypeScriptLinter.nodeDescription[NodeType.LocalFunction] = "Local function declarations "; + TypeScriptLinter.nodeDescription[NodeType.SwitchSelectorInvalidType] = "Switch selectors with invalid type "; + TypeScriptLinter.nodeDescription[NodeType.CaseExpressionNonConst] = "Non-constant Case expressions "; + TypeScriptLinter.nodeDescription[NodeType.ConditionalType] = "Conditional type "; + TypeScriptLinter.nodeDescription[NodeType.MappedType] = "Mapped types "; + TypeScriptLinter.nodeDescription[NodeType.NamespaceAsObject] = "Namespaces used as objects "; + TypeScriptLinter.nodeDescription[NodeType.NonDeclarationInNamespace] = "Non-declaration statements in namespaces "; + TypeScriptLinter.nodeDescription[NodeType.GeneratorFunction] = "Generator functions "; + TypeScriptLinter.nodeDescription[NodeType.FunctionContainsThis] = "Functions containing 'this' "; + TypeScriptLinter.nodeDescription[NodeType.PropertyAccessByIndex] = "property access by index "; + TypeScriptLinter.nodeDescription[NodeType.JsxElement] = "JSX Elements "; + TypeScriptLinter.nodeDescription[NodeType.EnumMemberWithInitializer] = "Enum members with initializer "; + + TypeScriptLinter.nodeDescription[NodeType.ImplementsClass] = "'implements' a class "; + TypeScriptLinter.nodeDescription[NodeType.MultipleStaticBlocks] = "Multiple static blocks "; + //TypeScriptLinter.nodeDescription[NodeType.Decorators] = "Decorators "; // It's not a problem and counted temporary just to have statistic of decorators use. + TypeScriptLinter.nodeDescription[NodeType.ThisType] = "'this' type "; + TypeScriptLinter.nodeDescription[NodeType.InferType] = "Infer type "; + TypeScriptLinter.nodeDescription[NodeType.SpreadAssignment] = "Spread assignment "; + TypeScriptLinter.nodeDescription[NodeType.IntefaceExtendDifProps] = "Extends same properties with diff. types "; + TypeScriptLinter.nodeDescription[NodeType.DynamicTypeCheck] = "Dynamic type check "; + + TypeScriptLinter.nodeDescription[NodeType.TypeOnlyImport] = "Type-only imports "; + TypeScriptLinter.nodeDescription[NodeType.TypeOnlyExport] = "Type-only exports "; + TypeScriptLinter.nodeDescription[NodeType.DefaultImport] = "Default import declarations "; + TypeScriptLinter.nodeDescription[NodeType.DefaultExport] = "Default export declarations "; + TypeScriptLinter.nodeDescription[NodeType.ExportRenaming] = "Renaming in export declarations "; + TypeScriptLinter.nodeDescription[NodeType.ExportListDeclaration] = "Export list declarations "; + TypeScriptLinter.nodeDescription[NodeType.ReExporting] = "Re-exporting declarations "; + TypeScriptLinter.nodeDescription[NodeType.ExportAssignment] = "Export assignments (export = ..) "; + TypeScriptLinter.nodeDescription[NodeType.ImportAssignment] = "Import assignments (import = ..) "; + + TypeScriptLinter.nodeDescription[NodeType.ObjectRuntimeCheck] = "Object runtime checks "; + TypeScriptLinter.nodeDescription[NodeType.GenericCallNoTypeArgs] = "Generic calls without specifying type args "; + + TypeScriptLinter.nodeDescription[NodeType.BigIntType] = "'bigint' type "; + TypeScriptLinter.nodeDescription[NodeType.BigIntLiteral] = "bigint literal "; + TypeScriptLinter.nodeDescription[NodeType.StringLiteralType] = "string literal type "; + TypeScriptLinter.nodeDescription[NodeType.InterfaceOptionalProp] = "Interface optional property "; + TypeScriptLinter.nodeDescription[NodeType.ParameterProperties] = "Parameter properties in constructor "; + TypeScriptLinter.nodeDescription[NodeType.InstanceofUnsupported] = "Left-hand side of 'instanceof' is wrong "; + TypeScriptLinter.nodeDescription[NodeType.GenericArrayType] = "'Array' type "; + } + + static { + // Specify features that should NOT be counted and printed in Relax mode. + TypeScriptLinter.printInRelaxModeFlags[NodeType.ObjectLiteralNoContextType] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ArrayLiteralNoContextType] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.FunctionExpression] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.TypeParameterWithDefaultValue] = false; + + TypeScriptLinter.printInRelaxModeFlags[NodeType.IfWithNonBoolean] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.DoWithNonBoolean] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.WhileWithNonBoolean] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.FuncWithoutReturnType] = false; + + TypeScriptLinter.printInRelaxModeFlags[NodeType.ArrowFunctionWithOmittedTypes] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ClassExpression] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.DestructuringAssignment] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.DestructuringDeclaration] = false; + + TypeScriptLinter.printInRelaxModeFlags[NodeType.ForOfNonArray] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.VarDeclaration] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.CatchWithUnsupportedType] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.PrivateIdentifier] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.LocalFunction] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.TemplateLiteral] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ThrowStatement] = false; + + TypeScriptLinter.printInRelaxModeFlags[NodeType.TypeOnlyImport] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.TypeOnlyExport] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.DefaultImport] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.DefaultExport] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ExportRenaming] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ExportListDeclaration] = false; + + TypeScriptLinter.printInRelaxModeFlags[NodeType.GenericCallNoTypeArgs] = false; + TypeScriptLinter.printInRelaxModeFlags[NodeType.ParameterProperties] = false; + } + + static badNodeInfos: BadNodeInfo[] = []; + + static tsTypeChecker: ts.TypeChecker; + + currentLine: number; + staticBlocks: Set; + decorators: Map; + + constructor(private tsSourceFile: ts.SourceFile, private tsProgram: ts.Program) { + TypeScriptLinter.tsTypeChecker = tsProgram.getTypeChecker(); + this.currentLine = 0; + this.staticBlocks = new Set(); + this.decorators = new Map(); + } + + public incrementCounters(node: ts.Node, nodeType: number) { + TypeScriptLinter.nodeCounters[nodeType]++; + + // TSC counts lines and columns from zero + let { line, character } = this.tsSourceFile.getLineAndCharacterOfPosition(node.getStart()); + ++line; + ++character; + + if (TypeScriptLinter.STRICT_mode || TypeScriptLinter.printInRelaxModeFlags[nodeType]) { + if(!TypeScriptLinter.IDE_mode) { + console.log(`Warning: ${this.tsSourceFile.fileName}(${line},${character}): ${ TypeScriptLinter.nodeDescription[nodeType] ? TypeScriptLinter.nodeDescription[nodeType].trim() : TypeScriptLinter.tsSyntaxKindNames[node.kind] }`) + if(problemList[nodeType] && problemList[nodeType].suggestion) { + console.log("\tSuggestion: " + problemList[nodeType].suggestion + " CookBook ref. #" + problemList[nodeType].cookBookRef); + } + } + else { + let cookBookMsgNum = problemList[nodeType] ? Number(problemList[nodeType].cookBookRef) : 0; + let badNodeInfo: BadNodeInfo = { + line: line, + column: character, + start: node.getStart(), + end: node.getEnd(), + type: TypeScriptLinter.tsSyntaxKindNames[node.kind], + problem: NodeType[nodeType], + //suggest: problemList[nodeType] ? problemList[nodeType].suggestion + "\n\t CookBook Ref. #" + problemList[nodeType].cookBookRef : "" + suggest: cookBookMsgNum > 0 ? cookBookMsg[ cookBookMsgNum ] : "", + rule: (cookBookMsgNum > 0 && cookBookTag[ cookBookMsgNum ] !== "") ? cookBookTag[ cookBookMsgNum ] : + ( TypeScriptLinter.nodeDescription[nodeType] ? TypeScriptLinter.nodeDescription[nodeType].trim() : + TypeScriptLinter.tsSyntaxKindNames[node.kind] ) + }; + + TypeScriptLinter.badNodeInfos.push(badNodeInfo); + } + } + + TypeScriptLinter.lineCounters[nodeType] ++ + + if(line != this.currentLine) { + this.currentLine = line; + TypeScriptLinter.commonLineCounter ++ + TypeScriptLinter.lineNumbersString += "" + String(line) + ", "; + TypeScriptLinter.lineNumbersStringPosCntr ++; + if((TypeScriptLinter.lineNumbersStringPosCntr % 20) === 0 ) + TypeScriptLinter.lineNumbersString += "\n\t\t " + } + + if( node.kind === ts.SyntaxKind.UnionType) { + TypeScriptLinter.specificNodeLineNumbers +="" + String(line) + ", "; + TypeScriptLinter.specificNodeLineNumbersPosCntr ++; + if((TypeScriptLinter.specificNodeLineNumbersPosCntr % 20) === 0 ) + TypeScriptLinter.specificNodeLineNumbers += "\n\t\t " + } + } + + public CountTSNodes(srcFile: ts.SourceFile) { + let self = this; + + visitTSNode(srcFile); + + function visitTSNode(node: ts.Node) { + if (node == null || node.kind == null) return; + + // check for top-level statements + if(Utils.isStatementKindNode(node) && (node.kind != ts.SyntaxKind.VariableStatement) ) { + if( node.parent && node.parent.kind === ts.SyntaxKind.SourceFile) + self.incrementCounters(node, NodeType.TopLevelStmt); + } + + switch (node.kind) { + // if( node.kind is TriviaSyntaxKind) break; + //case ts.SyntaxKind.PunctuationSyntaxKind: + //case ts.SyntaxKind.KeywordSyntaxKind: + //case ts.SyntaxKind.ModifierSyntaxKind: + //case ts.SyntaxKind.KeywordTypeSyntaxKind: + //case ts.SyntaxKind.TypeNodeSyntaxKind: + //case ts.SyntaxKind.TokenSyntaxKind: + //case ts.SyntaxKind.JsxTokenSyntaxKind: + //case ts.SyntaxKind.JsxTokenSyntaxKind: + // break; + + case ts.SyntaxKind.OpenBraceToken: + case ts.SyntaxKind.CloseBraceToken: + case ts.SyntaxKind.OpenParenToken: + case ts.SyntaxKind.CloseParenToken: + case ts.SyntaxKind.OpenBracketToken: + case ts.SyntaxKind.CloseBracketToken: + case ts.SyntaxKind.DotToken: + case ts.SyntaxKind.DotDotDotToken: + case ts.SyntaxKind.SemicolonToken: + case ts.SyntaxKind.CommaToken: + case ts.SyntaxKind.QuestionDotToken: + case ts.SyntaxKind.LessThanToken: + case ts.SyntaxKind.LessThanSlashToken: + case ts.SyntaxKind.GreaterThanToken: + case ts.SyntaxKind.LessThanEqualsToken: + case ts.SyntaxKind.GreaterThanEqualsToken: + case ts.SyntaxKind.EqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsToken: + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + case ts.SyntaxKind.EqualsGreaterThanToken: + case ts.SyntaxKind.PlusToken: + case ts.SyntaxKind.MinusToken: + case ts.SyntaxKind.AsteriskToken: + case ts.SyntaxKind.AsteriskAsteriskToken: + case ts.SyntaxKind.SlashToken: + case ts.SyntaxKind.PercentToken: + case ts.SyntaxKind.PlusPlusToken: + case ts.SyntaxKind.MinusMinusToken: + case ts.SyntaxKind.LessThanLessThanToken: + case ts.SyntaxKind.GreaterThanGreaterThanToken: + case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case ts.SyntaxKind.AmpersandToken: + case ts.SyntaxKind.BarToken: + case ts.SyntaxKind.CaretToken: + case ts.SyntaxKind.ExclamationToken: + case ts.SyntaxKind.TildeToken: + case ts.SyntaxKind.AmpersandAmpersandToken: + case ts.SyntaxKind.BarBarToken: + case ts.SyntaxKind.QuestionQuestionToken: + case ts.SyntaxKind.QuestionToken: + case ts.SyntaxKind.ColonToken: + case ts.SyntaxKind.AtToken: + case ts.SyntaxKind.BacktickToken: + case ts.SyntaxKind.HashToken: + case ts.SyntaxKind.EqualsToken: + case ts.SyntaxKind.PlusEqualsToken: + case ts.SyntaxKind.MinusEqualsToken: + case ts.SyntaxKind.AsteriskEqualsToken: + case ts.SyntaxKind.AsteriskAsteriskEqualsToken: + case ts.SyntaxKind.SlashEqualsToken: + case ts.SyntaxKind.PercentEqualsToken: + case ts.SyntaxKind.LessThanLessThanEqualsToken: + case ts.SyntaxKind.GreaterThanGreaterThanEqualsToken: + case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case ts.SyntaxKind.AmpersandEqualsToken: + case ts.SyntaxKind.BarEqualsToken: + case ts.SyntaxKind.CaretEqualsToken: + case ts.SyntaxKind.Unknown: + case ts.SyntaxKind.EndOfFileToken: + case ts.SyntaxKind.SingleLineCommentTrivia: + case ts.SyntaxKind.MultiLineCommentTrivia: + case ts.SyntaxKind.NewLineTrivia: + case ts.SyntaxKind.WhitespaceTrivia: + // We detect and preserve #! on the first line + case ts.SyntaxKind.ShebangTrivia: + // We detect and provide better error recovery when we encounter a git merge marker. This + // allows us to edit files with git-conflict markers in them in a much more pleasant manner. + case ts.SyntaxKind.ConflictMarkerTrivia: + // We don't want to increase counters for these tokens. + return; + + /// Problem syntax kinds start here + // + case ts.SyntaxKind.AnyKeyword: + self.incrementCounters(node, NodeType.AnyType); + break; + + case ts.SyntaxKind.BigIntKeyword: + self.incrementCounters(node, NodeType.BigIntType); + break; + + case ts.SyntaxKind.BigIntLiteral: + self.incrementCounters(node, NodeType.BigIntLiteral); + break; + + case ts.SyntaxKind.SymbolKeyword: + self.incrementCounters(node, NodeType.SymbolType); + break; + + case ts.SyntaxKind.UnionType: + // 'Type | null' now is a part of STS language. All other cases of union type should be counted as a problem. + let tsUT = node as ts.UnionTypeNode; + let uTypes = tsUT.types; + + if (uTypes.length !== 2 || (!Utils.isNullType(uTypes[0]) && !Utils.isNullType(uTypes[1]))) + self.incrementCounters(node, NodeType.UnionType); + + break; + + case ts.SyntaxKind.ThisType: + self.incrementCounters(node, NodeType.ThisType); + break; + + case ts.SyntaxKind.InferType: + self.incrementCounters(node, NodeType.InferType); + break; + + case ts.SyntaxKind.TupleType: + self.incrementCounters(node, NodeType.TupleType); + break; + + case ts.SyntaxKind.ObjectLiteralExpression: + let tsObjectLiteralExpr = node as ts.ObjectLiteralExpression; + + // If object literal is a part of destructuring assignment, then + // don't process it further. + if (Utils.isDestructuringAssignmentLHS(tsObjectLiteralExpr)) + break; + + let tsObjectLiteralContextType = TypeScriptLinter.tsTypeChecker.getContextualType(tsObjectLiteralExpr); + if (!(tsObjectLiteralContextType && tsObjectLiteralContextType.isClass())) + self.incrementCounters(node, NodeType.ObjectLiteralNoContextType); + + if (node.parent.kind !== ts.SyntaxKind.CallExpression) { + TypeScriptLinter.objLiteralNotParameter++; + } + + break; + + case ts.SyntaxKind.ComputedPropertyName: + self.incrementCounters(node, NodeType.ComputedPropertyName); + break; + + case ts.SyntaxKind.TypeOfExpression: + self.incrementCounters(node, NodeType.TypeOfExpression); + break; + + case ts.SyntaxKind.DeleteExpression: + self.incrementCounters(node, NodeType.DeleteOperator); + + case ts.SyntaxKind.ArrayLiteralExpression: + // If array literal is a part of destructuring assignment, then + // don't process it further. + if (Utils.isDestructuringAssignmentLHS(node as ts.ArrayLiteralExpression)) + break; + + let arrayLitNode = node as ts.ArrayLiteralExpression; + //let literalType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(arrayLitNode); + + // check element types + if (ts.isUnionTypeNode(arrayLitNode)) { + self.incrementCounters(node, NodeType.TupleLiteral); + } + + let noContextTypeForArrayLiteral = true; + let tsArrayLiteralCtxType = TypeScriptLinter.tsTypeChecker.getContextualType(arrayLitNode); + if (tsArrayLiteralCtxType) { + let tsArrayLiteralCtxTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(tsArrayLiteralCtxType, undefined, ts.NodeBuilderFlags.None); + if (tsArrayLiteralCtxTypeNode && Utils.isArrayNotTupleType(tsArrayLiteralCtxTypeNode)) { + noContextTypeForArrayLiteral = false; + } + } + + if (noContextTypeForArrayLiteral) + self.incrementCounters(node, NodeType.ArrayLiteralNoContextType); + + break; + + case ts.SyntaxKind.RegularExpressionLiteral: + self.incrementCounters(node, NodeType.RegexLiteral); + break; + + case ts.SyntaxKind.TypePredicate: + self.incrementCounters(node, NodeType.IsOperator); + break; + + case ts.SyntaxKind.Parameter: + let tsParam = node as ts.ParameterDeclaration; + if (ts.isArrayBindingPattern(tsParam.name) || ts.isObjectBindingPattern(tsParam.name)) + self.incrementCounters(node, NodeType.DestructuringParameter); + + let tsParamMods = ts.getModifiers(tsParam); + if (Utils.hasModifier(tsParamMods, ts.SyntaxKind.PublicKeyword) || + Utils.hasModifier(tsParamMods, ts.SyntaxKind.ProtectedKeyword) || + Utils.hasModifier(tsParamMods, ts.SyntaxKind.PrivateKeyword)) + self.incrementCounters(node, NodeType.ParameterProperties); + + break; + + case ts.SyntaxKind.YieldExpression: + self.incrementCounters(node, NodeType.YieldExpression); + break; + + case ts.SyntaxKind.EnumDeclaration: + let enumNode = node as ts.EnumDeclaration; + const enumSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(enumNode.name); + if (enumSymbol) { + const enumDecls = enumSymbol.getDeclarations(); + if (enumDecls) { + // Since type checker merges all declarations with the same name + // into one symbol, we need to check that there's more than one + // enum declaration related to that specific symbol. + // See 'countDeclarationsWithDuplicateName' method for details. + let enumDeclCount = 0; + for (const decl of enumDecls) { + if (decl.kind === ts.SyntaxKind.EnumDeclaration) + enumDeclCount++; + } + + if (enumDeclCount > 1) { + self.incrementCounters(node, NodeType.InterfaceOrEnumMerging); + } + } + } + + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(enumNode.name), enumNode); + + break; + + case ts.SyntaxKind.InterfaceDeclaration: + let interfaceNode = node as ts.InterfaceDeclaration; + + const iSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(interfaceNode.name); + if (iSymbol) { + const iDecls = iSymbol.getDeclarations(); + if (iDecls) { + // Since type checker merges all declarations with the same name + // into one symbol, we need to check that there's more than one + // interface declaration related to that specific symbol. + // See 'countDeclarationsWithDuplicateName' method for details. + let iDeclCount = 0; + for (const decl of iDecls) { + if (decl.kind === ts.SyntaxKind.InterfaceDeclaration) + iDeclCount++; + } + + if (iDeclCount > 1) { + self.incrementCounters(node, NodeType.InterfaceOrEnumMerging); + } + } + } + + if (interfaceNode.heritageClauses) { + for (const hClause of interfaceNode.heritageClauses) { + if (hClause.token === ts.SyntaxKind.ExtendsKeyword) { + let prop2type = new Map(); + + for (const tsTypeExpr of hClause.types) { + let tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression); + if (tsExprType.isClass()) { + self.incrementCounters(node, NodeType.InterfaceExtendsClass); + } + else if (tsExprType.isClassOrInterface()) { + let props = tsExprType.getProperties(); + for (let p of props) { + let propName = p.name; + if (p.declarations) { + let decl : ts.Declaration = p.declarations[0]; + if (decl.kind === ts.SyntaxKind.MethodSignature) { + self.countInterfaceExtendsDifferentPropertyTypes(node, prop2type, p.name, (decl as ts.MethodSignature).type); + } + else if (decl.kind === ts.SyntaxKind.MethodDeclaration) { + self.countInterfaceExtendsDifferentPropertyTypes(node, prop2type, p.name, (decl as ts.MethodDeclaration).type); + } + else if (decl.kind === ts.SyntaxKind.PropertyDeclaration) { + self.countInterfaceExtendsDifferentPropertyTypes(node, prop2type, p.name, (decl as ts.PropertyDeclaration).type); + } + else if (decl.kind == ts.SyntaxKind.PropertySignature) { + self.countInterfaceExtendsDifferentPropertyTypes(node, prop2type, p.name, (decl as ts.PropertySignature).type); + } + } + } + } + } + } + } + } + + for (let tsTypeElem of interfaceNode.members) { + if (tsTypeElem.questionToken) { + self.incrementCounters(tsTypeElem, NodeType.InterfaceOptionalProp); + } + } + + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(interfaceNode.name), interfaceNode); + + let tsInterfaceModifiers = ts.getModifiers(interfaceNode); + if (Utils.hasModifier(tsInterfaceModifiers, ts.SyntaxKind.ExportKeyword) && Utils.hasModifier(tsInterfaceModifiers, ts.SyntaxKind.DefaultKeyword)) + self.incrementCounters(node, NodeType.DefaultExport); + + self.countOverloadedFunctions(interfaceNode.members); + + break; + + case ts.SyntaxKind.IndexSignature: + self.incrementCounters(node, NodeType.IndexMember); + break; + + case ts.SyntaxKind.WithStatement: + self.incrementCounters(node, NodeType.WithStatement); + break; + + case ts.SyntaxKind.ThrowStatement: + let throwStmt = node as ts.ThrowStatement; + let throwExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(throwStmt.expression); + + if (!throwExprType.isClassOrInterface() || !self.typeHierarchyHasTypeError(throwExprType) ) + self.incrementCounters(node, NodeType.ThrowStatement); + + break; + + case ts.SyntaxKind.IndexedAccessType: + self.incrementCounters(node, NodeType.IndexedAccessType); + break; + + case ts.SyntaxKind.UndefinedKeyword: + self.incrementCounters(node, NodeType.UndefinedType); + break; + + case ts.SyntaxKind.UnknownKeyword: + self.incrementCounters(node, NodeType.UnknownType); + break; + + case ts.SyntaxKind.ForStatement: + let tsForStmt = node as ts.ForStatement; + + let tsForInit = tsForStmt.initializer; + if (tsForInit && (ts.isArrayLiteralExpression(tsForInit) || ts.isObjectLiteralExpression(tsForInit))) + self.incrementCounters(tsForInit, NodeType.DestructuringAssignment); + + break; + + case ts.SyntaxKind.ForInStatement: + let tsForInStmt = node as ts.ForInStatement; + + let tsForInInit = tsForInStmt.initializer; + if (ts.isArrayLiteralExpression(tsForInInit) || ts.isObjectLiteralExpression(tsForInInit)) + self.incrementCounters(tsForInInit, NodeType.DestructuringAssignment); + + self.incrementCounters(node, NodeType.ForInStatement); + break; + + case ts.SyntaxKind.ForOfStatement: + let tsForOfStmt = node as ts.ForOfStatement; + + let tsForOfInit = tsForOfStmt.initializer; + if (ts.isArrayLiteralExpression(tsForOfInit) || ts.isObjectLiteralExpression(tsForOfInit)) + self.incrementCounters(tsForOfInit, NodeType.DestructuringAssignment); + + let expr = tsForOfStmt.expression; + let exprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(expr); + let exprTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(exprType, undefined, ts.NodeBuilderFlags.None); + if (!(ts.isArrayLiteralExpression(expr) || Utils.isArrayNotTupleType(exprTypeNode))) { + self.incrementCounters(node, NodeType.ForOfNonArray); + } + + break; + + case ts.SyntaxKind.InKeyword: + self.incrementCounters(node, NodeType.InOperator); + break; + + case ts.SyntaxKind.SpreadElement: + self.incrementCounters(node, NodeType.SpreadOperator); + break; + + case ts.SyntaxKind.SpreadAssignment: + self.incrementCounters(node, NodeType.SpreadAssignment); + break; + + case ts.SyntaxKind.TypeOperator: + self.incrementCounters(node, NodeType.KeyOfOperator); + break; + + case ts.SyntaxKind.ImportDeclaration: + let importDeclNode = node as ts.ImportDeclaration; + let expr_ = importDeclNode.moduleSpecifier; + if (expr_.kind === ts.SyntaxKind.StringLiteral) { + if (!importDeclNode.importClause) { + self.incrementCounters(node, NodeType.ImportFromPath); + } + } + break; + + case ts.SyntaxKind.LiteralType: + let tsLiteralType = node as ts.LiteralTypeNode; + if (ts.isStringLiteral(tsLiteralType.literal)) + self.incrementCounters(node, NodeType.StringLiteralType); + + break; + + case ts.SyntaxKind.PropertyAccessExpression: + let propertyAccessNode = node as ts.PropertyAccessExpression; + + if (self.isObjectRuntimeCheck(propertyAccessNode)) + self.incrementCounters(node, NodeType.ObjectRuntimeCheck); + + break; + + case ts.SyntaxKind.PropertyAssignment: + case ts.SyntaxKind.PropertyDeclaration: + let tsPropertyNode = node as (ts.PropertyAssignment | ts.PropertyDeclaration); + if (tsPropertyNode.name && + (tsPropertyNode.name.kind === ts.SyntaxKind.NumericLiteral) || + (tsPropertyNode.name.kind === ts.SyntaxKind.StringLiteral)) + self.incrementCounters(node, NodeType.LiteralAsPropertyName); + + break; + + case ts.SyntaxKind.FunctionExpression: + self.incrementCounters(node, NodeType.FunctionExpression); + + let funcExpr = node as ts.FunctionExpression; + if (funcExpr.typeParameters && funcExpr.typeParameters.length > 0) { + self.incrementCounters(node, NodeType.LambdaWithTypeParameters); + } + + if (funcExpr.asteriskToken) + self.incrementCounters(node, NodeType.GeneratorFunction); + + if (self.functionContainsThis(funcExpr.body)) + self.incrementCounters(node, NodeType.FunctionContainsThis); + + break; + + case ts.SyntaxKind.ArrowFunction: + let arrowFunc = node as ts.ArrowFunction; + + let hasOmittedType = !arrowFunc.type; + for (let param of arrowFunc.parameters) { + hasOmittedType ||= !param.type; + } + + if (hasOmittedType) { + self.incrementCounters(node, NodeType.ArrowFunctionWithOmittedTypes); + } + + if (arrowFunc.typeParameters && arrowFunc.typeParameters.length > 0) { + self.incrementCounters(node, NodeType.LambdaWithTypeParameters); + } + + break; + + case ts.SyntaxKind.ClassExpression: + let tsClassExpr = node as ts.ClassExpression; + self.incrementCounters(node, NodeType.ClassExpression); + self.countOverloadedConstructors(tsClassExpr); + self.countOverloadedFunctions(tsClassExpr.members); + + break; + + case ts.SyntaxKind.TypeParameter: + let typeParameterNode = node as ts.TypeParameterDeclaration; + if (typeParameterNode.default) + self.incrementCounters(node, NodeType.TypeParameterWithDefaultValue); + + break; + + case ts.SyntaxKind.IfStatement: + let tsIfStatement = node as ts.IfStatement; + let tsIfExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsIfStatement.expression); + if (!(tsIfExprType.getFlags() & (ts.TypeFlags.BooleanLike))) + self.incrementCounters(node, NodeType.IfWithNonBoolean); + + self.checkExprForDynamicTypeCheck(tsIfStatement.expression); + + break; + + case ts.SyntaxKind.DoStatement: + let tsDoStatement = node as ts.DoStatement; + let tsDoExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsDoStatement.expression); + if (!(tsDoExprType.getFlags() & (ts.TypeFlags.BooleanLike))) + self.incrementCounters(node, NodeType.DoWithNonBoolean); + + break; + + case ts.SyntaxKind.WhileStatement: + let tsWhileStatement = node as ts.WhileStatement; + let tsWhileExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsWhileStatement.expression); + if (!(tsWhileExprType.getFlags() & (ts.TypeFlags.BooleanLike))) + self.incrementCounters(node, NodeType.WhileWithNonBoolean); + + break; + + case ts.SyntaxKind.FunctionDeclaration: + let tsFunctionDeclaration = node as ts.FunctionDeclaration; + if (!tsFunctionDeclaration.type) + self.incrementCounters(node, NodeType.FuncWithoutReturnType); + + if (tsFunctionDeclaration.name) + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsFunctionDeclaration.name), tsFunctionDeclaration); + + let tsParams: ts.NodeArray = tsFunctionDeclaration.parameters; + for (let tsParam of tsParams) { + if (tsParam.questionToken) + self.incrementCounters(tsParam, NodeType.FuncOptionalParams); + } + + if (tsFunctionDeclaration.body && self.functionContainsThis(tsFunctionDeclaration.body)) { + self.incrementCounters(node, NodeType.FunctionContainsThis); + } + + if (!ts.isSourceFile(tsFunctionDeclaration.parent) && !ts.isModuleBlock(tsFunctionDeclaration.parent)) + self.incrementCounters(tsFunctionDeclaration, NodeType.LocalFunction); + + if (tsFunctionDeclaration.asteriskToken) + self.incrementCounters(node, NodeType.GeneratorFunction); + + let tsFuncModifiers = ts.getModifiers(tsFunctionDeclaration); + if (Utils.hasModifier(tsFuncModifiers, ts.SyntaxKind.ExportKeyword) && Utils.hasModifier(tsFuncModifiers, ts.SyntaxKind.DefaultKeyword)) + self.incrementCounters(node, NodeType.DefaultExport); + + break; + + case ts.SyntaxKind.PrefixUnaryExpression: + let tsUnaryArithm = node as ts.PrefixUnaryExpression; + let tsUnaryOp = tsUnaryArithm.operator; + if (tsUnaryOp === ts.SyntaxKind.PlusToken || tsUnaryOp === ts.SyntaxKind.MinusToken || tsUnaryOp === ts.SyntaxKind.TildeToken) { + let tsOperatndType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsUnaryArithm.operand); + if (!(tsOperatndType.getFlags() & (ts.TypeFlags.NumberLike))) + self.incrementCounters(node, NodeType.UnaryArithmNotNumber); + } + else if (tsUnaryOp === ts.SyntaxKind.ExclamationToken) { + let tsOperatndType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsUnaryArithm.operand); + if (!(tsOperatndType.getFlags() & (ts.TypeFlags.BooleanLike))) + self.incrementCounters(node, NodeType.LogNotWithNotBool); + } + + break; + + case ts.SyntaxKind.BinaryExpression: + let tsBinaryExpr = node as ts.BinaryExpression; + if (Utils.isAssignmentOperator(tsBinaryExpr.operatorToken)) { + if (ts.isObjectLiteralExpression(tsBinaryExpr.left) || ts.isArrayLiteralExpression(tsBinaryExpr.left)) { + self.incrementCounters(node, NodeType.DestructuringAssignment); + } + } + + let leftOperandType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsBinaryExpr.left); + let rightOperandType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsBinaryExpr.right); + + if(tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.BarBarToken) { + + if(!(Utils.isBooleanType(leftOperandType) && Utils.isBooleanType(rightOperandType))) + self.incrementCounters(node, NodeType.LogicalWithNonBoolean); + + } else if(tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.PlusToken) { + + if(Utils.isNumberType(leftOperandType) && Utils.isNumberType(rightOperandType)) { + break; + } + else if(Utils.isStringType(leftOperandType) || Utils.isStringType(rightOperandType) ) { + break; + } else + self.incrementCounters(node, NodeType.AddWithWrongType); + + } else if (tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.AmpersandToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.BarToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.CaretToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.LessThanLessThanToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.GreaterThanGreaterThanToken || + tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken) { + + if(!(Utils.isNumberType(leftOperandType) && Utils.isNumberType(rightOperandType))) + self.incrementCounters(node, NodeType.BitOpWithWrongType); + + } else if(tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.CommaToken) { + + // CommaOpertor is allowed in 'for' statement initalizer and incrementor + let tsExprNode: ts.Node = tsBinaryExpr; + let tsParentNode = tsExprNode.parent; + while (tsParentNode && tsParentNode.kind === ts.SyntaxKind.BinaryExpression ) { + tsExprNode = tsParentNode; + tsParentNode = tsExprNode.parent; + } + if( tsParentNode && tsParentNode.kind === ts.SyntaxKind.ForStatement) { + let tsForNode = tsParentNode as ts.ForStatement; + if( tsExprNode === tsForNode.initializer || tsExprNode === tsForNode.incrementor ) { + break; + } + } + self.incrementCounters(node, NodeType.CommaOperator); + + } + else if (tsBinaryExpr.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword) { + let leftExpr = Utils.unwrapParenthesizedExpression(tsBinaryExpr.left); + let leftSymbol = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(leftExpr); + let leftType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(leftExpr); + // In STS, the left-hand side expression may be of any reference type, otherwise a compile-time error occurs. + // In addition, the left operand in STS cannot be a type. + if (ts.isTypeNode(leftExpr) || !Utils.isReferenceType(leftOperandType) || Utils.isTypeSymbol(leftSymbol)) { + self.incrementCounters(node, NodeType.InstanceofUnsupported); + } + } + + break; + + case ts.SyntaxKind.VariableDeclarationList: + let varDeclFlags = ts.getCombinedNodeFlags(node); + if (!(varDeclFlags & (ts.NodeFlags.Let | ts.NodeFlags.Const))) + self.incrementCounters(node, NodeType.VarDeclaration); + + break; + + case ts.SyntaxKind.VariableDeclaration: + let tsVarDecl = node as ts.VariableDeclaration; + + if (ts.isArrayBindingPattern(tsVarDecl.name) || ts.isObjectBindingPattern(tsVarDecl.name)) + self.incrementCounters(node, NodeType.DestructuringDeclaration); + + // Check variable declaration for duplicate name. + let visitBindingPatternNames = (tsBindingName: ts.BindingName) => { + if (ts.isIdentifier(tsBindingName)) + // The syntax kind of the declaration is defined here by the parent of 'BindingName' node. + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsBindingName), tsBindingName, tsBindingName.parent.kind); + else { + for (const tsBindingElem of tsBindingName.elements) { + if (ts.isOmittedExpression(tsBindingElem)) continue; + + visitBindingPatternNames(tsBindingElem.name) + } + } + } + + visitBindingPatternNames(tsVarDecl.name); + + break; + + case ts.SyntaxKind.IntersectionType: + self.incrementCounters(node, NodeType.IntersectionType); + break; + + case ts.SyntaxKind.TypeLiteral: + self.incrementCounters(node, NodeType.ObjectTypeLiteral); + break; + + case ts.SyntaxKind.CatchClause: + let tsCatch = node as ts.CatchClause; + if (tsCatch.variableDeclaration && tsCatch.variableDeclaration.type) { + // In TS catch clause doesn't permit specification of the exception varible type except 'any' or 'unknown'. + // It is not compatible with STS 'catch' where the exception varilab has to be of type 'Exception' or derived from it. + // So each 'catch' which has explicite type for the exception object goes to problems in strict mode. + self.incrementCounters(node, NodeType.CatchWithUnsupportedType); + } + break; + + case ts.SyntaxKind.ClassDeclaration: + let tsClassDecl = node as ts.ClassDeclaration; + if (tsClassDecl.name) { + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsClassDecl.name), tsClassDecl); + } + + self.countClassMembersWithDuplicateName(tsClassDecl); + + if (tsClassDecl.heritageClauses) { + for (const hClause of tsClassDecl.heritageClauses) { + if (hClause && hClause.token === ts.SyntaxKind.ImplementsKeyword) { + for (const tsTypeExpr of hClause.types) { + let tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeExpr.expression); + if (tsExprType.isClass()) + self.incrementCounters(tsTypeExpr, NodeType.ImplementsClass); + } + } + } + } + + let tsClassModifiers = ts.getModifiers(tsClassDecl); + if (Utils.hasModifier(tsClassModifiers, ts.SyntaxKind.ExportKeyword) && Utils.hasModifier(tsClassModifiers, ts.SyntaxKind.DefaultKeyword)) + self.incrementCounters(node, NodeType.DefaultExport); + + self.countOverloadedConstructors(tsClassDecl); + self.countOverloadedFunctions(tsClassDecl.members); + + break; + + case ts.SyntaxKind.ModuleDeclaration: + let tsModuleDecl = node as ts.ModuleDeclaration; + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsModuleDecl.name), tsModuleDecl); + + let tsModuleBody = tsModuleDecl.body; + if (tsModuleBody && ts.isModuleBlock(tsModuleBody)) { + for (const tsModuleStmt of tsModuleBody.statements) { + switch (tsModuleStmt.kind) { + case ts.SyntaxKind.VariableStatement: + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.ClassDeclaration: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.TypeAliasDeclaration: + case ts.SyntaxKind.EnumDeclaration: + case ts.SyntaxKind.ModuleDeclaration: + break; + default: + self.incrementCounters(tsModuleStmt, NodeType.NonDeclarationInNamespace); + break; + } + } + + self.countOverloadedFunctions(tsModuleBody.statements); + } + + break; + + case ts.SyntaxKind.TypeAliasDeclaration: + let tsTypeAlias = node as ts.TypeAliasDeclaration; + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsTypeAlias.name), tsTypeAlias); + break; + + case ts.SyntaxKind.ImportClause: + let tsImportClause = node as ts.ImportClause; + if (tsImportClause.name) + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsImportClause.name), tsImportClause); + + if (tsImportClause.isTypeOnly) + self.incrementCounters(node, NodeType.TypeOnlyImport); + + break; + + case ts.SyntaxKind.ImportSpecifier: + let tsImportSpecifier = node as ts.ImportSpecifier; + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsImportSpecifier.name), tsImportSpecifier); + + if (tsImportSpecifier.propertyName && tsImportSpecifier.propertyName.text === "default") + self.incrementCounters(node, NodeType.DefaultImport); + + if (tsImportSpecifier.isTypeOnly) + self.incrementCounters(node, NodeType.TypeOnlyImport); + + break; + + case ts.SyntaxKind.NamespaceImport: + let tsNamespaceImport = node as ts.NamespaceImport; + self.countDeclarationsWithDuplicateName(TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsNamespaceImport.name), tsNamespaceImport); + break; + + case ts.SyntaxKind.ConstructorType: + case ts.SyntaxKind.ConstructSignature: + self.incrementCounters(node, NodeType.ConstructorType); + break; + + case ts.SyntaxKind.CallSignature: + self.incrementCounters(node, NodeType.CallSignature); + break; + + case ts.SyntaxKind.NoSubstitutionTemplateLiteral: + case ts.SyntaxKind.TemplateExpression: + self.incrementCounters(node, NodeType.TemplateLiteral); + break; + + case ts.SyntaxKind.TypeAssertionExpression: + self.incrementCounters(node, NodeType.TypeAssertion); + break; + + case ts.SyntaxKind.MethodDeclaration: + let tsMethodDecl = node as ts.MethodDeclaration; + if (!tsMethodDecl.type) + self.incrementCounters(node, NodeType.FuncWithoutReturnType); + + if (tsMethodDecl.asteriskToken) + self.incrementCounters(node, NodeType.GeneratorFunction); + + break; + + case ts.SyntaxKind.ClassStaticBlockDeclaration: + if (ts.isClassDeclaration(node.parent)) { + let tsClassDecl = node.parent as ts.ClassDeclaration; + let className: string = ""; + if (tsClassDecl.name) // May be undefined in `export default class { ... }`. + className = tsClassDecl.name.text; + + if (self.staticBlocks.has(className)) { + self.incrementCounters(node, NodeType.MultipleStaticBlocks); + } + else { + self.staticBlocks.add(className); + } + } + + break; + + case ts.SyntaxKind.PrivateIdentifier: + self.incrementCounters(node, NodeType.PrivateIdentifier); + break; + + case ts.SyntaxKind.SwitchStatement: + let tsSwitchStmt = node as ts.SwitchStatement; + + let tsSwitchExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsSwitchStmt.expression); + if (!(tsSwitchExprType.getFlags() & (ts.TypeFlags.NumberLike | ts.TypeFlags.StringLike)) && !Utils.isEnumType(tsSwitchExprType)) { + self.incrementCounters(tsSwitchStmt.expression, NodeType.SwitchSelectorInvalidType) + } + + for (const tsCaseClause of tsSwitchStmt.caseBlock.clauses) { + if (ts.isCaseClause(tsCaseClause)) { + let tsCaseExpr = tsCaseClause.expression; + let tsCaseExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsCaseExpr); + if (!(ts.isNumericLiteral(tsCaseExpr) || ts.isStringLiteralLike(tsCaseExpr) || tsCaseExprType.flags & ts.TypeFlags.EnumLike)) { + self.incrementCounters(tsCaseExpr, NodeType.CaseExpressionNonConst); + } + } + } + + break; + + case ts.SyntaxKind.ConditionalType: + self.incrementCounters(node, NodeType.ConditionalType); + break; + + case ts.SyntaxKind.MappedType: + self.incrementCounters(node, NodeType.MappedType); + break; + + case ts.SyntaxKind.Identifier: + let tsIdentifier = node as ts.Identifier; + let tsIdentSym = TypeScriptLinter.tsTypeChecker.getSymbolAtLocation(tsIdentifier); + if (tsIdentSym && (tsIdentSym.getFlags() & ts.SymbolFlags.Module) !== 0 + && (tsIdentSym.getFlags() & (ts.SymbolFlags.Variable)) === 0 + && !ts.isModuleDeclaration(tsIdentifier.parent)) { + + // If module name is duplicated by another declaration, this increases the possibility + // of finding a lot of false positives. Thus, do not check further in that case. + if (!Utils.symbolHasDuplicateName(tsIdentSym, ts.SyntaxKind.ModuleDeclaration)) { + + // If module name is the right-most name of Property Access chain or Qualified name, + // or it's a separate identifier expression, then module is being referenced as an object. + let tsIdentParent: ts.Node = tsIdentifier; + + while (ts.isPropertyAccessExpression(tsIdentParent.parent) || ts.isQualifiedName(tsIdentParent.parent)) + tsIdentParent = tsIdentParent.parent; + + if ((!ts.isPropertyAccessExpression(tsIdentParent) && !ts.isQualifiedName(tsIdentParent)) + || (ts.isPropertyAccessExpression(tsIdentParent) && tsIdentifier === tsIdentParent.name) + || (ts.isQualifiedName(tsIdentParent) && tsIdentifier === tsIdentParent.right)) + self.incrementCounters(node, NodeType.NamespaceAsObject); + } + } + + if (self.isObjectRuntimeCheck(tsIdentifier)) + self.incrementCounters(node, NodeType.ObjectRuntimeCheck); + + break; + + case ts.SyntaxKind.ElementAccessExpression: + let tsElementAccessExpr = node as ts.ElementAccessExpression; + + let tsElemAccessBaseExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsElementAccessExpr.expression); + let tsElemAccessBaseExprTypeNode = TypeScriptLinter.tsTypeChecker.typeToTypeNode(tsElemAccessBaseExprType, undefined, ts.NodeBuilderFlags.None); + let tsElemAccessExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsElementAccessExpr.argumentExpression); + + if (!(Utils.isArrayNotTupleType(tsElemAccessBaseExprTypeNode) && Utils.isNumberLikeType(tsElemAccessExprType))) { + self.incrementCounters(node, NodeType.PropertyAccessByIndex); + } + + break; + + case ts.SyntaxKind.JsxElement: + case ts.SyntaxKind.JsxSelfClosingElement: + self.incrementCounters(node, NodeType.JsxElement); + break; + + case ts.SyntaxKind.EnumMember: + let tsEnumMember = node as ts.EnumMember; + if (tsEnumMember.initializer) + self.incrementCounters(node, NodeType.EnumMemberWithInitializer); + break; + + case ts.SyntaxKind.ClassStaticBlockDeclaration: + if (ts.isClassDeclaration(node.parent)) { + let tsClassDecl = node.parent as ts.ClassDeclaration; + let className: string = ""; + if (tsClassDecl.name) // May be undefined in `export default class { ... }`. + className = tsClassDecl.name.text; + + if (self.staticBlocks.has(className)) { + self.incrementCounters(node, NodeType.MultipleStaticBlocks); + } + else { + self.staticBlocks.add(className); + } + } + + break; + + case ts.SyntaxKind.Decorator: + let tsDecorator = node as ts.Decorator; + let tsDecoratorName = tsDecorator.getText(); + + let n = self.decorators.get(tsDecoratorName); + if (n) + n++; + else + n = 1; + + self.decorators.set(tsDecoratorName, n); + break; + + case ts.SyntaxKind.ExportDeclaration: + let tsExportDecl = node as ts.ExportDeclaration; + + if (tsExportDecl.isTypeOnly) + self.incrementCounters(node, NodeType.TypeOnlyExport); + + if (tsExportDecl.moduleSpecifier) + self.incrementCounters(node, NodeType.ReExporting); + + break; + + case ts.SyntaxKind.NamedExports: + self.incrementCounters(node, NodeType.ExportListDeclaration); + break; + + case ts.SyntaxKind.ExportSpecifier: + let tsExportSpecifier = node as ts.ExportSpecifier; + + if (tsExportSpecifier.propertyName) + self.incrementCounters(node, NodeType.ExportRenaming); + + if (tsExportSpecifier.isTypeOnly) + self.incrementCounters(node, NodeType.TypeOnlyExport); + + break; + + case ts.SyntaxKind.ExportAssignment: + let tsExportAssignment = node as ts.ExportAssignment; + + if (tsExportAssignment.isExportEquals) + self.incrementCounters(node, NodeType.ExportAssignment); + else + self.incrementCounters(node, NodeType.DefaultExport); + + break; + + case ts.SyntaxKind.ImportEqualsDeclaration: + self.incrementCounters(node, NodeType.ImportAssignment); + break; + + case ts.SyntaxKind.CallExpression: + let tsCallExpr = node as ts.CallExpression; + let tsCallSignature = TypeScriptLinter.tsTypeChecker.getResolvedSignature(tsCallExpr); + if (tsCallSignature) { + let tsSignDecl = tsCallSignature.getDeclaration(); + if (tsSignDecl && tsSignDecl.typeParameters && tsSignDecl.typeParameters.length > 0 && + (!tsCallExpr.typeArguments || tsCallExpr.typeArguments.length !== tsSignDecl.typeParameters.length)) + self.incrementCounters(node, NodeType.GenericCallNoTypeArgs); + } + + break; + + case ts.SyntaxKind.NewExpression: + let tsNewExpr = node as ts.NewExpression; + + let tsNewExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsNewExpr); + if ((tsNewExprType.getFlags() & ts.TypeFlags.Object) !== 0 && ((tsNewExprType as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference) !== 0) { + let tsTargetType = (tsNewExprType as ts.TypeReference).target; + if (tsTargetType.typeParameters && tsTargetType.typeParameters.length > 0 && + (!tsNewExpr.typeArguments || tsNewExpr.typeArguments.length !== tsTargetType.typeParameters.length)) + self.incrementCounters(node, NodeType.GenericCallNoTypeArgs); + } + + if (Utils.isGenericArrayType(TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsNewExpr))) + self.incrementCounters(node, NodeType.GenericArrayType); + + break; + + case ts.SyntaxKind.TypeReference: + let tsTypeRef = node as ts.TypeReferenceNode; + + if (Utils.isGenericArrayType(TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsTypeRef))) + self.incrementCounters(node, NodeType.GenericArrayType); + + break; + + case ts.SyntaxKind.SourceFile: + let tsSrcFile = node as ts.SourceFile; + self.countOverloadedFunctions(tsSrcFile.statements); + break; + + case ts.SyntaxKind.Block: + let tsBlock = node as ts.Block; + self.countOverloadedFunctions(tsBlock.statements); + break; + + default: + break; + } + + // Increase common Node counter. + TypeScriptLinter.nodeCntr++; + + ts.forEachChild(node, visitTSNode); + } + } + + private countInterfaceExtendsDifferentPropertyTypes(node: ts.Node, prop2type : Map, propName: string, type: ts.TypeNode) { + if (type) { + let methodType = type.getText(); + let propType = prop2type.get(propName); + if (!propType) { + prop2type.set(propName, methodType); + } + else if (propType !== methodType) { + this.incrementCounters(node, NodeType.IntefaceExtendDifProps); + } + } + } + + private typeHierarchyHasTypeError(type: ts.Type) : boolean { + let symbol = type.getSymbol(); + if (symbol?.getName() === "Error") { + return true; + } + else { + let baseTypes = type.getBaseTypes(); + if (baseTypes) { + for (let baseType of baseTypes) { + if (this.typeHierarchyHasTypeError(baseType)) + return true; + } + } + } + + return false; + } + + private countDeclarationsWithDuplicateName(symbol: ts.Symbol, tsDeclNode: ts.Node, tsDeclKind?: ts.SyntaxKind): void { + // Sanity check. + if (!symbol) return; + + // If specific declaration kind is provided, check against it. + // Otherwise, use syntax kind of corresponding declaration node. + if (Utils.symbolHasDuplicateName(symbol, tsDeclKind ?? tsDeclNode.kind)) { + this.incrementCounters(tsDeclNode, NodeType.DeclWithDuplicateName); + } + } + + private countClassMembersWithDuplicateName(tsClassDecl: ts.ClassDeclaration): void { + for (const tsCurrentMember of tsClassDecl.members) { + if (!tsCurrentMember.name || !(ts.isIdentifier(tsCurrentMember.name) || ts.isPrivateIdentifier(tsCurrentMember.name))) + continue; + + for (const tsClassMember of tsClassDecl.members) { + if (tsCurrentMember === tsClassMember) continue; + + if (!tsClassMember.name || !(ts.isIdentifier(tsClassMember.name) || ts.isPrivateIdentifier(tsClassMember.name))) + continue; + + if (ts.isIdentifier(tsCurrentMember.name) && ts.isPrivateIdentifier(tsClassMember.name) + && tsCurrentMember.name.text === tsClassMember.name.text.substring(1)) { + this.incrementCounters(tsCurrentMember, NodeType.DeclWithDuplicateName); + break; + } + + if (ts.isPrivateIdentifier(tsCurrentMember.name) && ts.isIdentifier(tsClassMember.name) + && tsCurrentMember.name.text.substring(1) === tsClassMember.name.text) { + this.incrementCounters(tsCurrentMember, NodeType.DeclWithDuplicateName); + break; + } + } + } + } + + private functionContainsThis(tsNode: ts.Node): boolean { + let found = false; + + function visitNode(tsNode: ts.Node) { + // Stop visiting child nodes if finished searching. + if (found) return; + + if (tsNode.kind === ts.SyntaxKind.ThisKeyword) { + found = true; + return; + } + + // Visit children nodes. Skip any local declaration that defines + // its own scope as it needs to be checked separately. + if (!ts.isClassDeclaration(tsNode) && !ts.isClassExpression(tsNode) && !ts.isModuleDeclaration(tsNode) + && !ts.isFunctionDeclaration(tsNode) && !ts.isFunctionExpression(tsNode)) { + + tsNode.forEachChild(visitNode); + } + } + visitNode(tsNode); + + return found; + } + + private checkPropertyAccessForDynamicTypeCheck(tsPropAccess: ts.PropertyAccessExpression) : void { + let childName = tsPropAccess.name.text; + let objType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsPropAccess.expression); + let props = objType.getProperties(); + let found = false; + for (let prop of props) { + if (prop.getName() === childName) { + found = true; + break; + } + } + + if (!found) + this.incrementCounters(tsPropAccess, NodeType.DynamicTypeCheck); + } + + private checkExprForDynamicTypeCheck(tsExpr : ts.Expression) : void { + if (ts.isPropertyAccessExpression(tsExpr)) { + this.checkPropertyAccessForDynamicTypeCheck(tsExpr as ts.PropertyAccessExpression); + } + else if (ts.isPropertyAccessChain(tsExpr)) { + let tsPropAccessChain = tsExpr as ts.PropertyAccessChain; + this.checkPropertyAccessForDynamicTypeCheck(tsPropAccessChain); + this.checkExprForDynamicTypeCheck(tsPropAccessChain.expression); + } + else if (ts.isBinaryExpression(tsExpr)) { + let tsBinExpr = tsExpr as ts.BinaryExpression; + this.checkExprForDynamicTypeCheck(tsBinExpr.left); + this.checkExprForDynamicTypeCheck(tsBinExpr.right); + } + } + + private isObjectRuntimeCheck(tsExpr: ts.Identifier | ts.PropertyAccessExpression): boolean { + // Get parent node of the expression, unwrap enclosing parentheses if needed. + let tsExprParent = tsExpr.parent; + while (ts.isParenthesizedExpression(tsExprParent)) + tsExprParent = tsExprParent.parent; + + // If object reference is not a boolean type and is used + // in a boolean context (if statement, ternary operator, while loop, etc.), + // then this is a object runtime check. + let tsExprType = TypeScriptLinter.tsTypeChecker.getTypeAtLocation(tsExpr); + return (tsExprType && !(tsExprType.getFlags() & ts.TypeFlags.BooleanLike)) && + ((ts.isIfStatement(tsExprParent) && tsExpr === Utils.unwrapParenthesizedExpression(tsExprParent.expression)) || + (ts.isWhileStatement(tsExprParent) && tsExpr === Utils.unwrapParenthesizedExpression(tsExprParent.expression)) || + (ts.isDoStatement(tsExprParent) && tsExpr === Utils.unwrapParenthesizedExpression(tsExprParent.expression)) || + (ts.isForStatement(tsExprParent) && tsExprParent.condition && tsExpr === Utils.unwrapParenthesizedExpression(tsExprParent.condition)) || + (ts.isConditionalExpression(tsExprParent) && tsExpr === Utils.unwrapParenthesizedExpression(tsExprParent.condition)) || + (ts.isBinaryExpression(tsExprParent) && + (tsExprParent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || tsExprParent.operatorToken.kind === ts.SyntaxKind.BarBarToken)) || + (ts.isPrefixUnaryExpression(tsExprParent) && tsExprParent.operator === ts.SyntaxKind.ExclamationToken) + ); + } + + private countOverloadedFunctions(tsStatementsOrDecls: ts.NodeArray): void { + let tsFunctionMap: Map = new Map(); + + for (let tsChildNode of tsStatementsOrDecls) { + if ((ts.isFunctionDeclaration(tsChildNode) || ts.isMethodDeclaration(tsChildNode) || ts.isMethodSignature(tsChildNode)) + && tsChildNode.name && ts.isIdentifier(tsChildNode.name)) { + let tsFunName = tsChildNode.name.text; + if (!tsFunctionMap.has(tsFunName)) { + tsFunctionMap.set(tsFunName, [ tsChildNode ]); + } else { + tsFunctionMap.get(tsFunName).push(tsChildNode); + } + } + } + + for (let tsFunDecls of tsFunctionMap.values()) { + if (tsFunDecls.length > 1) { + for (let tsFunDecl of tsFunDecls) { + this.incrementCounters(tsFunDecl, NodeType.FunctionOverload); + } + } + } + } + + private countOverloadedConstructors(tsClassDecl: ts.ClassLikeDeclaration) { + let tsClassCtors: ts.ClassElement[] = []; + + for (let tsClassElem of tsClassDecl.members) { + if (tsClassElem.kind === ts.SyntaxKind.Constructor) + tsClassCtors.push(tsClassElem); + } + + if (tsClassCtors.length > 1) { + for (let tsClassCtor of tsClassCtors) { + this.incrementCounters(tsClassCtor, NodeType.ConstructorOverload); + } + } + } + + public lint(): any { + this.CountTSNodes(this.tsSourceFile); + return null; + } +} diff --git a/linter/src/Utils.ts b/linter/src/Utils.ts new file mode 100644 index 000000000..386973951 --- /dev/null +++ b/linter/src/Utils.ts @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as ts from "typescript"; + +export function isStatementKindNode(tsNode: ts.Node): boolean { + switch(tsNode.kind) { + case ts.SyntaxKind.Block: + case ts.SyntaxKind.EmptyStatement: + case ts.SyntaxKind.VariableStatement: + case ts.SyntaxKind.ExpressionStatement: + case ts.SyntaxKind.IfStatement: + case ts.SyntaxKind.DoStatement: + case ts.SyntaxKind.WhileStatement: + case ts.SyntaxKind.ForStatement: + case ts.SyntaxKind.ForInStatement: + case ts.SyntaxKind.ForOfStatement: + case ts.SyntaxKind.ContinueStatement: + case ts.SyntaxKind.BreakStatement: + case ts.SyntaxKind.ReturnStatement: + case ts.SyntaxKind.WithStatement: + case ts.SyntaxKind.SwitchStatement: + case ts.SyntaxKind.LabeledStatement: + case ts.SyntaxKind.ThrowStatement: + case ts.SyntaxKind.TryStatement: + case ts.SyntaxKind.DebuggerStatement: + return true; + } + return false; +} + + +export function isAssignmentOperator(tsBinaryOperator: ts.BinaryOperatorToken): boolean { + return tsBinaryOperator.kind >= ts.SyntaxKind.FirstAssignment && tsBinaryOperator.kind <= ts.SyntaxKind.LastAssignment; +} + +export function isArrayNotTupleType(tsType: ts.TypeNode): boolean { + if (tsType && tsType.kind && ts.isArrayTypeNode(tsType)) { + // Check that element type is not a union type to + // filter out tuple types induced by tuple literals. + let tsElemType = unwrapParenthesizedType(tsType.elementType); + return !ts.isUnionTypeNode(tsElemType); + } + + return false; +} + +export function isNumberType(tsType: ts.Type): boolean { + return (tsType.getFlags() & (ts.TypeFlags.NumberLike)) != 0; +} + +export function isBooleanType(tsType: ts.Type): boolean { + return (tsType.getFlags() & (ts.TypeFlags.BooleanLike)) != 0; +} + +export function isStringType(tsType: ts.Type): boolean { + return (tsType.getFlags() & (ts.TypeFlags.StringLike)) != 0; +} + + +export function unwrapParenthesizedType(tsType: ts.TypeNode): ts.TypeNode { + while (ts.isParenthesizedTypeNode(tsType)) { + tsType = tsType.type; + } + + return tsType; +} + +export function findParentIf(asExpr: ts.AsExpression): ts.IfStatement | null { + let node = asExpr.parent; + + while(node) { + if (node.kind === ts.SyntaxKind.IfStatement) { + return node as ts.IfStatement; + } + + node = node.parent; + } + + return null; +} + +export function isDestructuringAssignmentLHS(tsExpr: ts.ArrayLiteralExpression | ts.ObjectLiteralExpression): boolean { + // Check whether given expression is the LHS part of the destructuring + // assignment (or is a nested element of destructuring pattern). + + let tsParent = tsExpr.parent; + let tsCurrentExpr: ts.Node = tsExpr; + while (tsParent) { + if (ts.isBinaryExpression(tsParent) && isAssignmentOperator(tsParent.operatorToken) && tsParent.left === tsCurrentExpr) + return true; + + if ((ts.isForStatement(tsParent) || ts.isForInStatement(tsParent) || ts.isForOfStatement(tsParent)) + && tsParent.initializer && tsParent.initializer === tsCurrentExpr) + return true; + + tsCurrentExpr = tsParent; + tsParent = tsParent.parent; + } + + return false; +} + +export function isEnumType(tsType: ts.Type): boolean { + // Note: For some reason, test (tsType.flags & ts.TypeFlags.Enum) != 0 doesn't work here. + // Must use SymbolFlags to figure out if this is an enum type. + return tsType.symbol && (tsType.symbol.flags & ts.SymbolFlags.Enum) != 0; +} + +export function isNumberLikeType(tsType: ts.Type): boolean { + return (tsType.getFlags() & ts.TypeFlags.NumberLike) !== 0; +} + +export function hasModifier(tsModifiers: readonly ts.Modifier[], tsModifierKind: number): boolean { + // Sanity check. + if (!tsModifiers) return false; + + for (let tsModifier of tsModifiers) { + if (tsModifier.kind === tsModifierKind) + return true; + } + + return false; +} + + +export function unwrapParenthesizedExpression(tsExpr: ts.Expression): ts.Expression { + let unwrappedExpr = tsExpr; + + while (ts.isParenthesizedExpression(unwrappedExpr)) + unwrappedExpr = unwrappedExpr.expression; + + return unwrappedExpr; +} + +export function symbolHasDuplicateName(symbol: ts.Symbol, tsDeclKind: ts.SyntaxKind): boolean { + // Type Checker merges all declarations with the same name + // in one scope into one symbol. Thus, check whether the + // symbol of certain declaration has any declaration with + // different syntax kind. + let symbolDecls = symbol?.getDeclarations(); + if (symbolDecls) { + for (const symDecl of symbolDecls) { + // Don't count declarations with 'Identifier' syntax kind as those + // usually depict declaring an object's property through assignment. + if (symDecl.kind !== ts.SyntaxKind.Identifier && symDecl.kind !== tsDeclKind) { + return true; + } + } + } + + return false; +} + +export function isReferenceType(tsType: ts.Type): boolean { + let f = tsType.getFlags(); + + return (f & ts.TypeFlags.InstantiableNonPrimitive) != 0 + || (f & ts.TypeFlags.Object) != 0 + || (f & ts.TypeFlags.Boolean) != 0 + || (f & ts.TypeFlags.Enum) != 0 + || (f & ts.TypeFlags.NonPrimitive) != 0 + || (f & ts.TypeFlags.Number) != 0 + || (f & ts.TypeFlags.String) != 0; + //|| (f & ts.TypeFlags.C) + //|| (f & ts.TypeFlags.Instantiable) != 0 +} + +export function isTypeSymbol(symbol: ts.Symbol) { + return symbol && symbol.flags && (symbol.flags & ts.SymbolFlags.Class || symbol.flags & ts.SymbolFlags.Interface); +} + +// Check whether type is generic 'Array' type defined in TypeScript standard library. +export function isGenericArrayType(tsType: ts.Type): boolean { + if (isTypeReference(tsType)) + tsType = tsType.target; + + return tsType.isClassOrInterface() && tsType.getSymbol()?.getName() === "Array"; +} + +export function isTypeReference(tsType: ts.Type): tsType is ts.TypeReference { + return (tsType.getFlags() & ts.TypeFlags.Object) !== 0 && ((tsType as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference) !== 0; +} + +export function isNullType(tsTypeNode: ts.TypeNode): boolean { + return ts.isLiteralTypeNode(tsTypeNode) && tsTypeNode.literal.kind === ts.SyntaxKind.NullKeyword; +} \ No newline at end of file diff --git a/linter/src/cookbook_convertor/cookbook_convertor.ts b/linter/src/cookbook_convertor/cookbook_convertor.ts new file mode 100644 index 000000000..a6af1e2d1 --- /dev/null +++ b/linter/src/cookbook_convertor/cookbook_convertor.ts @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { readFileSync } from 'fs'; +import { join } from 'path'; + + +const COPYRIGHT_HEADER = "/* \n\ + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. \n\ + * Licensed under the Apache License, Version 2.0 (the \"License\"); \n\ + * you may not use this file except in compliance with the License. \n\ + * You may obtain a copy of the License at \n\ + * \n\ + * http://www.apache.org/licenses/LICENSE-2.0 \n\ + * \n\ + * Unless required by applicable law or agreed to in writing, software \n\ + * distributed under the License is distributed on an \"AS IS\" BASIS, \n\ + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n\ + * See the License for the specific language governing permissions and \n\ + * limitations under the License. \n\ + */ \n\ +"; + +// HTML tegs +const T_BR = "
"; +const T_UNDERLINE = ""; +const T_END_UNDERLINE = ""; +const T_BOLD = ""; +const T_END_BOLD = ""; +const T_ITALIC = ""; +const T_END_ITALIC = ""; +const T_CODE = ""; +const T_END_CODE = ""; +const T_NBSP = " "; +const T_HR = "
"; + +// RST substititions +const CB_ = "|CB_"; +const CB_R = "|CB_R|"; +const CB_RULE = "|CB_RULE|"; +const CB_BAD = "|CB_BAD|"; +const CB_OK = "|CB_OK|"; +const CB_SEE = "|CB_SEE|"; + +let doc_lines: string[]; +let _line:number +let recNum: number; + +let tegs: string[] = []; +let cooks: string[] = []; + + +const NEW_REC_HEADER = ".. _R"; +const CODE_BLOCK = ".. code"; // should be ".. code-block" but in some places there is error in doc file + +const CL = " \\"; // continue line + + +function syncReadFile(filename: string) { + const contents = readFileSync(filename, 'utf-8'); + + doc_lines = contents.split(/\r?\n/); + + // ✅ Read file line by line + + //doc_lines.forEach((line) => { + + //console.log(line); + //}); + + _line = 0; + while( _line < doc_lines.length ) { + skipEmptyLines(); + if( doc_lines[_line].startsWith(NEW_REC_HEADER)) { + makeRecept(); + } + else + _line++; + } + + return doc_lines; +} + + +// +// utility functions +// +function translateLine( s: string ) : string { + let line = s; + line = line.replace( CB_BAD, "TypeScript"); + line = line.replace( CB_OK, "ArkTS"); + //line = line.replace( "|CB_R|", "Recipe"); + //.. |CB_RULE| replace:: Rule + //.. |CB_SEE| replace:: See also + line = line.replace( "|JS|", "JavaScript"); + line = line.replace( "|LANG|", "ArkTS"); //.. |LANG| replace:: {lang} + line = line.replace( "|TS|", "TypeScript"); + + return line; +} + + +function translateTeg( s: string) :string { + let ss = s.split("\`\`"); + let teg = ""; + ss.forEach((line) => { teg += "\'" + line; } ); + return teg.replace("\'"," ").trim(); + //return teg.replaceAll("\`\`", "\'"); +} + + +function makeHdr( s: string) :string { + let ss = s.split("\`\`"); + let teg: string =""; + ss.forEach((line) => { teg += "\'" + line; } ); + return teg.replace("\'",""); +} + + +function highlightCode( s: string ): string { + let ss = s.split("\`\`"); + let line = ss[0]; + for( let i = 1; i < ss.length; i++ ) { + if( (i % 2) === 0 ) + line += T_END_CODE; + else + line += T_CODE; + line += ss[i]; + } + return line; +} + +function escapeSym( s: string ): string { + let ss = s.split("\""); + let esc_line = ""; + ss.forEach( (line) => { esc_line += "\\\"" + line; }); + return esc_line.replace("\\\"", ""); +} + +function setNBSP( s: string ): string { + let ss = ""; + let flag = true; + for( let ch of s ) { + if( ch !== " " && ch !== "\t" ) + flag = false; + if( flag && ch === " " ) + ss += T_NBSP; + else if( flag && ch ==="\t" ) + ss += T_NBSP + T_NBSP + T_NBSP + T_NBSP + T_NBSP + T_NBSP + T_NBSP + T_NBSP ; + else + ss += ch; + } + return ss; +} + +function skipEmptyLines() { + while( _line < doc_lines.length ) { + let s = doc_lines[_line]; + s = s.trim(); + if( s !== "") + break; + _line++; + } +} + +function isHeader(): boolean { + return doc_lines[ _line ].startsWith( CB_ ) || doc_lines[ _line ].startsWith( ".." ) ; +} + + + +// +// parsing functions +// +function makeRecept() { + recNum = Number(doc_lines[_line].slice(NEW_REC_HEADER.length, NEW_REC_HEADER.length+3)) + console.log("cookBookMsg[ " + recNum + " ] = \"" + CL); + _line++; + makeTeg(); + makeBody(); + makeBad(); + makeOk(); + makeSee(); + console.log("\";"); + console.log(""); +} + + +function makeTeg() { + console.error(">>>TEG: " + doc_lines[_line]); + //while( !doc_lines[_line].startsWith( CB_R ) ) + while ( _line < doc_lines.length && !isHeader() ) + _line++; + +console.error(">>>TEG>>>: " + _line + " -> " + doc_lines[_line]); + if( ! doc_lines[ _line ].startsWith( CB_R ) ) + return; + let line = doc_lines[ _line ].split( CB_R )[1]; + line = escapeSym( translateLine(line) ); + let teg = translateTeg( line ); + //console.log( teg ); + //let hdr = makeHdr( line ); + let hdr = highlightCode(line); + console.log(hdr + T_BR + CL); + tegs[ recNum ] = teg; + _line++; +} + + +function makeBody(): string { + let body = ""; + + //while( !doc_lines[ _line ].startsWith( CB_RULE ) ){ + while( _line < doc_lines.length && !isHeader()) { + console.error("in rule SKIP: " + doc_lines[ _line ]); + _line++; + } + if( !doc_lines[ _line ].startsWith( CB_RULE ) ) + return ""; + + _line++; _line++; // skip underline + console.log( T_HR + T_BOLD + "Rule" + T_END_BOLD + T_BR + CL ); + while( !isHeader() /*!doc_lines[_line].startsWith("|CB_") && !doc_lines[_line].startsWith("..") */ ) { + //skipEmptyLines(); + let s = translateLine( doc_lines[_line] ); + s = highlightCode( s ); + s = escapeSym( s ); + console.log(s + CL); + + body += s; + _line++; + } + console.log(T_BR + CL); + return body; +} + + + +function makeBad(): string { + let badCode =""; + + while( !isHeader ) { + console.error("in TS SKIP: " + doc_lines[_line]); + _line++; + } + if( ! doc_lines[_line].startsWith( CB_BAD ) ) { + return ""; + } + + _line++; _line++; // skip underline + console.log( T_HR + T_BOLD + "TypeScript" + T_END_BOLD + T_BR + CL ); + while( _line < doc_lines.length && !isHeader() /* !doc_lines[_line].startsWith( CB_ ) && !doc_lines[_line].startsWith("..") */ ) { + //skipEmptyLines(); + let s = translateLine( doc_lines[_line] ); + s = highlightCode( s ); + console.log(s + CL); + + badCode += s; + _line++; + } + skipEmptyLines(); + if( doc_lines[_line++].startsWith( CODE_BLOCK ) ) { + console.log( T_CODE + CL ); + while( _line < doc_lines.length && !isHeader() /* !doc_lines[_line].startsWith( CB_ ) && !doc_lines[_line].startsWith("..") */ ) { + console.log( setNBSP( escapeSym(doc_lines[_line]) ) + T_BR + CL ); + _line++; + } + console.log( T_END_CODE + T_BR + CL ); + } + + return badCode; +} + + +function makeOk(): string { + let goodCode = ""; + + while( !isHeader() ) { + console.error( "in Ark SKIP: " + doc_lines[ _line ] ); + _line++; + } + if( !doc_lines[_line].startsWith(CB_OK) ) { + return ""; + } + + _line++; _line++; // skip underline + console.log( T_HR + T_BOLD + "ArkTS" + T_END_BOLD + T_BR + CL ); + + while( _line < doc_lines.length && !isHeader() /* !doc_lines[ _line ].startsWith( CB_ ) && !doc_lines[ _line ].startsWith( ".." ) */ ) { + //skipEmptyLines(); + let s = translateLine( doc_lines[ _line ] ); + s = highlightCode( s ); + console.log(s + CL); + + goodCode += s; + _line++; + } + + skipEmptyLines(); + if( doc_lines[ _line++ ].startsWith( CODE_BLOCK ) ) { + console.log( T_CODE + CL ); + while( _line < doc_lines.length && !isHeader() /* !doc_lines[ _line ].startsWith( CB_ ) && !doc_lines[ _line ].startsWith("..")*/ ) { + console.log( setNBSP( escapeSym(doc_lines[ _line ]) ) + T_BR + CL ); + _line++; + } + console.log( T_END_CODE + T_BR + CL); + } + + + return goodCode; +} + + +function makeSee( ): string { + console.error("#" + recNum + " PASSED: " + doc_lines[_line]); + while( _line < doc_lines.length && !doc_lines[ _line ].startsWith( ".." ) ) + _line++; + + return ""; +} + + +// +// Main routie +// +let commandLineArgs = process.argv.slice(2); +if (commandLineArgs.length === 0) { + console.log("Command line error: no arguments"); + process.exit(-1); +} + +let inFileName = commandLineArgs[0]; +//console.log(inFileName); +console.log(COPYRIGHT_HEADER); +console.log("export var cookBookMsg: string[] = []; \n"); +console.log("export var cookBookTag: string[] = []; \n"); +syncReadFile( inFileName); + +for( recNum = 1; recNum < tegs.length; recNum++ ) { + console.log( "cookBookTag[ " + recNum + " ] = \"" + ( tegs[ recNum ] ? tegs[ recNum ] : "" ) + "\";" ); +} + diff --git a/linter/src/cookbook_convertor/recipes.rst b/linter/src/cookbook_convertor/recipes.rst new file mode 100644 index 000000000..193fae760 --- /dev/null +++ b/linter/src/cookbook_convertor/recipes.rst @@ -0,0 +1,5100 @@ +Recipes +======= + +.. _R001: + +|CB_R| #1: Objects with property names that are not identifiers are not supported +--------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support Objects with name properties that are numbers or +strings. Use classes to access data by property names. Use arrays to access data +by numeric indices. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var x = {"name": 1, 2: 3} + + console.log(x["name"]) + console.log(x[2]) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class X { + public name: number + } + let x = {name: 1} + console.log(x.name) + + let y = [1, 2, 3] + console.log(y[2]) + + // If you still need a container to store keys of different types, + // use Map: + let z = new Map() + z.set("name", 1) + z.set(2, 2) + console.log(z.get("name")) + console.log(z.get(2)) + +|CB_SEE| +~~~~~~~~ + +* :ref:`R002` +* :ref:`R052` +* :ref:`R059` +* :ref:`R060` +* :ref:`R066` +* :ref:`R105` +* :ref:`R109` + +.. _R002: + +|CB_R| #2: ``Symbol()`` API is not supported +-------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``Symbol()`` API. + +|CB_BAD| +~~~~~~~~ + +|TS| has ``Symbol()`` API, which can be used among other things to generate +unique property names at runtime: + +.. code-block:: typescript + + const sym = Symbol() + let o = { + [sym]: "value" + } + +|CB_OK| +~~~~~~~ + +|LANG| does not support ``Symbol()`` API because its most popular use cases +make no sense in the statically typed environment. In particular, the object +layout is defined at compile time and cannot be changed at runtime. + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R052` +* :ref:`R059` +* :ref:`R060` +* :ref:`R066` +* :ref:`R105` +* :ref:`R109` + +.. _R003: + +|CB_R| #3: Private '#' identifiers are not supported +---------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not private identifiers started with ``#`` symbol, use ``private`` keyword instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class C { + foo = 1 + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class C { + private foo = 1 + } + + +.. _R004: + +|CB_R| #4: Use unique names for types, namespaces, etc. +------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Names for types, namespaces and so on must be unique and distinct from other +names, e.g., variable names. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let X: string + type X = number[] // Type alias with the same name as the variable + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let X: string + type T = number[] // X is not allowed here to avoid name collisions + +.. _R005: + +|CB_R| #5: Use ``let`` instead of ``var`` +----------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``var``, always use ``let`` instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function f(shouldInitialize: boolean) { + if (shouldInitialize) { + var x = 10 + } + return x + } + + console.log(f(true)) // 10 + console.log(f(false)) // undefined + + let upper_let = 0 + { + var scoped_var = 0 + let scoped_let = 0 + upper_let = 5 + } + scoped_var = 5 // Visible + scoped_let = 5 // Compile-time error + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function f(shouldInitialize: boolean): Object { + let x: Object = new Object(); + if (shouldInitialize) { + x = 10 + } + return x + } + + console.log(f(true)); // 10 + console.log(f(false)); // {} + + let upper_let = 0 + let scoped_var = 0 + { + let scoped_let = 0 + upper_let = 5 + } + scoped_var = 5 + scoped_let = 5 // Compile-time error + +.. _R008: + +|CB_R| #8: Use explicit types instead of ``any``, ``undefined``, ``unknown`` +---------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``any``, ``undefined``, and ``unknown`` types. +Specify types explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var x + console.log(x) // undefined + + var y: any + console.log(y) // undefined + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // All variables should have their types specified explicitly: + let x: Object = {} + console.log(x) // {} + +|CB_SEE| +~~~~~~~~ + +* :ref:`R013` + +.. _R009: + +|CB_R| #9: You can extend your |TS| code with more numeric types +---------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports different numeric types on top of just ``number``. + +|CB_BAD| +~~~~~~~~ + +|TS| supports ``number`` as the only numeric type: + +.. code-block:: typescript + + let x: number = 1 + +|CB_OK| +~~~~~~~ + +|LANG| supports several numeric types: + ++-----------+----------+-------------------------------------------------------------+ +| Type | Size | Range | ++===========+==========+=============================================================+ +|``byte`` | 8 bits |``[-128 .. 127]`` | ++-----------+----------+-------------------------------------------------------------+ +|``short`` | 16 bits |``[-32,768 .. 32,767]`` | ++-----------+----------+-------------------------------------------------------------+ +|``int`` | 32 bits |``[-2,147,483,648 .. 2,147,483,647]`` | ++-----------+----------+-------------------------------------------------------------+ +|``long`` | 64 bits |``[-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807]``| ++-----------+----------+-------------------------------------------------------------+ +|``ubyte`` | 8 bits |``[0 .. 255]`` | ++-----------+----------+-------------------------------------------------------------+ +|``ushort`` | 16 bits |``[0 .. 65,535]`` | ++-----------+----------+-------------------------------------------------------------+ +|``uint`` | 32 bits |``[0 .. 4,294,967,295]`` | ++-----------+----------+-------------------------------------------------------------+ +|``ulong`` | 64 bits |``[0 .. 18,446,744,073,709,551,615]`` | ++-----------+----------+-------------------------------------------------------------+ +|``float`` | 32 bits |``3.4E +/- 38 (7 digits)`` | ++-----------+----------+-------------------------------------------------------------+ +|``double`` | 64 bits |``1.7E +/- 308 (15 digits)`` | ++-----------+----------+-------------------------------------------------------------+ + +Additionally, |LANG| supports the following types: + +* Character type ``char`` (the range of values is the same as ``ushort``) +* Boolean type ``boolean`` (values: ``true``, ``false``) + +.. code-block:: typescript + + let x: int = 1 + let y: boolean = true + let z: char = 'a' + +.. _R010: + +|CB_R| #10: Use ``long`` instead of ``bigint`` +---------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Use ``long`` to work with 64-bit integers. + +|CB_BAD| +~~~~~~~~ + +|TS| supports ``bigint`` data type, but this feature is available only since +ES2020 and requires ``n`` suffix for numeric literals: + +.. code-block:: typescript + + let a: bigint = 1n + +|CB_OK| +~~~~~~~ + +|LANG| provides ``long`` data type to work with 64-bit +integers, ``n`` suffix is not supported: + +.. code-block:: typescript + + let x: long = 1 + +.. _R011: + +|CB_R| #11: Use ``enum`` instead of string literal types +--------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support string literal types. Use ``enum`` instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + type Easing = "ease-in" | "ease-out" | "ease-in-out"; + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + enum Easing {EaseIn, EaseOut, EaseInOut} + +.. _R012: + +|CB_R| #12: Use ``T[]`` instead of ``Array`` to declare arrays +----------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +In |TS|, arrays can be declared as either ``Array`` or ``T[]``. Currently, +|LANG| supports only the second syntax for array declaration. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // These are equivalent in TypeScript: + let y: Array = ["1", "2", "3"] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x: string[] = ["1", "2", "3"]; + let y: string[] = ["1", "2", "3"]; // Array is not supported currently + +.. _R013: + +|CB_R| #13: Use ``Object[]`` instead of tuples +---------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support tuples. You can use arrays of ``Object`` +(``Object[]``) to emulate tuples. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var t: [number, string] = [3, "three"] + var n = t[0] + var s = t[1] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let t: Object[] = [3, "three"] + let n = t[0] + let s = t[1] + +|CB_SEE| +~~~~~~~~ + +* :ref:`R013` + +.. _R014: + +|CB_R| #14: Use ``class`` instead of a type with call signature +--------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support call signatures in object types. Use classes instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + type DescribableFunction = { + description: string + (someArg: number): string // call signature + } + + function doSomething(fn: DescribableFunction): void { + console.log(fn.description + " returned " + fn(6)) + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class DescribableFunction { + description: string; + public invoke(someArg: number): string { + return someArg.toString() + } + constructor() { + this.description = "desc" + } + } + + function doSomething(fn: DescribableFunction): void { + console.log(fn.description + " returned " + fn.invoke(6)) + } + + doSomething(new DescribableFunction()); + +|CB_SEE| +~~~~~~~~ + +* :ref:`R015` + +.. _R015: + +|CB_R| #15: Use ``class`` instead of a type with constructor signature +---------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support constructor signatures in object types. Use classes +instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class SomeObject {} + + type SomeConstructor = { + new (s: string): SomeObject + } + + function fn(ctor: SomeConstructor) { + return new ctor("hello"); + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class SomeObject { + public f: string + constructor (s: string) { + this.f = s + } + } + + function fn(s: string): SomeObject { + return new SomeObject(s) + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R014` + +.. _R016: + +|CB_R| #16: Only one static block is supported +---------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not allow to have sevaral static block for class initialization, combine static blocks statements to the one static block. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class C { + static s: string + + static { + C.s = "aa" + } + static { + C.s = C.s + "bb" + } + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + + class C { + static s: string + + static { + C.s = "aa" + C.s = C.s + "bb" + } + } + + +.. _R017: + +|CB_R| #17: Indexed signatures are not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not allow indexed signatures, use arrays instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // Interface with an indexed signature: + interface StringArray { + [index: number]: string + } + + const myArray: StringArray = getStringArray() + const secondItem = myArray[1] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class X { + public f: string[] + } + + let myArray: X = new X() + const secondItem = myArray.f[1] + +.. _R018: + +|CB_R| #18: Use ``Object`` instead of union types +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| provides limited support for union types; +nullable types are supported only in the form ``T | null``. +You can use ``Object`` to emulate the behaviour of the unions in standard |TS|. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var x: string | number + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x: Object + + x = 2 + console.log(x) + + x = "2" + console.log(x) + +.. _R019: + +|CB_R| #19: Use inheritance instead of intersection types +--------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support intersection types. You can use inheritance +as a work-around. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface Identity { + id: number + name: string + } + + interface Contact { + email: string + phone: string + } + + type Employee = Identity & Contact + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface Identity { + id: number + name: string + } + + interface Contact { + email: string + phone: string + } + + interface Employee extends Identity, Contact {} + +.. _R020: + +|CB_R| #20: Default values for type parameters in generics are not supported +---------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support default values for type parameters. Use +generic parameters without default values instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // Declare a generic function: + function foo() {...} + + // Call the function: + foo() // foo() will be called + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // Declare a generic function: + function foo() {...} + + // Call the function: + foo() // N and S should be specified explicitly + +.. _R021: + +|CB_R| #21: Returning ``this`` type is not supported +---------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the returning ``this`` type. Use explicit type instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface ListItem { + getHead(): this + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface ListItem { + getHead(): ListItem + } + +.. _R023: + +|CB_R| #22: Conditional types are not supported +---------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support conditional type aliases. Introduce a new type with constraints explicitly or rewrite logic with use of ``Object``. +``infer`` keyword is not supported. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + type X = T extends number ? T : never + + type Y = T extends Array ? Item : never + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // Provide explicit contraints within type alias + type X1 = T + + // Rewrite with Object. Less type control, need more type checks for safety + type X2 = Object + + // Item has to be used as a generic parameter and need to be properly instantiated + type YI> = Item + + +|CB_R| #23: Type queries are not supported +------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support specifying types via ``typeof``. +All types must be specified explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var a = {x: 10, y: 20} + var b: typeof a + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class A { + public x: number = 10 + public y: number = 20 + } + + let a: A + let b: A + +.. _R024: + +|CB_R| #24: Optional arguments are not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support optional parameters. Specify an +optional parameter as a parameter of a nullable type with the +default value ``null``. Default parameter values are supported for all types. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // x is an optional parameter: + function f(x?: number) { + console.log(x) // log undefined or number + } + + // x is a required parameter with the default value: + function g(x: number = 1) { + console.log(x) + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // Optional parameters are not supported, + // but you can assign a default value ``null`` for the parameter: + function f(x: number | null = null) { + console.log(x); // log null or number + } + + // x is a required argument with the default value: + function g(x: number = 1) { + console.log(x); + } + +.. _R025: + +|CB_R| #25: Declaring fields in ``constructor`` is not supported +---------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support declaring class fields in the ``constructor``. +You must declare them inside the ``class`` declaration instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Person { + constructor( + protected ssn: string, + private firstName: string, + private lastName: string + ) { + this.ssn = ssn + this.firstName = firstName + this.lastName = lastName + } + + getFullName(): string { + return this.firstName + " " + this.lastName + } + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Person { + protected ssn: string + private firstName: string + private lastName: string + + constructor(ssn: string, firstName: string, lastName: string) { + this.ssn = ssn + this.firstName = firstName + this.lastName = lastName + } + + getFullName(): string { + return this.firstName + " " + this.lastName + } + } + +.. _R026: + +|CB_R| #26: Specialized signatures are not supported +---------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support specialized signatures as a form of +overloading with special type notation (string literal instead of type). +Use other patterns (e.g., interfaces) instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + inteface Document { + createElement(tagname: "div"): HTMLDivElement + createElement(tagname: "span"): HTMLDivElement + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class HTMLElement { + // ... + } + + class HTMLDivElement extends HTMLElement { + // ... + } + + class HTMLSpanElement extends HTMLElement { + // ... + } + + interface Document { + createElement(tagName: string): HTMLElement + } + + class D implements Document { + createElement(tagName: string): HTMLElement { + switch (tagname) { + case "div": return new HTMLDivElement() + case "span": return new HTMLSpanElement() + ... + } + } + } + +.. _R027: + +|CB_R| #27: Construct signatures not supported in interfaces +------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support construct signatures. Use methods instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface I { + new (s: string): I + } + + function fn(i: I) { + return new i("hello"); + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface I { + create(s: string): I + } + + function fn(i: I) { + return i.create("hello") + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R015` + +.. _R028: + +|CB_R| #28: Indexed access types are not supported +-------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support indexed access types. Use the type name instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + type Point = {x: number, y: number} + type N = Point["x"] // is equal to number + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Point {x: number = 0; y: number = 0} + type N = number + +.. _R029: + +|CB_R| #29: Indexed access is not supported for fields +------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support indexed access for class fields. Use dot notation instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Point {x: number = 0; y: number = 0} + let p: Point = {x: 1, y: 2} + let x = p["x"] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Point {x: number = 0; y: number = 0} + let p: Point = {x: 1, y: 2} + let x = p.x + +.. _R030: + +|CB_R| #30: Structural identity is not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support structural identity, i.e., the compiler +cannot compare two types' public APIs and decide whether such types are +identical. Use other mechanisms (inheritance, interfaces or type aliases) +instead. + +In |TS|, types ``X`` and ``Y`` are equal (interchangeble), while in |LANG| +they are not. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface X { + f(): string + } + + interface Y { // Y is equal to X + f(): string + } + +|CB_OK| +~~~~~~~ + +|LANG| does not support structural identity. In the static environment the +compiler checks if two classes or interfaces are equal, but there is no way +to compare unrelated (by inheritance or interface) classes that are +structurally equivalent. + +.. code-block:: typescript + + interface X { + f(): string + } + + type Y = X // Y is equal to X + +|CB_SEE| +~~~~~~~~ + +* :ref:`R031` +* :ref:`R032` +* :ref:`R035` + + +.. _R031: + +|CB_R| #31: Structural typing is not supported for subtyping / supertyping +-------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not check structural equivalence for type inference, i.e., +the compiler cannot compare two types' public APIs and decide whether such types +are identical. +Use other mechanisms (inheritance or interfaces) instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class X { + public foo: number + + constructor() { + this.foo = 0 + } + } + + class Y { + public foo: number + + constructor() { + this.foo = 0 + } + } + + let x = new X() + let y = new Y() + + console.log("Assign X to Y") + y = x + + console.log("Assign Y to X") + x = y + + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class X { + public foo: number + + constructor() { + this.foo = 0 + } + } + + // Y is derived from X, which explicitly set subtype / supertype relations: + class Y extends X { + constructor() { + super() + } + } + + let x = new X() + let y = new Y() + + console.log("Assign X to Y") + y = x // ok, X is the super class of X + + // Cannot assign Y to X + //x = y - compile-time error + + +|CB_SEE| +~~~~~~~~ + +* :ref:`R030` +* :ref:`R032` +* :ref:`R035` + +.. _R032: + +|CB_R| #32: Structural typing is not supported for assignability checks +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not check structural equivalence when checking if types +are assignable to each other, i.e., the compiler cannot compare two types' +public APIs and decide whether such types are identical. Use other mechanisms +(inheritance or interfaces) instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class X { + public foo: number + + constructor() { + this.foo = 0 + } + } + + class Y { + public foo: number + constructor() { + this.foo = 0 + } + } + + let x = new X() + let y = new Y() + + console.log("Assign X to Y") + y = x + + console.log("Assign Y to X") + x = y + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface Z { + foo: number + } + + // X implements interface Z, which makes relation between X and Y explicit. + class X implements Z { + public foo: number + + constructor() { + this.foo = 0 + } + } + + // Y implements interface Z, which makes relation between X and Y explicit. + class Y implements Z { + public foo: number + + constructor() { + this.foo = 0 + } + } + + let x: Z = new X() + let y: Z = new Y() + + console.log("Assign X to Y") + y = x // ok, both are of the same type + + console.log("Assign Y to X") + x = y // ok, both are of the same type + +|CB_SEE| +~~~~~~~~ + +* :ref:`R030` +* :ref:`R031` +* :ref:`R035` + +.. _R033: + +|CB_R| #33: Optional properties are not supported +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support optional properties. Use properties with default values. +Use properties of nullable types and the default ``null`` value to distinguish +whether a value is set or not. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface CompilerOptions { + strict?: boolean + sourcePath?: string + targetPath?: string + } + + var options: CompilerOptions = { + strict: true, + sourcepath: "./src", + } + if option.targetPath == undefined { + // set default + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + interface CompilerOptions { + strict: boolean = false + sourcePath: string = "" + targetPath: string | null = null + } + + let options: CompilerOptions = { + strict: true, + sourcepath: "./src", + } + if option.targetPath == null { + // set default + } + +.. _R034: + +|CB_R| #34: Generic functions must be called with explicit type specialization +------------------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support inference of type parameters in case of calls +to generic functions. If a function is declared generic, all calls must specify +type parameters explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function choose(x: T, y: T): T { + return Math.random() < 0.5 ? x : y + } + + let x = choose(10, 20) // Ok + let y = choose("10", 20) // Compile-time error + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function choose(x: T, y: T): T { + return Math.random() < 0.5 ? x : y + } + + let x = choose(10, 20) // Ok + let y = choose("10", 20) // Compile-time error + +.. _R035: + +|CB_R| #35: Structural typing is not supported for type inference +----------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support structural typing, i.e., the compiler cannot +compare two types' public APIs and decide whether such types are identical. +Use inheritance and interfaces to specify the relation between the types +explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class X { + public foo: number + private s: string + + constructor (f: number) { + this.foo = f + this.s = "" + } + + public say(): void { + console.log("X = ", this.foo) + } + } + + class Y { + public foo: number + + constructor (f: number) { + this.foo = f + } + public say(): void { + console.log("Y = ", this.foo) + } + } + + function bar(z: X): void { + z.say() + } + + // X and Y are equivalent because their public API is equivalent. + // Thus the second call is allowed: + bar(new X(1)); + bar(new Y(2)); + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface Z { + say(): void + } + + class X implements Z { + public foo: number + private s: string + + constructor (f: number) { + this.foo = f + this.s = "" + } + public say(): void { + console.log("X = ", this.foo) + } + } + + class Y implements Z { + public foo: number + + constructor (f: number) { + this.foo = f + } + public say(): void { + console.log("Y = ", this.foo) + } + } + + function bar(z: Z): void { + z.say() + } + + // X and Y implement the same interface Z, thus both calls are allowed: + bar(new X(1)) + bar(new Y(2)) + +|CB_SEE| +~~~~~~~~ + +* :ref:`R030` +* :ref:`R031` +* :ref:`R032` + +.. _R036: + +|CB_R| #36: Type widening is not supported +------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support widened types because in most cases type widening +is applied to the currently unsupported types ``any``, ``unknown`` +and ``undefined``. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + var a = null + var b = undefined + var c = {c: 0, y: null} + var d = [null, undefined] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class C { + public c: number = 0 + public y: Object | null + } + + let a: Object | null = null + let b: Object + let c: C = {c: 0, y: null} + let d: Object[] = [null, null] + +.. _R037: + +|CB_R| #37: RegExp literals are not supported +--------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support RegExp literals. Use library call with string +literals instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let regex: RegExp = /bc*d/ + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let regex: RegExp = new RegExp("/bc*d/") + +.. _R038: + +|CB_R| #38: Object literal must correspond to explicitly declared class or interface +------------------------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the usage of object literals if the compiler can infer +to what classes or interfaces such literals correspond to. +Otherwise, a compile-time error occurs. + +The class or interface can be specified as a type annotation for a variable. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let x = {f: 1} + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class O { + f: number + } + + let x: O = {f: 1} // OK + let y = {f: 1} // Compile-time error, cannot infer object literal type + let z: Object = {f: 2} // Compile-time error, class 'Object' does not have field 'f' + +|CB_SEE| +~~~~~~~~ + +* :ref:`R039` +* :ref:`R040` +* :ref:`R042` +* :ref:`R043` + +.. _R039: + +|CB_R| #39: Object literals must correspond to explicitly declared class or interface +------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the usage of object literals if the compiler can infer to what +classes or interfaces such literals correspond to. Otherwise, a compile-time +error occurs. + +The class or interface can be inferred from a type of the corresponding function parameter. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function foo(x: any) {} + foo({f: 1}) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class S { + f: number + } + + function foo(s: S) {} + + foo({f: 2}) // ok + foo({ff: 2}) // Compile-time error, class 'S' does not have field 'ff' + +|CB_SEE| +~~~~~~~~ + +* :ref:`R038` +* :ref:`R040` +* :ref:`R042` +* :ref:`R043` + +.. _R040: + +|CB_R| #40: Object literals cannot be used as type declarations +--------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the usage of object literals to declare +types in place. Declare classes and interfaces explicitly instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let o: {x: number, y: number} = { + x: 2, + y: 3 + } + + type T = G<{x: number, y: number}> + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class O { + x: number + y: number + } + + let o: O = {x: 2, y: 3} + + type T = G + +|CB_SEE| +~~~~~~~~ + +* :ref:`R038` +* :ref:`R039` +* :ref:`R042` +* :ref:`R043` + +.. _R042: + +|CB_R| #42: Array literals must correspond to known array types +--------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the usage of array literals if the compiler can infer +to what array types such literals correspond to. Otherwise, a compile-time +error occurs. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let x = ["aa", "bb"] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x: string[] = ["aa", "bb"] + +|CB_SEE| +~~~~~~~~ + +* :ref:`R038` +* :ref:`R039` +* :ref:`R040` +* :ref:`R043` + +.. _R043: + +|CB_R| #43: Untyped array literals are not supported +---------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the usage of untyped array literals. The type of an +array element must be inferred from the context. Use the type ``Object`` to +define mixed types array. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let x = [1, 2] + let y = [1, "aa"] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x: Object[] = [new Int(1), new Int(2)] + + // Implicit boxing of primitive int to object Int + let x1: Object[] = [1, 2] + + let y: Object[] = [1, "aa"] + +|CB_SEE| +~~~~~~~~ + +* :ref:`R038` +* :ref:`R039` +* :ref:`R040` +* :ref:`R042` + +.. _R044: + +|CB_R| #44: Template literals are not supported +----------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support template literals. You may use a ``+`` +concatenation as a work-around. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + const a = 5 + const b = 10 + console.log(`Fifteen is ${a + b}`) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + const a = 5 + const b = 10 + + // (a + b) is converted to Int and then toString() method is called: + console.log("Fifteen is " + (a + b)) + +.. _R045: + +|CB_R| #45: Lambdas require explicit type annotation for parameters +------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| requires the types of lambda parameters +to be explicitly specified. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let f = (s) => { // type any is assumed + console.log(s) + } + +|CB_OK| +~~~~~~~ + +Explicit types for lambda parameters are mandatory. + +.. code-block:: typescript + + let f = + (s: string) => { + console.log(s) + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R047` + +.. _R046: + +|CB_R| #46: Use arrow functions instead of function expressions +------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support function expressions, use arrow functions instead +to be explicitly specified. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let f = function (s: string) { + console.log(s) + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let f = (s: string) => { + console.log(s) + } + +.. _R047: + +|CB_R| #47: Return type must be specified for lambdas explicitly +---------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +An explicit return type is mandatory for a lambda expression. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let f = (s: string) => { // return type is implicit + return s.toLowerCase() + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let f = (s: string): string => { // return type is explicit + return s.toLowerCase() + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R045` + +.. _R048: + +|CB_R| #48: Shortcut syntax for lambdas is not supported +-------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support shortcut syntax for lambdas. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = (x: number) => { return x } + let b = (x: number) => x + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a: (x: number) => number = + (x: number): number => { return x } + + let b: (x: number) => number = + (x: number): number => { return x } + + +|CB_R| #49: Usage of arrow function with type assertions or generics +-------------------------------------------------------------------- + +|CB_BAD| +~~~~~~~~ + +A non-compliant syntax is used. Not a part of the common subset. + +.. code-block:: typescript + + let generic_arrow_func = + (x: T) => { return x } + let type_asserted_function = + <() => boolean> (() => {return true}) + + generic_arrow_func(5) // Compile-time error + generic_arrow_func("string") + type_asserted_function() + +|CB_OK| +~~~~~~~ + +Introduce a new function to replace an arrow function with generics. +Explicit types are mandatory, static typing replaces type assertions by design. + +.. code-block:: typescript + + function generic_arrow_func(x: T): T { + return x + } + + let type_asserted_func: () => boolean = + (): boolean => {return true} + + generic_arrow_func(5) // Compile-time error + generic_arrow_func("string") + + type_asserted_func() + +.. _R050: + +|CB_R| #50: Class literals are not supported +-------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support class literals. A new named class type must be +introduced explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + const Rectangle = class { + constructor(height: number, width: number) { + this.heigth = height + this.width = width + } + + heigth + width + } + + const rectangle = new Rectangle(0.0, 0.0) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Rectangle { + constructor(height: number, width: number) { + this.heigth = height + this.width = width + } + + heigth: number + width: number + } + + const rectangle = new Rectangle(0.0, 0.0) + +.. _R051: + +|CB_R| #51: Classes cannot be specified in ``implements`` clause +---------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not allow to specify a class in implements clause. Only interfaces may be specified. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class C { + foo() {} + } + + class C1 implements C { + foo() {} + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface C { + foo() + } + + class C1 implements C { + foo() {} + } + + +.. _R052: + +|CB_R| #52: Attempt to access an undefined property is a compile-time error +--------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports accessing only those class properties that are either declared +in the class, or accessible via inheritance. Accessing any other properties is +prohibited and causes compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let person = {name: "Bob", isEmployee: true} + + let n = typ["name"] + let e = typ["isEmployee"] + let s = typ["office"] // undefined + +|CB_OK| +~~~~~~~ + +Use proper types to check property existence during compilation. + +.. code-block:: typescript + + class Person { + constructor(name: string, isEmployee: boolean) { + this.name = name + this.isEmployee = isEmployee + } + + name: string + isEmployee: boolean + } + + let person = new Person("Bob", true) + let n = typ.name + let e = typ.isEmployee + let s = typ.office // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R059` +* :ref:`R060` +* :ref:`R066` +* :ref:`R105` +* :ref:`R109` + +.. _R053: + +|CB_R| #53: Only ``as T`` syntax is supported for type casts +------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports ``as`` keyword as the only syntax for type casts. +Incorrect cast causes a compile-time error or runtime ``ClassCastException``. +```` syntax for type casts is not supported. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Shape {} + class Circle extends Shape {x: number = 5} + class Square extends Shape {y: string = "a"} + + function createShape(): Shape { + return new Circle() + } + + let c1 = createShape() + + let c2 = createShape() as Circle + + // No report is provided during compilation + // nor during runtime if cast is wrong: + let c3 = createShape() as Square + console.log(c3.y) // undefined + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Shape {} + class Circle extends Shape {x: number = 5} + class Square extends Shape {y: string = "a"} + + function createShape(): Shape { + return new Circle() + } + + let c2 = createShape() as Circle + + // ClassCastException during runtime is thrown: + let c3 = createShape() as Square + +.. _R054: + +|CB_R| #54: JSX expressions are not supported +--------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Do not use JSX since no alternative is provided to rewrite it. + +.. _R055: + +|CB_R| #55: Unary operators ``+``, ``-`` and ``~`` work only on numbers +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| allows unary operators to work on numeric types only. A compile-time +error occurs if these operators are applied to a non-numeric type. Unlike in +|TS|, implicit casting of strings in this context is not supported and must +be done explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = +5 // 5 as number + let b = +"5" // 5 as number + let c = -5 // -5 as number + let d = -"5" // -5 as number + let e = ~5 // -6 as number + let f = ~"5" // -6 as number + let g = +"string" // NaN as number + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = +5 // 5 as int + let b = +"5" // Compile-time error + let c = -5 // -5 as int + let d = -"5" // Compile-time error + let e = ~5 // -6 as int + let f = ~"5" // Compile-time error + let g = +"string" // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R056: + +|CB_R| #56: Unary ``+`` cannot be used for casting to ``number`` +---------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support casting from any type to a numeric type +by using the unary ``+`` operator, which can be applied only to +numeric types. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function returnTen(): string { + return "-10" + } + + function returnString(): string { + return "string" + } + + let a = +returnTen() // -10 as number + let b = +returnString() // NaN + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function returnTen(): string { + return "-10" + } + + function returnString(): string { + return "string" + } + + let a = +returnTen() // Compile-time error + let b = +returnString() // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R057: + +|CB_R| #57: ``!`` operator works only on values of the boolean type +------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports using ``!`` operator only for values of the boolean type. +Explicit cast from some type to the boolean (or Boolean) is mandatory. +Implicit casts are prohibited and cause compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = !true // false + let b = !"true" // false + let c = !"rnd_str" // false + let d = !"false" // false + let e = !5 // false + let f = !0 // true + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = !true // false + let b = !"true" // Compile-time error + let c = !"false" // Compile-time error + let d = !"rnd_str" // Compile-time error + let e = !5 // Compile-time error + let f = !0 // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R059: + +|CB_R| #59: ``delete`` operator is not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| assumes that object layout is known at compile time and cannot be +changed at runtime. Thus the operation of deleting a property makes no sense. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Point { + x?: number = 0.0 + y?: number = 0.0 + } + + let p = new Point() + delete p.y + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // To mimic the original semantics, you may declare a nullable type + // and assign null to mark value absence: + + class Point { + x: number | null + y: number | null + } + + let p = new Point() + p.y = null + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R052` +* :ref:`R060` +* :ref:`R066` +* :ref:`R105` +* :ref:`R109` + +.. _R060: + +|CB_R| #60: ``typeof`` operator is not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``typeof`` operator and requires explicit typing. +Use ``instanceof`` as a work-around where applicable. Type can be inferred +from the initalizer, but the initial value can be not a default one. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + console.log(typeof 5) // "number" + console.log(typeof "string") // "string" + let s = "hello" + let n: typeof s // n type is string, n == "" + let b = typeof s == "string" // true + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let s = "hello" + let n = s + let b = s instanceof string // true + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R052` +* :ref:`R059` +* :ref:`R066` +* :ref:`R105` +* :ref:`R109` + +.. _R061: + +|CB_R| #61: Binary operators ``*``, ``/``, ``%``, ``-``, ``<<``, ``>>``, ``>>>``, ``&``, ``^`` and ``|`` work only on numeric types +----------------------------------------------------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| allows applying binary operators ``*``, ``/``, ``%``, ``-``, ``<<``, +``>>``, ``>>>``, ``&``, ``^`` and ``|`` only to values of numeric types. +Implicit casts from other types to numeric types are prohibited and cause +compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = (5 & 5) // 5 + let b = (5.5 & 5.5) // 5, not 5.5 + let c = (5 | 5) // 5 + let d = (5.5 | 5.5) // 5, not 5.5 + + enum Direction { + Up = -1, + Down + } + let e = Direction.Up >> 1 // -1 + let f = Direction.Up >>> 1 // 2147483647 + + let g = ("10" as any) << 1 // 20 + let h = ("str" as any) << 1 // 0 + + let i = 10 * 5 + let j = 10 / 5 + let k = 10 % 5 + let l = 10 - 5 + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = (5 & 5) // 5 + let b = (5.5 & 5.5) // Compile-time error + let c = (5 | 5) // 5 + let d = (5.5 | 5.5) // Compile-time error + + enum Direction { + Up, // TBD: explicit start value + Down + } + + let e = Direction.Up >> 1 // 0 + let f = Direction.Up >>> 1 // 0 + + let i = 10 * 5 + let j = 10 / 5 + let k = 10 % 5 + let l = 10 - 5 + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R062: + +|CB_R| #62: Binary operators ``<<``, ``>>``, ``>>>``, ``&``, ``^`` and ``|`` work only on integral numeric types +---------------------------------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| expects an explicit cast to an integral type for logical binary +operations. Implicit casts are prohibited and cause compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let b = (5.5 & 5.5) // 5, not 5.5 + let d = (5.5 | 5.5) // 5, not 5.5 + + let g = ("10" as any) << 1 // 20 + let h = ("str" as any) << 1 // 0 + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let b = (5.5 & 5.5) // Compile-time error + let d = (5.5 | 5.5) // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R063: + +|CB_R| #63: Binary ``+`` operator supports implicit casts only for numbers and strings +-------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports implicit casts for ``+`` only for strings and numbers. +Elsewhere, any form of an explicit cast to string is required. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + enum E { E1, E2 } + + let a = 10 + 32 // 42 + let b = E.E1 + 10 // 10 + let c = 10 + "5" // "105" + + let d = "5" + E.E2 // "51" + let e = "Hello, " + "world!" // "Hello, world!" + let f = "string" + true // "stringtrue" + + let g = (new Object()) + "string" // "[object Object]string" + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + enum E { E1, E2 } + + let a = 10 + 32 // 42 + let b = E.E1 + 10 // 10 + let c = 10 + "5" // "105" + + let d = "5" + E.E2 // "51" + let e = "Hello, " + "world!" // "Hello, world!" + let f = "string" + true // "stringtrue" + + let g = (new Object()).toString() + "string" + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +.. _R064: + +|CB_R| #64: Binary ``+`` operator requires explicit casts for non-numbers and non-strings +----------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports implicit casts for ``+`` only for strings and numbers. +Elsewhere, any form of an explicit cast to string is required. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // "[object Object][object Object]" + let o = ({x: 5} as any) + {y: 6} + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let o = (new Object()).toString() + new Int(5) // "5" + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R067` +* :ref:`R068` +* :ref:`R078` + +|CB_R| #65: ``instanceof`` operator is partially supported +---------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +In |TS|, the left-hand side of an ``instanceof`` expression must be of type +``any``, an object type or a type parameter, otherwise the result is ``false``. +In |LANG|, the left-hand side expression may be of any reference type, otherwise +a compile-time error occurs. In addition, the left operand in |LANG| cannot be +a type. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class X {} + + let a = (new X()) instanceof Object // true + let b = (new X()) instanceof X // true + // left operand is a type: + let c = X instanceof Object // true + let d = X instanceof X // false + + // left operand is not of type any + let e = (5.0 as Number) instanceof Number // false + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class X {} + + let a = (new X()) instanceof Object // true + let b = (new X()) instanceof X // true + // left operand is a type: + let c = X instanceof Object // Compile-time error + let d = X instanceof X // Compile-time error + + // left operand may be of any reference type, like number + let e = (5.0 as Number) instanceof Number // true + +.. _R066: + +|CB_R| #66: ``in`` operator is not supported +-------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the ``in`` operator. However, this operator makes +little sense since the object layout is known at compile time and cannot +be modified at runtime. Use ``instanceof`` as a work-around if you still need +to check whether certain class members exist. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string = "" + } + let p = new Person() + + let b = "name" in p // true + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string = "" + } + let p = new Person() + + let b = p instanceof Person // true, and "name" is guaranteed to be present + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R052` +* :ref:`R059` +* :ref:`R060` +* :ref:`R105` +* :ref:`R109` + +.. _R067: + +|CB_R| #67: Operators ``&&`` and ``||`` work on values of the boolean type only +------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports using ``&&`` and ``||`` operators only for the values of the +boolean type. Explicit cast from some type to the boolean (or Boolean) is +mandatory. Implicit casts are prohibited and cause compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = true && false // false + let b = 5 || 0 // 5 + let c = 5 && 0 // 0 + let d = "" && 5 // "" + let e = "" || "abcd" // "abcd" + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = true && false // false + let b = 5 || 0 // Compile-time error + let c = 5 && 0 // Compile-time error + let d = "" && 5 // Compile-time error + let e = "" || "abcd" // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R068` +* :ref:`R078` + +.. _R068: + +|CB_R| #68: Using of ``&&`` and ``||`` on non-boolean types is not supported +---------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the usage of ``&&`` and ``||`` operators only for the values +of the boolean type. Explicit cast from some type to the boolean (or Boolean) +is mandatory. Implicit casts are prohibited and cause compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a = true && false // false + let b = 5 || 0 // 5 + let c = 5 && 0 // 0 + let d = "" && 5 // "" + let e = "" || "abcd" // "abcd" + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = true && false // false + let b = 5 || 0 // Compile-time error + let c = 5 && 0 // Compile-time error + let d = "" && 5 // Compile-time error + let e = "" || "abcd" // Compile-time error + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R078` + +.. _R069: + +|CB_R| #69: Destructuring assignment is not supported +----------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support destructuring assignment. Other idioms (e.g., +using a temporary variable, where applicable) can be used for replacement. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let [one, two] = [1, 2] + [one, two] = [two, one] + + let head, tail + [head, ...tail] = [1, 2, 3, 4] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let arr: number[] = [1, 2] + let one = arr[0] + let two = arr[1] + + let tmp = one + one = two + two = tmp + + let data: Number[] = [1,2,3,4] + let head = data[0] + let tail = new Number[data.length - 1] + for (let i = 1; i < data.length; ++i) { + tail[i-1] = data[i] + } + +.. _R071: + +|CB_R| #71: The comma operator ``,`` is supported only in ``for`` loops +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the comma operator ``,`` only in ``for`` loops. Otherwise, +it is useless as it makes the execution order harder to understand. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + for (let i = 0, j = 0; i < 10; ++i, j += 2) { + console.log(i, j) + } + + let x = 0 + x = (++x, x++) // 1 + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + for (let i = 0, j = 0; i < 10; ++i, j += 2) { + console.log(i, j) + } + + // Use explicit execution order instead of the comma operator: + let x = 0 + ++x + x = x++ + +|CB_R| #72: Usage of contextually typed expressions is supported partially +-------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +In many cases |TS| allows the use of contextually typed expressions, +where the actual type of expression is defined by the type of destination. +|LANG| allows the use of contextually typed expressions in the following +two situations: + +- as an initialization expresssion in a variable or constant declaration; and +- as an argument in a function call. + +Other usages are contradictory to the static typing. + +|CB_BAD| +~~~~~~~~ + +A literal can be contextually typed as Point, i.e., implicit. This feature +is prohibited in |LANG| due to the static typing. + +.. code:: typescript + + class Point { + x: number = 0.0 + y: number = 0.0 + ... + } + + function id_x_y(o: Point) : Point { + return o + } + + // type of expression determined by the type of the variable + let p: Point = {x: 5, y: 10} + + // type of expression determined by the type of the parameter + id_x_y({x: 5, y: 10}) + +|CB_OK| +~~~~~~~ + +A value with an instantiated type must be passed into a function. +There are no implicit casts from any arbitrary type to another type. + +.. code:: typescript + + class Point { + x: number = 0.0 + y: number = 0.0 + ... + } + + function id_x_y(o: Point): Point { + return o + } + + // type of expression determined by the type of the variable + let p: Point = {x: 5, y: 10} + + // type of expression determined by the type of the parameter + id_x_y({x: 5, y: 10}) + +.. _R073: + +|CB_R| #74: Destructuring variable declarations are not supported +----------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support destructuring variable declarations. This is a dynamic +feature relying on structural compatibility. In addition, names in destructuring +declarations must be equal to properties within destructured classes. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + class Point { + x: number = 0.0 + y: number = 0.0 + } + + function returnZeroPoint(): Point { + return new Point() + } + + let {x, y} = returnZeroPoint() + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + class Point { + x: number = 0.0 + y: number = 0.0 + } + + function returnZeroPoint(): Point { + return new Point() + } + + // Create an intermediate object and work with it field by field + // without name restrictions: + let zp = returnZeroPoint() + let x = zp.x + let y = zp.y + +.. _R076: + +|CB_R| #76: Inference of implied types is not supported +------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support inference of implied types. Use explicit +type notation instead. Use ``Object[]`` if you need containers that hold +data of mixed types. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let [a, b, c] = [1, "hello", true] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let a = 1 + let b = "hello" + let c = true + + let arr: Object[] = [1, "hello", true] + let a1 = arr[0] + let b1 = arr[1] + let c1 = arr[2] + +.. _R078: + +|CB_R| #78: Implicit casts to the boolean are not supported in ``if``, ``do`` and ``while`` +------------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports only values of the boolean type in ``if``, ``do`` and ``while`` +statements. Implicit casts from other types to the boolean are prohibited and +cause compile-time errors. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + if (true) {} + do {} while (false) + + let a = new Boolean(true) + if (a) {} + do {break} while (a) + while (a) {break} + + let b = 42 + if (b) {} + do {break} while (b) + while (b) {break} + + let c = "str" + if (c) {} + do {break} while (c) + while (c) {break} + + let d = new Object() + if (d) {} + do {break} while (d) + while (d) {break} + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + if (true) {} + do {} while (false) + + let a = new Boolean(true) + if (a) {} + do {break} while (a) + while (a) {break} + + let b = 42 + if (b != 0) {} + do {break} while (b != 0) + while (b != 0) {break} + + let c = "str" + if (c.length != 0) {} + do {break} while (c.length != 0) + while (c.length != 0) {break} + + let d = new Object() + if (d != null) {} + do {break} while (d != null) + while (d != null) {break} + +|CB_SEE| +~~~~~~~~ + +* :ref:`R055` +* :ref:`R056` +* :ref:`R057` +* :ref:`R061` +* :ref:`R062` +* :ref:`R063` +* :ref:`R064` +* :ref:`R067` +* :ref:`R068` + +.. _R079: + +|CB_R| #79: Type annotation in catch clause is not supported +------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +In |TS| catch clause variable type annotation must be ``any`` or ``unknown`` if specified. +As |LANG| does not support these types, a type annotation should be omitted. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + try { + // some code + } + catch (a: unknown) {} + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + try { + // some code + } + catch (a) {} + +|CB_SEE| +~~~~~~~~ + +* :ref:`R087` + +.. _R080: + +|CB_R| #80: ``for .. in`` is not supported +------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the iteration over object contents by the +``for .. in`` loop. For objects, iteration over properties at runtime is +considered redundant because object layout is known at compile time and cannot +change at runtime. For arrays, you can iterate with the regular ``for`` loop. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let a: number[] = [1.0, 2.0, 3.0] + for (let i in a) { + console.log(a[i]) + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + let a: number[] = [1.0, 2.0, 3.0] + for (let i = 0; i < a.length; ++i) { + console.log(a[i]) + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R081` +* :ref:`R082` + +.. _R081: + +|CB_R| #81: Iterable interfaces are not supported +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the ``Symbol`` API, ``Symbol.iterator`` and +eventually iterable interfaces. Use arrays and library-level containers to +iterate over data. + +|CB_SEE| +~~~~~~~~ + +* :ref:`R002` +* :ref:`R080` +* :ref:`R082` + +.. _R082: + +|CB_R| #82: ``for-of`` is supported only for arrays +------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the iteration over arrays by the ``for .. of`` loop, +but does not support the iteration of objects content. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + let a: string[] = ["a", "b", "c"] + for (let s of a) { + console.log(s) + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + let a: string[] = ["a", "b", "c"] + for (let s of a) { + console.log(s) + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R080` +* :ref:`R081` + +.. _R083: + +|CB_R| #83: Mapped type expression is not supported +--------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support mapped types. Use other language idioms and regular classes +to achieve the same behaviour. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + type OptionsFlags = { + [Property in keyof Type]: boolean; + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R097` + +.. _R084: + +|CB_R| #84: ``with`` statement is not supported +----------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the ``with`` statement. Use other language idioms +(including fully qualified names of functions) to achieve the same behaviour. + +.. _R085: + +|CB_R| #85: Values computed at runtime are not supported in ``case`` statements +------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports ``case`` statements that contain only compile-time values. +Use ``if`` statements as an alternative. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let x = 2 + let y = 3 + switch (x) { + case 1: + console.log(1) + break + case 2: + console.log(2) + break + case y: + console.log(y) + break + default: + console.log("other") + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x = 2 + switch (x) { + case 1: + console.log(1) + break + case 2: + console.log(2) + break + case 3: + console.log(3) + break + default: + console.log("other") + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R112` + +.. _R086: + +|CB_R| #86: ``switch`` statements cannot accept values of arbitrary types +------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports the values of the types ``char``, ``byte``, ``short``, ``int``, +``long``, ``Char``, ``Byte``, ``Short``, ``Int``, ``Long``, ``String`` or +``enum`` in ``switch`` statements. Use ``if`` statements in other cases. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Point { + x: number = 0 + y: number = 0 + } + + let a = new Point() + + switch (a) { + case null: break; + default: console.log("not null") + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Point { + x: number = 0 + y: number = 0 + } + + let a = new Point() + + if (a != null) { + console.log("not null") + } + +.. _R087: + +|CB_R| #87: ``throw`` statements cannot accept values of arbitrary types +------------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| supports throwing only objects of the class ``Error`` or any +derived class. Throwing an arbitrary type (i.e., a ``number`` or ``string``) +is prohibited. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + throw 4 + throw "" + throw new Error() + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + throw new Error() + +.. _R088: + +|CB_R| #88: Each overloaded function should have its body +--------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the |TS| style of overloading signatures with one +function body. Define each overloading function with its own body instead of +one body for a list of signatures. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + function add(x: number, y: number): number + function add(x: string, y: string): string + function add(x: any, y: any): any { + return x + y + } + + console.log(add(2, 3)) // returns 5 + console.log(add("hello", "world")) // returns "helloworld" + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + function add(x: number, y: number): number { + return x + y + } + + function add(x: string, y: string): string { + return x + y + } + + function main() { + console.log(add(2, 3)) // returns 5 + console.log(add("hello", "world")) // returns "helloworld" + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R089` + +.. _R089: + +|CB_R| #89: Each overloaded function with optional parameters should have its body +---------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the |TS| style of overloading signatures with one +function body. Write a separate body for each overloaded signature instead of +an optional parameter like `value?` for a single body in |TS|. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + function foo(name: string): number + function foo(name: string, value: string): Accessor + function foo(name: any, value?: string): any { + // one body here + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + function foo(name: string): string { + return name + } + + function foo(name: string, value: string): Accessor { + return new Accessor() + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R088` + +.. _R090: + +|CB_R| #90: Function must have explicit return type +--------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| requires all functions to have explicit return types. For corner cases, +use `Object` when it is difficult to determine the return type. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function f(x: number) { + if (x <= 0) { + return x + } + return g(x) + } + + function g(x: number) { + return f(x - 1) + } + + function doOperation(x: number, y: number) { + return x + y + } + + console.log(f(10)) + console.log(doOperation(2, 3)) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function f(x: number): Object { + if (x <= 0) { + return x + } + return g(x) + } + + function g(x: number): Object { + return f(x - 1) + } + + function doOperation(x: number, y: number): Object { + let z = x + y + return z + } + + function main(): void { + console.log(f(-10) as number) // returns -10 + console.log(doOperation(2, 3)) // returns 5 + } + +|CB_R| #91: Destructuring parameter declarations are not supported +------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| requires that parameters must be passed directly to the function, and +local names must be assigned manually. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) { + console.log(text) + console.log(x) + console.log(y) + console.log(bold) + } + + drawText({ text: "Hello, world!", location: [100, 50], bold: true }) + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + function drawText(text: String, location: number[], bold: boolean) { + let x = location[0] + let y = location[1] + console.log(text) + console.log(x) + console.log(y) + console.log(bold) + } + + function main() { + drawText("Hello, world!", [100, 50], true) + } + +.. _R092: + +|CB_R| #92: Nested functions are not supported +---------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support nested functions. Use lambdas instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function addNum(a: number, b: number): void { + + // nested function: + function logToConsole(message: String): void { + console.log(message) + } + + let result = a + b + + // Invoking the nested function: + logToConsole("result is " + result) + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function addNum(a: number, b: number): void { + + // Use lambda instead of a nested function: + let logToConsole: (message: String): void = (message: String): void => { + console.println(message) + } + + let result = a + b + + logToConsole("result is " + result) + } + +.. _R093: + +|CB_R| #93: Using ``this`` inside stand-alone functions is not supported +------------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the usage of ``this`` inside stand-alone functions. +``this`` can be used in methods only. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function foo(i: number) { + this.count = i + } + + class A { + count: number = 1 + m = foo + } + + let a = new A() + console.log(a.count) // prints "1" + a.m(2) + console.log(a.count) // prints "2" + + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class A { + count: number = 1 + m(i: number): void { + this.count = i + } + } + + function main(): void { + let a = new A() + console.log(a.count) // prints "1" + a.m(2) + console.log(a.count) // prints "2" + } + +.. _R094: + +|CB_R| #94: Generator functions are not supported +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support generator functions. +Use the ``async`` / ``await`` mechanism for multitasking. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function* counter(start: number, end: number) { + for (let i = start; i <= end; i++) { + yield i + } + } + + for (let num of counter(1, 5)) { + console.log(num) + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + for (let i = 1; i <= 5; ++i) { + console.log(i) + } + +.. _R095: + +|CB_R| #95: Asynchronous functions are partially supported +---------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| partially supports asynchronous functions. +Using the ``launch`` mechanism (|LANG| extension to |TS|) +is recommended for multitasking. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + async function sum(numbers: number[]): Promise { + let sum = 0 + for (let num of numbers) { + sum += await num + } + return sum + } + + ... + const result = await sum(5, 10) + ... + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function sum(numbers: number[]): number { + let sum = 0 + for (let i = 0; i < numbers.length; ++i) { + sum += numbers[i] + } + return sum + } + + ... + const result = launch sum(5, 10) // `result` will be of type `Promise` + ... + +NOT recommended: + +.. code-block:: typescript + + async function sum(numbers: number[]): Promise { + let sum = 0 + for (let i = 0; i < numbers.length; ++i) { + sum += await numbers[i] + } + return sum + } + + ... + const result = sum(5, 10) + ... + +.. _R096: + +|CB_R| #96: Type guarding is supported with ``instanceof`` and ``as`` +--------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the ``is`` operator, which must be replaced by the +``instanceof`` operator. Note that the fields of an object must be cast to the +appropriate type with the ``as`` operator before use. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Foo { + foo: number = 0 + common: string = "" + } + + class Bar { + bar: number = 0 + common: string = "" + } + + function isFoo(arg: any): arg is Foo { + return arg.foo !== undefined + } + + function doStuff(arg: Foo | Bar) { + if (isFoo(arg)) { + console.log(arg.foo) // OK + console.log(arg.bar) // Error! + } + else { + console.log(arg.foo) // Error! + console.log(arg.bar) // OK + } + } + + doStuff({ foo: 123, common: '123' }) + doStuff({ bar: 123, common: '123' }) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Foo { + foo: number = 0 + common: string = "" + } + + class Bar { + bar: number = 0 + common: string = "" + } + + function isFoo(arg: Object): boolean { + return arg instanceof Foo + } + + function doStuff(arg: Object): void { + if (isFoo(arg)) { + let fooArg = arg as Foo + console.log(fooArg.foo) // OK + console.log(arg.bar) // Error! + } + else { + let barArg = arg as Bar + console.log(arg.foo) // Error! + console.log(barArg.bar) // OK + } + } + + function main(): void { + doStuff(new Foo()) + doStuff(new Bar()) + } + +.. _R097: + +|CB_R| #97: `keyof` operator is not supported +--------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| has no `keyof` operator because the object layout is defined +at compile time and cannot be changed at runtime. Object fields can only be +accessed directly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Point { + x: number = 1 + y: number = 2 + } + + type PointKeys = keyof Point // The type of PointKeys is "x" | "y" + + function getPropertyValue(obj: Point, key: PointKeys) { + return obj[key] + } + + let obj = new Point() + console.log(getPropertyValue(obj, "x")) // prints "1" + console.log(getPropertyValue(obj, "y")) // prints "2" + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Point { + x: number = 1 + y: number = 2 + } + + function getPropertyValue(obj: Point, key: string): number { + if (key.equals("x")) { + return obj.x + } + if (key.equals("y")) { + return obj.y + } + throw new Error() // No such property + return 0 + } + + function main(): void { + let obj = new Point() + console.log(getPropertyValue(obj, "x")) // prints "1" + console.log(getPropertyValue(obj, "y")) // prints "2" + } + +.. _R098: + +|CB_R| #98: Spreading an array into function arguments is not supported +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the spread operator. +"Unpack" data from an array to a callee manually. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + function foo(x, y, z) {} + + let args = [0, 1, 2] + foo(...args) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + function foo(x: number, y: number, z: number): void {} + + function main(): void { + let args: number[] = [0, 1, 2] + foo(args[0], args[1], args[2]) + } + +.. _R099: + +|CB_R| #99: Spread operator is not supported +-------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the spread operator. +"Unpack" data from arrays indices manually where necessary. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + let list = [1, 2] + list = [...list, 3, 4] + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let list: number[] = [1, 2] + list = [list[0], list[1], 3, 4] + +.. _R100: + +|CB_R| #100: Spreading an object is not supported +--------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the spread operator. +"Unpack" data from an object to a callee manually, field by field. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + const point2d = {x: 1, y: 2} + const point3d = {...point2d, z: 3} + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Point2D { + x: number + y: number + + constructor(x: number, y: number) { + this.x = x + this.y = y + } + } + + class Point3D { + x: number + y: number + z: number + + constructor(x: number, y: number, z: number) { + this.x = x + this.y = y + this.z = z + } + } + + function main(): void { + const point2d = new Point2D(1, 2) + const point3d = new Point3D(point2d.x, point2d.y, 3) + } + +|CB_R| #101: Interfaces with optional properties and call signatures are not supported +-------------------------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support interfaces with optional properties and interfaces +with call signatures. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + // Interface with optional properties + interface Person { + firstName: string + lastName: string + age?: number + } + + // Interface with call signature + interface Greet { + (name: string): string + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + // Use nullable type instead of optional property + interface Person { + firstName: string + lastName: string + age: number | null + } + + // Use a method signature instead of call signature + interface Greet { + action (name: string): string + } + + + +|CB_R| #102: Interface declarations (extends same property) +----------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not allow an interface to contain two methods with signatures that +are not distinguishable, e.g., two methods that have the same parameter lists +but different return types. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + interface Mover { + getStatus(): { speed: number } + } + interface Shaker { + getStatus(): { frequency: number } + } + + interface MoverShaker extends Mover, Shaker { + getStatus(): { speed: number; frequency: number } + } + + class C implements MoverShaker { + private speed: number = 0 + private frequency: number = 0 + + getStatus() { + return { speed: this.speed, frequency: this.frequency } + } + } + +In |TS|, an interface that extends ``Mover`` and ``Shaker`` must declare a +new ``getStatus`` with a combined result type. It is not allowed in |LANG|. + +.. _R103: + +|CB_R| #103: Declaration merging is not supported +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support merging declratations. All definitions of classes, +interfaces and so on must be kept compact in the code base. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + interface Document { + createElement(tagName: any): Element + } + + interface Document { + createElement(tagName: string): HTMLElement + } + + interface Document { + createElement(tagName: number): HTMLDivElement + createElement(tagName: boolean): HTMLSpanElement + createElement(tagName: string, value: number): HTMLCanvasElement + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface Document { + createElement(tagName: number): HTMLDivElement + createElement(tagName: boolean): HTMLSpanElement + createElement(tagName: string, value: number): HTMLCanvasElement + createElement(tagName: string): HTMLElement + createElement(tagName: Object): Element + } + +.. _R104: + +|CB_R| #104: Interfaces cannot extend classes +--------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support interfaces that extend classes. Interfaces can extend +only interfaces. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Control { + state: number = 0 + } + + interface SelectableControl extends Control { + select(): void + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + interface Control { + state: number = 0 + } + + interface SelectableControl extends Control { + select(): void + } + +.. _R105: + +|CB_R| #105: Property-based runtime type checks are not supported +----------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| requires that object layout is determined in compile-time and cannot +be changed at runtime. There for no runtime property-based checks are supported. +If you need to do a type cast, use ``as`` operator and use desired properties +and methods. If some property doesn't exist then an attempt to reference it +will result in a compile-time error. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class A { + foo() {} + bar() {} + } + + function getSomeObject() { + return new A() + } + + let obj: any = getSomeObject() + if (obj && obj.foo && obj.bar) { + console.log("Yes") // prints "Yes" in this example + } else { + console.log("No") + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class A { + foo(): void {} + bar(): void {} + } + + function getSomeObject(): A { + return new A() + } + + function main(): void { + let tmp: Object = getSomeObject() + let obj: A = tmp as A + obj.foo() // OK + obj.bar() // OK + obj.some_foo() // Compile-time error: Method some_foo does not exist on this type + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R052` +* :ref:`R059` +* :ref:`R060` +* :ref:`R066` +* :ref:`R109` + +.. _R106: + +|CB_R| #106: Constructor function type is not supported +------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the usage of the constructor function type. +Use lambdas instead, as they can be generalized to several types of objects. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Person { + constructor( + name: string, + age: number + ) {} + } + + type PersonConstructor = new (name: string, age: number) => Person + + function createPerson(Ctor: PersonConstructor, name: string, age: number): Person { + return new Ctor(name, age) + } + + const person = createPerson(Person, 'John', 30) + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Person { + constructor( + name: string, + age: number + ) {} + } + + let PersonConstructor: (name: string, age: number): Person = (name: string, age: number): Person => { + return new Person(name, age) + } + + function createPerson(Ctor: (name: string, age: number): Person, name: string, age: number): Person { + return PersonConstructor(name, age) + } + + function main(): void { + const person = createPerson(PersonConstructor, "John", 30) + } + +.. _R107: + +|CB_R| #107: Constructor declarations +------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support optional parameters in constructors. +Constructors are not inherited from a superclass to a subclass. Use overloading +constructors instead of constructors with optional parameters: + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + class Foo { + constructor(bar: string = 'default', baz?: number) {} + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + class Foo { + constructor(bar: string) {} + constructor(bar: string, baz: number) {} + } + +|CB_RULE| +~~~~~~~~~ + +In |LANG|, constructors are not inherited from a superclass. + +|CB_BAD| +~~~~~~~~ + +The constructor defined in a superclass can be used in a subclass. + +.. code:: typescript + + class C1 { + constructor(bar: string, baz: number) {} + } + class C2 extends Foo {} + + let c = C2("a", "b") + +|CB_OK| +~~~~~~~ + +A subclass must define its own constructor. + +.. code:: typescript + + class C1 { + constructor(bar: string, baz: number) {} + } + class C2 extends Foo { + constructor(bar: string, baz: number) { + super(bar, string) + } + } + + let c = C2("a", "b") + +|CB_SEE| +~~~~~~~~ + +* :ref:`R015` + +.. _R108: + +|CB_R| #108: Overloaded constructors with shared body are not supported +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support sharing a body between function overloads. +The shared body feature for ``constructor`` is not supported, either. +Overload constructor with a separate body for each signature. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string + age: number + + constructor(name: string, age?: number) { + this.name = name + if (age) { + this.age = age + } else { + this.age = 0 + } + } + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string + age: number + + constructor(name: string, age: number) { + this.name = name + this.age = age + } + + constructor(name: string) { + this.name = name + this.age = 0 + } + } + +.. _R109: + +|CB_R| #109: Dynamic property declaration is not supported +---------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support dynamic property declaration. All object properties must +be declared immediately in the class. While it can be replaced with an array +of objects, it is still better to adhere to the static language paradigm and +declare fields, their names and types explicitly. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string = "" + age: number = 0 + [key: string]: string | number + } + + const person: Person = { + name: "John", + age: 30, + email: "john@example.com", + phone: 1234567890, + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + class Person { + name: string + age: number + email: string + phone: number + + constructor(name: string, age: number, email: string, phone: number) { + this.name = name + this.age = age + this.email = email + this.phone = phone + } + } + + function main(): void { + const person: Person = new Person("John", 30, "john@example.com", 1234567890) + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R001` +* :ref:`R002` +* :ref:`R052` +* :ref:`R059` +* :ref:`R060` +* :ref:`R066` +* :ref:`R105` + +.. _R111: + +|CB_R| #111: Explicit values for enumeration constants are not supported +------------------------------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +Currently, |LANG| does not support assigning explicit values for ``enums``. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + enum E { + A, + B, + C = 10, + D + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + enum E { + A, + B, + C = 10, // Compile-time error: assigning out of order values for enums is not supported + D + } + + enum E_fixed { + A, + B, + C, // OK + D + } + +.. _R112: + +.. _R113: + +|CB_R| #113: ``enum`` declaration merging is not supported +---------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support merging declratations for ``enum``. +The declaration of each ``enum`` must be kept compact in the code base. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + enum Color { + RED, + GREEN + } + enum Color { + YELLOW + } + enum Color { + BLACK, + BLUE + } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + enum Color { + RED, + GREEN, + YELLOW, + BLACK, + BLUE + } + +.. _R114: + +|CB_R| #114: Namespaces cannot be used as objects +------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support the usage of namespaces as objects. +Classes or modules can be interpreted as analogues of namespaces. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + namespace MyNamespace { + export let x: number + } + + let m = MyNamespace + m.x = 2 + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + namespace MyNamespace { + export let x: number + } + + MyNamespace.x = 2 + +.. _R115: + +|CB_R| #115: Scripts and modules +-------------------------------- + +|CB_RULE| +~~~~~~~~~ + +In general, scripts and modules in |LANG| are very close to |TS|. +Differences are described in separate recipes. + +|CB_SEE| +~~~~~~~~ + +* :ref:`R117` +* :ref:`R118` +* :ref:`R119` +* :ref:`R120` +* :ref:`R121` +* :ref:`R122` +* :ref:`R123` +* :ref:`R124` +* :ref:`R125` +* :ref:`R126` + +.. _R116: + +|CB_R| #116: Non-declaration statements in namespaces are not supported +----------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support statements in namespaces. Use a function to exectute statements. + +|CB_BAD| +~~~~~~~~~ + +.. code:: typescript + + namespace A { + export let x: number + x = 1 + } + +|CB_OK| +~~~~~~~~~ + +Initialization function should be called to execute statements. + +.. code:: typescript + + namespace A { + export let x: number + + export function init() { + x = 1 + } + } + A.init() + + +.. _R117: + +|CB_R| #117: Statement as top-level element +------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support statements as top-level elements. Statements must be +placed in a block ``{}``. + +|CB_BAD| +~~~~~~~~~ + +.. code:: typescript + + let a = 1 + let b = 2 + if (b == a) { + console.log("a EQ b") + } else { + console.log("a NEQ b") + } + +|CB_OK| +~~~~~~~~~ + +.. code:: typescript + + // A block can be a top-level element, + // put statements inside one or several blocks: + { + let a = 1 + let b = 2 + } + + { + if (b == a) { + console.log("a EQ b") + } else { + console.log("a NEQ b") + } + } + + +.. _R118: + +|CB_R| #118: Special import type declarations are not supported +--------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not have a special notation for importing types. +Use ordinary import instead. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + // Re-using the same import + import { APIResponseType } from "./api" + + // Explicitly use import type + import type { APIResponseType } from "./api" + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + import { APIResponseType } from "./api" + +|CB_SEE| +~~~~~~~~ + +* :ref:`R119` +* :ref:`R120` +* :ref:`R121` + +.. _R119: + +|CB_R| #119: Importing a module for side-effects only is not supported +---------------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support global variables like ``window`` to avoid +side-effects during module importing. All variables marked as export can be +accessed through the ``*`` syntax. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + // === module at "path/to/module.ts" + export const EXAMPLE_VALUE = 42 + + // Set a global variable + window.MY_GLOBAL_VAR = "Hello, world!" + + // ==== using this module: + import "path/to/module" + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + import * from "path/to/module" + +.. _R120: + +|CB_R| #120: ``import default as ...`` is not supported +------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``import default as ...`` syntax. +Use explicit ``import ... from ...`` instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + import { default as d } from "mod" + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + import d from "mod" + +|CB_SEE| +~~~~~~~~ + +* :ref:`R122` + +.. _R121: + +|CB_R| #121: ``require`` is not supported +----------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support importing via ``require``. Use ``import`` instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + import m = require("mod") + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + import * as m from "mod" + +.. _R122: + +|CB_R| #122: ``export default`` is not supported +------------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``export default``. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // file1.ts + export default class MyClass { + // ... + } + + // file2.ts + // Can write just `MyClass` instead of `{ MyClass }` in case of default export + import MyClass from './file1' + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // module1 + export class MyClass { + // ... + } + + // module2 + // Use explicit name in import + import { MyClass } from "./module1" + +|CB_SEE| +~~~~~~~~ + +* :ref:`R120` + +.. _R123: + +|CB_R| #123: Renaming in export declarations is not supported +------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support renaming in export declarations. Similar effect +can be achieved through setting an alias for the exported entity. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // file1.ts + class MyClass { + // ... + } + + export { MyClass as RenamedClass } + + // file2.ts + import { RenamedClass } from "./file1" + + function main(): void { + const myObject = new RenamedClass() + // ... + } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // module1 + class MyClass { + // ... + } + + export RenamedClass = MyClass + + // module2 + import RenamedClass from "./module1" + + function main(): void { + const myObject = new RenamedClass() + // ... + } + +|CB_SEE| +~~~~~~~~ + +* :ref:`R124` +* :ref:`R125` +* :ref:`R126` + +.. _R124: + +|CB_R| #124: Export list declaration is not supported +----------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support syntax of export list declarations. All exported +entities must be explicitly annotated with the ``export`` keyword. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + export { x } + export { x } from "mod" + export { x, y as b, z as c } + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + let x = 1 + class MyClass {} + export let y = x, z: number = 2 + export RenamedClass = MyClass + +|CB_SEE| +~~~~~~~~ + +* :ref:`R123` +* :ref:`R125` +* :ref:`R126` + +.. _R125: + +|CB_R| #125: Re-exporting is not supported +------------------------------------------ + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support re-exporting. All desired entities must be +imported explicitly from the modules that export them. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // module1 + export class MyClass { + // ... + } + + // module2 + export { MyClass } from "module1" + + // consumer module + import { MyClass } from "module2" + + const myInstance = new MyClass() + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // module1 + export class MyClass { + // ... + } + + // module2 + // some stuff + + // consumer module + import MyClass from "module1" + import * from "module2" + + const myInstance = new MyClass() + +|CB_SEE| +~~~~~~~~ + +* :ref:`R123` +* :ref:`R124` +* :ref:`R126` + +.. _R126: + +|CB_R| #126: ``export = ...`` assignment is not supported +--------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not support ``export = ...`` syntax. +Use regular ``export`` / ``import`` instead. + +|CB_BAD| +~~~~~~~~ + +.. code-block:: typescript + + // module1 + export = Point + + class Point { + constructor(x: number, y: number) {} + static origin = new Point(0, 0) + } + + // module2 + import Pt = require("module1") + + let p = Pt.origin + +|CB_OK| +~~~~~~~ + +.. code-block:: typescript + + // module1 + export class Point { + constructor(x: number, y: number) {} + static origin = new Point(0, 0) + } + + // module2 + import * as Pt from "module1" + + let p = Pt.origin + +|CB_SEE| +~~~~~~~~ + +* :ref:`R123` +* :ref:`R124` +* :ref:`R125` + + +.. _R127: + +|CB_R| #127: Special export type declarations are not supported +--------------------------------------------------------------- + +|CB_RULE| +~~~~~~~~~ + +|LANG| does not have a special notation for exporting types. +Use ordinary export instead. + +|CB_BAD| +~~~~~~~~ + +.. code:: typescript + + class C {} + export type { C } + +|CB_OK| +~~~~~~~ + +.. code:: typescript + + export class C {} + diff --git a/linter/src/main.ts b/linter/src/main.ts new file mode 100644 index 000000000..8de6495ce --- /dev/null +++ b/linter/src/main.ts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { run } from "./LinterRunner"; + +run(); \ No newline at end of file diff --git a/linter/test/array_literals.ts b/linter/test/array_literals.ts new file mode 100644 index 000000000..9331b802b --- /dev/null +++ b/linter/test/array_literals.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class C { + a: any; + b: any[]; + c: [number, number]; + d: number[]; +} + +function array_literals(): void { + // Variable declaration + let a = [1, 2]; // NOT OK + let b: any = [3, 4]; // NOT OK + let c: any[] = [5, 6]; // OK + let d: [number, number] = [7, 8]; // NOT OK + let e: number[] = [9, 10]; // OK + let f = [1, "x", true]; // NOT OK + let g: Object[] = [2, "y", false]; // OK + + let h: C = { + a: [1, 2], // NOT OK + b: [3, 4], // OK + c: [5, 6], // NOT OK + d: [7, 8] // OK + }; + + let x = [1, 2, 3][1]; // NOT OK + + // Assignment + a = [1, 2]; // OK (at this point, variable is known to be the 'number[]' type) + b = [3, 4]; // NOT OK + c = [5, 6]; // OK + d = [7, 8]; // NOT OK + e = [9, 10]; // OK + f = [1, "x", true]; // NOT OK + g = [2, "y", false]; // OK + + h = { + a: [1, 2], // NOT OK + b: [3, 4], // OK + c: [5, 6], // NOT OK + d: [7, 8] // OK + }; + + // Default parameter value + function foo(x = [1, 2]) { } // NOT OK + function foo2(x: any = [3, 4]) { } // NOT OK + function foo3(x: any[] = [5, 6]) { } // OK + function foo4(x: [number, number] = [7, 8]) { } // NOT OK + function foo5(x: number[] = [9, 10]) { } // OK + + // Function call + foo([1, 2]); // OK + foo2([3, 4]); // NOT OK + foo3([5, 6]); // OK + foo4([7, 8]); // NOT OK + foo5([9, 10]); // OK + + // Return from function + function bar() { return [1, 2]; } // NOT OK + function bar2(): any { return [3, 4]; } // NOT OK + function bar3(): any[] { return [5, 6]; } // OK + function bar4(): [number, number] { return [7, 8]; } // NOT OK + function bar5(): number[] { return [9, 10]; } // OK + + // In ternary operator + let condition = true; + a = (condition) ? [1, 2] : [3, 4]; // OK + b = (condition) ? [5, 6] : [7, 8]; // NOT OK + c = (condition) ? [9, 10] : [11, 12]; // OK + d = (condition) ? [13, 14] : [15, 16]; // NOT OK + e = (condition) ? [17, 18] : [19, 20]; // OK +} \ No newline at end of file diff --git a/linter/test/array_literals.ts.relax.json b/linter/test/array_literals.ts.relax.json new file mode 100644 index 000000000..1b56a4bfb --- /dev/null +++ b/linter/test/array_literals.ts.relax.json @@ -0,0 +1,78 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 8, + "problem": "AnyType" + }, + { + "line": 18, + "column": 8, + "problem": "AnyType" + }, + { + "line": 19, + "column": 8, + "problem": "TupleType" + }, + { + "line": 26, + "column": 12, + "problem": "AnyType" + }, + { + "line": 27, + "column": 12, + "problem": "AnyType" + }, + { + "line": 28, + "column": 12, + "problem": "TupleType" + }, + { + "line": 60, + "column": 22, + "problem": "AnyType" + }, + { + "line": 61, + "column": 22, + "problem": "AnyType" + }, + { + "line": 62, + "column": 22, + "problem": "TupleType" + }, + { + "line": 74, + "column": 22, + "problem": "AnyType" + }, + { + "line": 75, + "column": 22, + "problem": "AnyType" + }, + { + "line": 76, + "column": 22, + "problem": "TupleType" + } + ] +} \ No newline at end of file diff --git a/linter/test/array_literals.ts.strict.json b/linter/test/array_literals.ts.strict.json new file mode 100644 index 000000000..cd2f6722b --- /dev/null +++ b/linter/test/array_literals.ts.strict.json @@ -0,0 +1,278 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 8, + "problem": "AnyType" + }, + { + "line": 18, + "column": 8, + "problem": "AnyType" + }, + { + "line": 19, + "column": 8, + "problem": "TupleType" + }, + { + "line": 25, + "column": 13, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 26, + "column": 12, + "problem": "AnyType" + }, + { + "line": 26, + "column": 18, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 27, + "column": 12, + "problem": "AnyType" + }, + { + "line": 28, + "column": 12, + "problem": "TupleType" + }, + { + "line": 28, + "column": 31, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 30, + "column": 13, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 34, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 36, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 40, + "column": 13, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 44, + "column": 9, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 46, + "column": 9, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 48, + "column": 9, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 52, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 54, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 59, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 59, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 59, + "column": 22, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 60, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 60, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 60, + "column": 22, + "problem": "AnyType" + }, + { + "line": 60, + "column": 28, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 61, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 61, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 61, + "column": 22, + "problem": "AnyType" + }, + { + "line": 62, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 62, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 62, + "column": 22, + "problem": "TupleType" + }, + { + "line": 62, + "column": 41, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 63, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 63, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 67, + "column": 10, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 69, + "column": 10, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 73, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 73, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 73, + "column": 29, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 74, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 74, + "column": 22, + "problem": "AnyType" + }, + { + "line": 74, + "column": 35, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 75, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 75, + "column": 22, + "problem": "AnyType" + }, + { + "line": 76, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 76, + "column": 22, + "problem": "TupleType" + }, + { + "line": 76, + "column": 48, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 77, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 82, + "column": 23, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 82, + "column": 32, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 84, + "column": 23, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 84, + "column": 34, + "problem": "ArrayLiteralNoContextType" + } + ] +} \ No newline at end of file diff --git a/linter/test/bigint.ts b/linter/test/bigint.ts new file mode 100644 index 000000000..51c67878c --- /dev/null +++ b/linter/test/bigint.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const oneHundred: bigint = BigInt(100); +const anotherHundred: bigint = 100n; +const bi = 200n; + +console.log(oneHundred); +console.log(anotherHundred); +console.log(bi); \ No newline at end of file diff --git a/linter/test/bigint.ts.relax.json b/linter/test/bigint.ts.relax.json new file mode 100644 index 000000000..a9ab135f6 --- /dev/null +++ b/linter/test/bigint.ts.relax.json @@ -0,0 +1,53 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 19, + "problem": "BigIntType" + }, + { + "line": 17, + "column": 23, + "problem": "BigIntType" + }, + { + "line": 17, + "column": 32, + "problem": "BigIntLiteral" + }, + { + "line": 18, + "column": 12, + "problem": "BigIntLiteral" + }, + { + "line": 20, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 21, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/bigint.ts.strict.json b/linter/test/bigint.ts.strict.json new file mode 100644 index 000000000..a9ab135f6 --- /dev/null +++ b/linter/test/bigint.ts.strict.json @@ -0,0 +1,53 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 19, + "problem": "BigIntType" + }, + { + "line": 17, + "column": 23, + "problem": "BigIntType" + }, + { + "line": 17, + "column": 32, + "problem": "BigIntLiteral" + }, + { + "line": 18, + "column": 12, + "problem": "BigIntLiteral" + }, + { + "line": 20, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 21, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/binary_wrong_types.ts b/linter/test/binary_wrong_types.ts new file mode 100644 index 000000000..edab7a266 --- /dev/null +++ b/linter/test/binary_wrong_types.ts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function gets() : string { + return "ss"; +} + +let b0 = true; + +let c0 = b0 && true; +let c1 = true && "3"; +let c2 = gets() && false; +let c3 = 5 && 6; + +let d0 = false || b0; +let d1 = (~"3" ) || true ; +let d2 = false || gets(); +let d3 = 4 || 5; + + +console.log(c1); +console.log(c2); +console.log(c3); +console.log(d1); +console.log(d2); +console.log(d3); + + + +let varAny: any = null; + +let add0 = 2 + 2; +let add1 = "2" + "2" +let add2 = "2" + varAny; +let add3 = varAny + "2"; +let add4 = varAny + 2; +let add5 = 6 + varAny; +let add6 = "2" + 2; +let add7 = 2 + "2"; + + +enum Const { PI = 3.14, E = 2.7818 } +enum State { OK = "ok", FAULT = "fail" } + + +let b1 = 7 ^ varAny; +let b2 = 7 | varAny; +let b3 = 7 & varAny; + +let b4 = 7 << varAny; +let b5 = 7 >> varAny; +let b6 = 7 >>> varAny; + +let b7 = varAny <<1; +let b8 = varAny >>2; +let b9 = varAny >>>3; + +let b11 = 7 ^ Const.PI +let b12 = 7 | Const.E; +let b13 = 7 & Const.PI; + +let b14 = 7 << Const.PI; +let b15 = 7 >> Const.E; +let b16 = 7 >>> Const.PI; + +let b17 = Const.PI <<1; +let b18 = Const.E >>2; +let b19 = Const.PI >>>3; + + +let b31 = State.OK ^ 7 +let b32 = 7 | State.FAULT; +let b33 = 7 & State.OK; + +let b34 = 7 << State.OK; +let b35 = 7 >> State.FAULT; +let b36 = 7 >>> State.OK; + +let b37 = State.FAULT <<1; +let b38 = State.OK >>2; +let b39 = State.FAULT >>>3; + + +let a000 = (k = 10,2+7); diff --git a/linter/test/binary_wrong_types.ts.relax.json b/linter/test/binary_wrong_types.ts.relax.json new file mode 100644 index 000000000..b025bc902 --- /dev/null +++ b/linter/test/binary_wrong_types.ts.relax.json @@ -0,0 +1,213 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 24, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 25, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 28, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 28, + "column": 11, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 29, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 30, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 33, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 34, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 37, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 38, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 13, + "problem": "AnyType" + }, + { + "line": 48, + "column": 12, + "problem": "AddWithWrongType" + }, + { + "line": 49, + "column": 12, + "problem": "AddWithWrongType" + }, + { + "line": 54, + "column": 14, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 54, + "column": 25, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 55, + "column": 14, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 55, + "column": 25, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 58, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 59, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 60, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 62, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 63, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 64, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 66, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 67, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 68, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 83, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 84, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 85, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 87, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 88, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 89, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 91, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 92, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 93, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 96, + "column": 13, + "problem": "CommaOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/binary_wrong_types.ts.strict.json b/linter/test/binary_wrong_types.ts.strict.json new file mode 100644 index 000000000..b025bc902 --- /dev/null +++ b/linter/test/binary_wrong_types.ts.strict.json @@ -0,0 +1,213 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 24, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 25, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 28, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 28, + "column": 11, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 29, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 30, + "column": 10, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 33, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 34, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 37, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 38, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 13, + "problem": "AnyType" + }, + { + "line": 48, + "column": 12, + "problem": "AddWithWrongType" + }, + { + "line": 49, + "column": 12, + "problem": "AddWithWrongType" + }, + { + "line": 54, + "column": 14, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 54, + "column": 25, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 55, + "column": 14, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 55, + "column": 25, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 58, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 59, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 60, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 62, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 63, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 64, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 66, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 67, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 68, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 83, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 84, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 85, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 87, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 88, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 89, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 91, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 92, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 93, + "column": 11, + "problem": "BitOpWithWrongType" + }, + { + "line": 96, + "column": 13, + "problem": "CommaOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/catch_clause.ts b/linter/test/catch_clause.ts new file mode 100644 index 000000000..b86003988 --- /dev/null +++ b/linter/test/catch_clause.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +try { + if (true) throw "Catch with 'any' type"; +} +catch(e : any) { + console.log(e); +} + +try { + if (true) + throw "Catch with 'unknown' type"; +} +catch(e : unknown) { + console.log(e); +} + +try { + if (true) + throw "Catch without explicit type"; +} +catch(e) { + console.log(e); +} \ No newline at end of file diff --git a/linter/test/catch_clause.ts.relax.json b/linter/test/catch_clause.ts.relax.json new file mode 100644 index 000000000..7ba4546e9 --- /dev/null +++ b/linter/test/catch_clause.ts.relax.json @@ -0,0 +1,43 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 19, + "column": 11, + "problem": "AnyType" + }, + { + "line": 23, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 27, + "column": 11, + "problem": "UnknownType" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/catch_clause.ts.strict.json b/linter/test/catch_clause.ts.strict.json new file mode 100644 index 000000000..342c43483 --- /dev/null +++ b/linter/test/catch_clause.ts.strict.json @@ -0,0 +1,68 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 17, + "column": 13, + "problem": "ThrowStatement" + }, + { + "line": 19, + "column": 1, + "problem": "CatchWithUnsupportedType" + }, + { + "line": 19, + "column": 11, + "problem": "AnyType" + }, + { + "line": 23, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 25, + "column": 5, + "problem": "ThrowStatement" + }, + { + "line": 27, + "column": 1, + "problem": "CatchWithUnsupportedType" + }, + { + "line": 27, + "column": 11, + "problem": "UnknownType" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 33, + "column": 5, + "problem": "ThrowStatement" + } + ] +} \ No newline at end of file diff --git a/linter/test/class_static_block.ts b/linter/test/class_static_block.ts new file mode 100644 index 000000000..6e30dd6a2 --- /dev/null +++ b/linter/test/class_static_block.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class C { + static s: string; + static { + C.s = "string"; + } + + static n: number; + static { + C.n = C.s.length; + } +} + +class B { + static s: string; + static + { + C.s = "string"; + } + + static n: number; +} diff --git a/linter/test/class_static_block.ts.relax.json b/linter/test/class_static_block.ts.relax.json new file mode 100644 index 000000000..c260ac84c --- /dev/null +++ b/linter/test/class_static_block.ts.relax.json @@ -0,0 +1,21 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "http://www.apache.org/licenses/LICENSE-2.0", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 4, + "problem": "MultipleStaticBlocks" + } + ] +} \ No newline at end of file diff --git a/linter/test/class_static_block.ts.strict.json b/linter/test/class_static_block.ts.strict.json new file mode 100644 index 000000000..c260ac84c --- /dev/null +++ b/linter/test/class_static_block.ts.strict.json @@ -0,0 +1,21 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "http://www.apache.org/licenses/LICENSE-2.0", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 4, + "problem": "MultipleStaticBlocks" + } + ] +} \ No newline at end of file diff --git a/linter/test/conditional_types.ts b/linter/test/conditional_types.ts new file mode 100644 index 000000000..ba8519f2c --- /dev/null +++ b/linter/test/conditional_types.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Animal { + live(): void; +} +interface Dog extends Animal { + woof(): void; +} +type Example1 = Dog extends Animal ? number : string; // type Example1 = number +type Example2 = RegExp extends Animal ? number : string; // type Example2 = string + +interface IdLabel { + id: number /* some fields */; +} +interface NameLabel { + name: string /* other fields */; +} +type NameOrId = T extends number + ? IdLabel + : NameLabel; +function createLabel(idOrName: T): NameOrId { + throw "unimplemented"; +} +let a = createLabel("typescript"); // let a: NameLabel +let b = createLabel(2.8); // let b: IdLabel +let c = createLabel(Math.random() ? "hello" : 42); // let c: NameLabel | IdLabel + +type MessageOf = T extends { message: unknown } ? T["message"] : never; +interface Email { + message: string; +} +interface Dog { + bark(): void; +} +type EmailMessageContents = MessageOf; // type EmailMessageContents = string +type DogMessageContents = MessageOf; // type DogMessageContents = never + +type Flatten = T extends any[] ? T[number] : T; +type Str = Flatten; // type Str = string +type Num = Flatten; // type Num = number \ No newline at end of file diff --git a/linter/test/conditional_types.ts.relax.json b/linter/test/conditional_types.ts.relax.json new file mode 100644 index 000000000..7286adfa5 --- /dev/null +++ b/linter/test/conditional_types.ts.relax.json @@ -0,0 +1,93 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 19, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 22, + "column": 17, + "problem": "ConditionalType" + }, + { + "line": 23, + "column": 17, + "problem": "ConditionalType" + }, + { + "line": 31, + "column": 25, + "problem": "UnionType" + }, + { + "line": 31, + "column": 44, + "problem": "ConditionalType" + }, + { + "line": 34, + "column": 32, + "problem": "UnionType" + }, + { + "line": 41, + "column": 21, + "problem": "ConditionalType" + }, + { + "line": 41, + "column": 31, + "problem": "ObjectTypeLiteral" + }, + { + "line": 41, + "column": 42, + "problem": "UnknownType" + }, + { + "line": 41, + "column": 54, + "problem": "IndexedAccessType" + }, + { + "line": 41, + "column": 56, + "problem": "StringLiteralType" + }, + { + "line": 45, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 51, + "column": 19, + "problem": "ConditionalType" + }, + { + "line": 51, + "column": 29, + "problem": "AnyType" + }, + { + "line": 51, + "column": 37, + "problem": "IndexedAccessType" + } + ] +} \ No newline at end of file diff --git a/linter/test/conditional_types.ts.strict.json b/linter/test/conditional_types.ts.strict.json new file mode 100644 index 000000000..8a9ffe73c --- /dev/null +++ b/linter/test/conditional_types.ts.strict.json @@ -0,0 +1,113 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 19, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 22, + "column": 17, + "problem": "ConditionalType" + }, + { + "line": 23, + "column": 17, + "problem": "ConditionalType" + }, + { + "line": 31, + "column": 25, + "problem": "UnionType" + }, + { + "line": 31, + "column": 44, + "problem": "ConditionalType" + }, + { + "line": 34, + "column": 32, + "problem": "UnionType" + }, + { + "line": 35, + "column": 5, + "problem": "ThrowStatement" + }, + { + "line": 37, + "column": 9, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 38, + "column": 9, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 39, + "column": 9, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 41, + "column": 21, + "problem": "ConditionalType" + }, + { + "line": 41, + "column": 31, + "problem": "ObjectTypeLiteral" + }, + { + "line": 41, + "column": 42, + "problem": "UnknownType" + }, + { + "line": 41, + "column": 54, + "problem": "IndexedAccessType" + }, + { + "line": 41, + "column": 56, + "problem": "StringLiteralType" + }, + { + "line": 45, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 51, + "column": 19, + "problem": "ConditionalType" + }, + { + "line": 51, + "column": 29, + "problem": "AnyType" + }, + { + "line": 51, + "column": 37, + "problem": "IndexedAccessType" + } + ] +} \ No newline at end of file diff --git a/linter/test/constructor_types.ts b/linter/test/constructor_types.ts new file mode 100644 index 000000000..beefe3680 --- /dev/null +++ b/linter/test/constructor_types.ts @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface ClockInterface { + tick(): void; +} + +class DigitalClock implements ClockInterface { + constructor(h: number, m: number) {} + tick() { + console.log("beep beep"); + } +} + +class AnalogClock implements ClockInterface { + constructor(h: number, m: number) {} + tick() { + console.log("tick tock"); + } +} + +function constructorSignature(): void { + interface ClockConstructor { + new (hour: number, minute: number): ClockInterface; + } + + function createClock( + ctor: ClockConstructor, + hour: number, + minute: number + ): ClockInterface { + return new ctor(hour, minute); + } + + let digital = createClock(DigitalClock, 12, 17); + let analog = createClock(AnalogClock, 7, 32); +} + +function constructorType(): void { + function createClock( + ctor: new (hour: number, minute: number) => ClockInterface, + h: number, + m: number + ): ClockInterface { + return new ctor(h, m); + } + + let digital = createClock(DigitalClock, 16, 30); + let analog = createClock(AnalogClock, 23, 45); +} \ No newline at end of file diff --git a/linter/test/constructor_types.ts.relax.json b/linter/test/constructor_types.ts.relax.json new file mode 100644 index 000000000..97f6d1cac --- /dev/null +++ b/linter/test/constructor_types.ts.relax.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 36, + "column": 9, + "problem": "ConstructorType" + }, + { + "line": 53, + "column": 15, + "problem": "ConstructorType" + } + ] +} \ No newline at end of file diff --git a/linter/test/constructor_types.ts.strict.json b/linter/test/constructor_types.ts.strict.json new file mode 100644 index 000000000..178006f81 --- /dev/null +++ b/linter/test/constructor_types.ts.strict.json @@ -0,0 +1,48 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 29, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 36, + "column": 9, + "problem": "ConstructorType" + }, + { + "line": 39, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 52, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 53, + "column": 15, + "problem": "ConstructorType" + } + ] +} \ No newline at end of file diff --git a/linter/test/controlflow_non_boolean.ts b/linter/test/controlflow_non_boolean.ts new file mode 100644 index 000000000..b0cb233ab --- /dev/null +++ b/linter/test/controlflow_non_boolean.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function ifNonBooleanTest() { + let cond = 0; + if (cond) + console.log(cond); + + cond = 1; + if (cond) + console.log(cond); + + let cond2 : boolean = true; + if (cond2) + console.log(cond2); +} + +function whileNonBooleanTest() { + let cond = 0; + while(cond) { + console.log(cond); + } + + let cond2 : boolean = true; + while(cond2) { + console.log(cond2); + cond2 = false; + } + + let cond3 : string = ""; + do { + console.log(cond3); + } while (cond3); +} \ No newline at end of file diff --git a/linter/test/controlflow_non_boolean.ts.relax.json b/linter/test/controlflow_non_boolean.ts.relax.json new file mode 100644 index 000000000..abe414a31 --- /dev/null +++ b/linter/test/controlflow_non_boolean.ts.relax.json @@ -0,0 +1,38 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 22, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 32, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 45, + "column": 11, + "problem": "ObjectRuntimeCheck" + } + ] +} \ No newline at end of file diff --git a/linter/test/controlflow_non_boolean.ts.strict.json b/linter/test/controlflow_non_boolean.ts.strict.json new file mode 100644 index 000000000..ec8f7b439 --- /dev/null +++ b/linter/test/controlflow_non_boolean.ts.strict.json @@ -0,0 +1,68 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 18, + "column": 2, + "problem": "IfWithNonBoolean" + }, + { + "line": 18, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 22, + "column": 2, + "problem": "IfWithNonBoolean" + }, + { + "line": 22, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 30, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 32, + "column": 2, + "problem": "WhileWithNonBoolean" + }, + { + "line": 32, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 43, + "column": 2, + "problem": "DoWithNonBoolean" + }, + { + "line": 45, + "column": 11, + "problem": "ObjectRuntimeCheck" + } + ] +} \ No newline at end of file diff --git a/linter/test/delete_operator.ts b/linter/test/delete_operator.ts new file mode 100644 index 000000000..ff4bf0b2e --- /dev/null +++ b/linter/test/delete_operator.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +type T0 = { + field: any; +}; + +const f0 = (o : T0) => delete o.field; + +type T1 = { + field: unknown; +}; + +const f1 = (o : T1) => delete o.field; + +type T2 = { + field: never; +}; + +const f2 = (o : T2) => delete o.field; + +type T3 = { + field?: number; +}; + +const f3 = (o : T3) => delete o.field; + +type T4 = { + field : number; +}; + +const f4 = (o : T4) => delete o.field; \ No newline at end of file diff --git a/linter/test/delete_operator.ts.relax.json b/linter/test/delete_operator.ts.relax.json new file mode 100644 index 000000000..85474d673 --- /dev/null +++ b/linter/test/delete_operator.ts.relax.json @@ -0,0 +1,78 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 17, + "column": 10, + "problem": "AnyType" + }, + { + "line": 20, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 22, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 23, + "column": 10, + "problem": "UnknownType" + }, + { + "line": 26, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 28, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 32, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 34, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 38, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 40, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 44, + "column": 24, + "problem": "DeleteOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/delete_operator.ts.strict.json b/linter/test/delete_operator.ts.strict.json new file mode 100644 index 000000000..cf76d3597 --- /dev/null +++ b/linter/test/delete_operator.ts.strict.json @@ -0,0 +1,128 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 17, + "column": 10, + "problem": "AnyType" + }, + { + "line": 20, + "column": 12, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 20, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 20, + "column": 24, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 22, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 23, + "column": 10, + "problem": "UnknownType" + }, + { + "line": 26, + "column": 12, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 26, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 26, + "column": 24, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 28, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 32, + "column": 12, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 32, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 32, + "column": 24, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 34, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 38, + "column": 12, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 38, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 38, + "column": 24, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 40, + "column": 11, + "problem": "ObjectTypeLiteral" + }, + { + "line": 44, + "column": 12, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 44, + "column": 24, + "problem": "DeleteOperator" + }, + { + "line": 44, + "column": 24, + "problem": "ArrayLiteralNoContextType" + } + ] +} \ No newline at end of file diff --git a/linter/test/destructuring.ts b/linter/test/destructuring.ts new file mode 100644 index 000000000..26e6639b3 --- /dev/null +++ b/linter/test/destructuring.ts @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function destructuringParameters(): void { + function drawText({ text = "", position: [x, y] = [0, 0]}): void { + // Draw text + } + drawText({text: "Figure 1", position: [10, 20]}); + + function print([a, b]): void { + console.log(a, b); + } + print(["Hello", "Wolrd"]); + + const hello = ({firstName, lastName}: {firstName: string, lastName: string}): string => `Hello ${firstName} ${lastName}`; + console.log(hello({ firstName: 'Karl', lastName: 'Marks' })); + + const person = {firstName: 'Adam', lastName: 'Smith'}; + console.log(hello(person)); +} + +function destructuringAssignments(): void { + let a = 5, b = 10, c = "value"; + ({ b, c } = { b: 200, c: "bar" }); + [a, b] = [b, a]; + + let rest: number[]; + [a, b, ...rest] = [10, 20, 30, 40, 50]; + + let list = [1, 2]; + list = [...list, 3, 4]; + + let e: number, f: number; + let x: {e: number}; + ({ a, b: { c, d: [e, f]} } = {a: 10, b: { c: "foo", d: [30, 40]}}); + [a, b, [x, { f }]] = [1, 2, [{e: 20}, {f: 5}]]; +} + +function destructuringDeclarations(): void { + let {q, w, e} = {q: 1, w: "foo", e: true}; + + function getSomeObject() { + return {x: 1, y: 2} + } + let {x, y} = getSomeObject(); + + let [i, j, k] = [10, 20, 30]; + + let getArray = (): number[] => [1, 2, 3]; + let [a, b] = getArray(); +} + +function loopVariables(): void { + let objects: { a: number, b: string }[] = [ + {a: 10, b: "q"}, + {a: 20, b: "w"}, + {a: 30, b: "e"} + ]; + for (let {a, b} of objects) { + console.log(a, b); + } + + let arrays = [[1, 2], [3, 4], [5, 6]]; + for (const [q, w] of arrays) { + console.log(q, w); + } + + let a: number, b: string; + for ({a, b} of objects) { + console.log(a, b); + } + + let x: number, y: number; + for ([x, y] of arrays) { + console.log(x, y); + } + + const people = [ + { name: "Mike Smith", family: { mother: "Jane Smith", father: "Harry Smith", } }, + { name: "Tom Jones", family: { mother: "Norah Jones", father: "Richard Jones", } }, + ]; + let n: string, f: string; + for ({ name: n, family: { father: f } } of people) { + console.log(`Name: ${n}, Father: ${f}`); + }; +} \ No newline at end of file diff --git a/linter/test/destructuring.ts.relax.json b/linter/test/destructuring.ts.relax.json new file mode 100644 index 000000000..796c48304 --- /dev/null +++ b/linter/test/destructuring.ts.relax.json @@ -0,0 +1,58 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 23, + "problem": "DestructuringParameter" + }, + { + "line": 22, + "column": 20, + "problem": "DestructuringParameter" + }, + { + "line": 27, + "column": 20, + "problem": "DestructuringParameter" + }, + { + "line": 27, + "column": 43, + "problem": "ObjectTypeLiteral" + }, + { + "line": 40, + "column": 12, + "problem": "SpreadOperator" + }, + { + "line": 43, + "column": 13, + "problem": "SpreadOperator" + }, + { + "line": 46, + "column": 12, + "problem": "ObjectTypeLiteral" + }, + { + "line": 66, + "column": 18, + "problem": "ObjectTypeLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/destructuring.ts.strict.json b/linter/test/destructuring.ts.strict.json new file mode 100644 index 000000000..3542f6fda --- /dev/null +++ b/linter/test/destructuring.ts.strict.json @@ -0,0 +1,318 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 17, + "column": 23, + "problem": "DestructuringParameter" + }, + { + "line": 17, + "column": 55, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 20, + "column": 14, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 20, + "column": 43, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 22, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 22, + "column": 20, + "problem": "DestructuringParameter" + }, + { + "line": 25, + "column": 11, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 27, + "column": 20, + "problem": "DestructuringParameter" + }, + { + "line": 27, + "column": 43, + "problem": "ObjectTypeLiteral" + }, + { + "line": 27, + "column": 93, + "problem": "TemplateLiteral" + }, + { + "line": 28, + "column": 23, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 30, + "column": 20, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 36, + "column": 6, + "problem": "DestructuringAssignment" + }, + { + "line": 36, + "column": 17, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 37, + "column": 5, + "problem": "DestructuringAssignment" + }, + { + "line": 37, + "column": 14, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 40, + "column": 5, + "problem": "DestructuringAssignment" + }, + { + "line": 40, + "column": 12, + "problem": "SpreadOperator" + }, + { + "line": 40, + "column": 23, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 42, + "column": 16, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 43, + "column": 13, + "problem": "SpreadOperator" + }, + { + "line": 46, + "column": 12, + "problem": "ObjectTypeLiteral" + }, + { + "line": 47, + "column": 6, + "problem": "DestructuringAssignment" + }, + { + "line": 47, + "column": 34, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 47, + "column": 45, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 47, + "column": 60, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 48, + "column": 5, + "problem": "DestructuringAssignment" + }, + { + "line": 48, + "column": 26, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 48, + "column": 33, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 48, + "column": 34, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 48, + "column": 43, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 52, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 52, + "column": 21, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 54, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 54, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 55, + "column": 16, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 57, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 59, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 59, + "column": 21, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 62, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 66, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 67, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 68, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 69, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 71, + "column": 14, + "problem": "DestructuringDeclaration" + }, + { + "line": 75, + "column": 18, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 75, + "column": 19, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 75, + "column": 27, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 75, + "column": 35, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 76, + "column": 16, + "problem": "DestructuringDeclaration" + }, + { + "line": 81, + "column": 10, + "problem": "DestructuringAssignment" + }, + { + "line": 86, + "column": 10, + "problem": "DestructuringAssignment" + }, + { + "line": 90, + "column": 20, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 91, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 91, + "column": 39, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 92, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 92, + "column": 38, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 95, + "column": 10, + "problem": "DestructuringAssignment" + }, + { + "line": 96, + "column": 21, + "problem": "TemplateLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/for_stmts.ts b/linter/test/for_stmts.ts new file mode 100644 index 000000000..eea0fb802 --- /dev/null +++ b/linter/test/for_stmts.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +enum Mammals { + Humans = 'Humans', + Bats = 'Bats', + Dolphins = 'Dolphins', +} + +for(var m in Mammals) { + console.log(m) +} + +let someArray = [1, "string", false]; +for (let entry of someArray) { + console.log(entry); // 1, "string", false +} + +let list = [4, 5, 6]; +for (let i in list) { + console.log(i); // "0", "1", "2", +} + +for (let i of list) { + console.log(i); // 4, 5, 6 +} + +let s : string = "abc"; + +for(let c of s) { + console.log(c); +} + +for (let i in s) { + console.log(i); +} + +let arr = ['z', 'x', 'y']; + +for (let c of arr) { + console.log(c); +} + + +let i:number, j:number, k:number; +// legal 'comma' operator +for( i = 1, j = 2, k = 3; ( i * j * k ) > 0; i++, k--, j +=2 ) { + continue; +} +// illegal 'comma' operator +for( i = 1, (j=2,k=3); (i * j * k) > 0; i--, ( k++, j --)) { + continue; +} + diff --git a/linter/test/for_stmts.ts.relax.json b/linter/test/for_stmts.ts.relax.json new file mode 100644 index 000000000..2da6c4eb9 --- /dev/null +++ b/linter/test/for_stmts.ts.relax.json @@ -0,0 +1,103 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 18, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 19, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 22, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 46, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 52, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 59, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 63, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 63, + "column": 14, + "problem": "CommaOperator" + }, + { + "line": 63, + "column": 48, + "problem": "CommaOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/for_stmts.ts.strict.json b/linter/test/for_stmts.ts.strict.json new file mode 100644 index 000000000..2c29d306a --- /dev/null +++ b/linter/test/for_stmts.ts.strict.json @@ -0,0 +1,133 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 18, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 19, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 22, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 22, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 26, + "column": 17, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 27, + "column": 1, + "problem": "ForOfNonArray" + }, + { + "line": 31, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 1, + "problem": "ForOfNonArray" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 46, + "column": 1, + "problem": "ForInStatement" + }, + { + "line": 50, + "column": 11, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 52, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 59, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 63, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 63, + "column": 14, + "problem": "CommaOperator" + }, + { + "line": 63, + "column": 48, + "problem": "CommaOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/func_def_params.ts b/linter/test/func_def_params.ts new file mode 100644 index 000000000..a460412ed --- /dev/null +++ b/linter/test/func_def_params.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function foo(arg?: number) { + return arg; +} + +function bar(x : string, y?: number) { + return 3; +} + +function ff(a : number, s : string) { + return s; +} \ No newline at end of file diff --git a/linter/test/func_def_params.ts.relax.json b/linter/test/func_def_params.ts.relax.json new file mode 100644 index 000000000..cf8afb016 --- /dev/null +++ b/linter/test/func_def_params.ts.relax.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 14, + "problem": "FuncOptionalParams" + }, + { + "line": 20, + "column": 26, + "problem": "FuncOptionalParams" + } + ] +} \ No newline at end of file diff --git a/linter/test/func_def_params.ts.strict.json b/linter/test/func_def_params.ts.strict.json new file mode 100644 index 000000000..387eb3784 --- /dev/null +++ b/linter/test/func_def_params.ts.strict.json @@ -0,0 +1,43 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 16, + "column": 14, + "problem": "FuncOptionalParams" + }, + { + "line": 20, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 20, + "column": 26, + "problem": "FuncOptionalParams" + }, + { + "line": 24, + "column": 1, + "problem": "FuncWithoutReturnType" + } + ] +} \ No newline at end of file diff --git a/linter/test/func_def_type_params.ts b/linter/test/func_def_type_params.ts new file mode 100644 index 000000000..fd096c9b1 --- /dev/null +++ b/linter/test/func_def_type_params.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function identity(arg: T): T { + return arg; +} + +function foo() { + return 3; +} \ No newline at end of file diff --git a/linter/test/func_def_type_params.ts.relax.json b/linter/test/func_def_type_params.ts.relax.json new file mode 100644 index 000000000..b06227021 --- /dev/null +++ b/linter/test/func_def_type_params.ts.relax.json @@ -0,0 +1,17 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [] +} \ No newline at end of file diff --git a/linter/test/func_def_type_params.ts.strict.json b/linter/test/func_def_type_params.ts.strict.json new file mode 100644 index 000000000..a06bd5597 --- /dev/null +++ b/linter/test/func_def_type_params.ts.strict.json @@ -0,0 +1,33 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 20, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 20, + "column": 14, + "problem": "TypeParameterWithDefaultValue" + }, + { + "line": 20, + "column": 26, + "problem": "TypeParameterWithDefaultValue" + } + ] +} \ No newline at end of file diff --git a/linter/test/function_overload.ts b/linter/test/function_overload.ts new file mode 100644 index 000000000..fd91e0b4f --- /dev/null +++ b/linter/test/function_overload.ts @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function makeDate(timestamp: number): Date; +function makeDate(m: number, d: number, y: number): Date; +function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { + if (d !== undefined && y !== undefined) { + return new Date(y, mOrTimestamp, d); + } else { + return new Date(mOrTimestamp); + } +} +const d1 = makeDate(12345678); +const d2 = makeDate(5, 5, 5); + +function fn(x: string): string; +function fn(x: number): string; +function fn(x: string | number): string { + return "foo"; +} + +class C { + constructor(x: number, y: string); + constructor(s: string); + constructor(xs: any, y?: any) { } + + m(n: number): void; + m(s: string): void; + m(): void { } +} +let c = new C(10, "foo"); +c = new C("bar"); +c.m(100); +c.m("bazz"); + +abstract class AbstractClass { + abstract foo(n: number): void; + + bar(s: string): void { console.log(s); } + + abstract baz(s: string): void; // Overload + abstract baz(n: number): number; // Overload +} + +declare class DeclareClass { + constructor(); + + foo(): void; + + bar(s: string): number; + + baz(s: string): void; // Overload + baz(n: number): number; // Overload +} + +declare function foobar(n: number): void; // Overload +declare function foobar(s: string): string; // Overload + +declare function barbaz(b: boolean): void; + +namespace X { + function foo(x: number): void; // Overload + function foo(): void {} // Overload + + export function bar(s: string): string; // Overload + export function bar(n: number): string; // Overload + export function bar(arg: number | string): string { // Overload + return arg.toString(); + } +} + +function f(): void { + function localFun(n: number): void; + function localFun(s: string): void; + function localFun(): void {} +} +interface I { + foo(x: number): void; // Overload + foo(s:string): number; // Overload +} + +class StaticBlock { + static { + function foo(x: number): void; // Overload + function foo(s:string): void; // Overload + function foo(): void {} + } +} \ No newline at end of file diff --git a/linter/test/function_overload.ts.relax.json b/linter/test/function_overload.ts.relax.json new file mode 100644 index 000000000..b6876e273 --- /dev/null +++ b/linter/test/function_overload.ts.relax.json @@ -0,0 +1,218 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 17, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 28, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 29, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 30, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 68, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 69, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 41, + "problem": "FuncOptionalParams" + }, + { + "line": 18, + "column": 53, + "problem": "FuncOptionalParams" + }, + { + "line": 30, + "column": 16, + "problem": "UnionType" + }, + { + "line": 35, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 36, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 37, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 39, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 40, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 41, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 37, + "column": 21, + "problem": "AnyType" + }, + { + "line": 37, + "column": 30, + "problem": "AnyType" + }, + { + "line": 44, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 45, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 53, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 54, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 64, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 65, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 74, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 75, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 77, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 78, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 79, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 79, + "column": 30, + "problem": "UnionType" + }, + { + "line": 85, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 86, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 87, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 90, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 91, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 96, + "column": 9, + "problem": "FunctionOverload" + }, + { + "line": 97, + "column": 9, + "problem": "FunctionOverload" + }, + { + "line": 98, + "column": 9, + "problem": "FunctionOverload" + } + ] +} \ No newline at end of file diff --git a/linter/test/function_overload.ts.strict.json b/linter/test/function_overload.ts.strict.json new file mode 100644 index 000000000..87aefe781 --- /dev/null +++ b/linter/test/function_overload.ts.strict.json @@ -0,0 +1,248 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 17, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 28, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 29, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 30, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 68, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 69, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 41, + "problem": "FuncOptionalParams" + }, + { + "line": 18, + "column": 53, + "problem": "FuncOptionalParams" + }, + { + "line": 30, + "column": 16, + "problem": "UnionType" + }, + { + "line": 35, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 36, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 37, + "column": 5, + "problem": "ConstructorOverload" + }, + { + "line": 39, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 40, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 41, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 37, + "column": 21, + "problem": "AnyType" + }, + { + "line": 37, + "column": 30, + "problem": "AnyType" + }, + { + "line": 44, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 45, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 53, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 54, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 64, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 65, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 74, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 75, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 77, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 78, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 79, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 79, + "column": 30, + "problem": "UnionType" + }, + { + "line": 85, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 86, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 87, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 85, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 86, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 87, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 90, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 91, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 96, + "column": 9, + "problem": "FunctionOverload" + }, + { + "line": 97, + "column": 9, + "problem": "FunctionOverload" + }, + { + "line": 98, + "column": 9, + "problem": "FunctionOverload" + }, + { + "line": 96, + "column": 9, + "problem": "LocalFunction" + }, + { + "line": 97, + "column": 9, + "problem": "LocalFunction" + }, + { + "line": 98, + "column": 9, + "problem": "LocalFunction" + } + ] +} \ No newline at end of file diff --git a/linter/test/function_spread_arg.ts b/linter/test/function_spread_arg.ts new file mode 100644 index 000000000..81c091e15 --- /dev/null +++ b/linter/test/function_spread_arg.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function foo(x, y, z) { + console.log(x, y, z); + } + + var args = [0, "str", false]; + foo(...args); \ No newline at end of file diff --git a/linter/test/function_spread_arg.ts.relax.json b/linter/test/function_spread_arg.ts.relax.json new file mode 100644 index 000000000..2650d7f51 --- /dev/null +++ b/linter/test/function_spread_arg.ts.relax.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 21, + "column": 3, + "problem": "TopLevelStmt" + }, + { + "line": 21, + "column": 7, + "problem": "SpreadOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/function_spread_arg.ts.strict.json b/linter/test/function_spread_arg.ts.strict.json new file mode 100644 index 000000000..33c0e81a6 --- /dev/null +++ b/linter/test/function_spread_arg.ts.strict.json @@ -0,0 +1,43 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 20, + "column": 3, + "problem": "VarDeclaration" + }, + { + "line": 20, + "column": 14, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 21, + "column": 3, + "problem": "TopLevelStmt" + }, + { + "line": 21, + "column": 7, + "problem": "SpreadOperator" + } + ] +} \ No newline at end of file diff --git a/linter/test/functions.ts b/linter/test/functions.ts new file mode 100644 index 000000000..a95b5b286 --- /dev/null +++ b/linter/test/functions.ts @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function rest_spread() { + const arr = [1, 2, 3]; + function Test(a, ...t) { + console.log(a); // 1 + console.log(t[0]); // 2 + console.log(t[1]); // 3 + } + Test(1, ...arr); +} + + +class MyGenerator { + public *getValues() { // you can put the return type Generator, but it is ot necessary as ts will infer + let index = 1; + while(true) { + yield index; + index = index + 1; + + if (index > 10) { + break; + } + } + } +} + +function defaultTypeParam(i: t, j: tt) { + let c = i; + let s = j; +} + +function functionExpressionTest(): void { + let empty = function() { }; + + let multiply = function(x: number, y: number): number { return x * y; } + + function createFunc(): () => number { + return function () { return 100; }; + } + + let foobar = function() { return "get result immediately";}(); + + (function () { + console.log("foo!"); + })(); + + void function () { + console.log("bar!"); + }(); + + let factorial = function func(n: number): number { + return (n === 1) ? 1 : n * func(n - 1); + } + + let array = [1, 2, 3, 4, 5, 6]; + let double = array.map(function(e) { return e * 2; }); + let even = array.filter(function(x) { return x % 2 === 0; }); + + let generic = function (t: T, e: E) { return t; }; +} + +function arrowFunctionTest() { + let empty = () => { }; // no return type + + let double = (x: number) => x * 2; // no return type + + let square = (x): number => x * x; // no param type + + let sqrt = x => Math.sqrt(x); // shortcut syntax + let even = [1, 2, 3, 4, 5, 6].filter(x => x % 2 === 0); // shortcut syntax + + let foo = (x: number, y): boolean => x == y; // types are partly omitted + + let generic = (t: T, e: E) => t; // Generic lambda +} + +function fooThis(i: number): void { + this.c = 10; +} +class C { + c: number; + m = fooThis; +} + +function choose(x: T, y: T): T { + return Math.random() < 0.5 ? x : y; +} +let choice1 = choose(10, 20); +let choice2 = choose("apple", "orange"); + +class Collection { + items: T[] = []; + + constructor(...args: T[]) { + if (!args) return; + + for (const arg of args) + this.items.push(arg); + } +} +let col = new Collection(1, 2, 3); +let col2 = new Collection("a", "b", "c"); \ No newline at end of file diff --git a/linter/test/functions.ts.relax.json b/linter/test/functions.ts.relax.json new file mode 100644 index 000000000..ad1512b44 --- /dev/null +++ b/linter/test/functions.ts.relax.json @@ -0,0 +1,58 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 13, + "problem": "SpreadOperator" + }, + { + "line": 28, + "column": 5, + "problem": "GeneratorFunction" + }, + { + "line": 31, + "column": 13, + "problem": "YieldExpression" + }, + { + "line": 73, + "column": 19, + "problem": "LambdaWithTypeParameters" + }, + { + "line": 88, + "column": 19, + "problem": "LambdaWithTypeParameters" + }, + { + "line": 91, + "column": 1, + "problem": "FunctionContainsThis" + }, + { + "line": 109, + "column": 13, + "problem": "LogNotWithNotBool" + }, + { + "line": 109, + "column": 14, + "problem": "ObjectRuntimeCheck" + } + ] +} \ No newline at end of file diff --git a/linter/test/functions.ts.strict.json b/linter/test/functions.ts.strict.json new file mode 100644 index 000000000..1d4e0875a --- /dev/null +++ b/linter/test/functions.ts.strict.json @@ -0,0 +1,213 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 17, + "column": 17, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 18, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 18, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 23, + "column": 13, + "problem": "SpreadOperator" + }, + { + "line": 28, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 28, + "column": 5, + "problem": "GeneratorFunction" + }, + { + "line": 31, + "column": 13, + "problem": "YieldExpression" + }, + { + "line": 41, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 41, + "column": 30, + "problem": "TypeParameterWithDefaultValue" + }, + { + "line": 47, + "column": 17, + "problem": "FunctionExpression" + }, + { + "line": 49, + "column": 20, + "problem": "FunctionExpression" + }, + { + "line": 51, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 52, + "column": 16, + "problem": "FunctionExpression" + }, + { + "line": 55, + "column": 18, + "problem": "FunctionExpression" + }, + { + "line": 57, + "column": 6, + "problem": "FunctionExpression" + }, + { + "line": 61, + "column": 10, + "problem": "FunctionExpression" + }, + { + "line": 65, + "column": 21, + "problem": "FunctionExpression" + }, + { + "line": 69, + "column": 17, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 70, + "column": 18, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 70, + "column": 28, + "problem": "FunctionExpression" + }, + { + "line": 71, + "column": 29, + "problem": "FunctionExpression" + }, + { + "line": 73, + "column": 19, + "problem": "FunctionExpression" + }, + { + "line": 73, + "column": 19, + "problem": "LambdaWithTypeParameters" + }, + { + "line": 76, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 77, + "column": 17, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 79, + "column": 18, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 81, + "column": 18, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 83, + "column": 16, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 84, + "column": 16, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 84, + "column": 42, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 86, + "column": 15, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 88, + "column": 19, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 88, + "column": 19, + "problem": "LambdaWithTypeParameters" + }, + { + "line": 91, + "column": 1, + "problem": "FunctionContainsThis" + }, + { + "line": 102, + "column": 15, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 109, + "column": 13, + "problem": "LogNotWithNotBool" + }, + { + "line": 109, + "column": 14, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 116, + "column": 12, + "problem": "GenericCallNoTypeArgs" + } + ] +} \ No newline at end of file diff --git a/linter/test/generators.ts b/linter/test/generators.ts new file mode 100644 index 000000000..7727351b8 --- /dev/null +++ b/linter/test/generators.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function* countAppleSales() { + const saleList = [3, 7, 5]; + for (let i = 0; i < saleList.length; i++) { + yield saleList[i]; + } +} + +const foo = function*() { + yield 'a'; + yield 'b'; + yield 'c'; +}; +let str = ''; +for (const val of foo()) { + str = str + val; +} +console.log(str); // Expected output: "abc" + +class MyGenerator { + public *getValues() { // you can put the return type Generator, but it is ot necessary as ts will infer + let index = 1; + while(true) { + yield index; + index = index + 1; + + if (index > 10) { + break; + } + } + } +} + +function* func1() { + yield 42; +} +function* func2() { + yield* func1(); +} +const iterator = func2(); +console.log(iterator.next().value); // Expected output: 42 + +function* g1() { + yield 2; + yield 3; + yield 4; +} +function* g2() { + yield 1; + yield* g1(); + yield 5; +} +const gen = g2(); +console.log(gen.next()); // {value: 1, done: false} +console.log(gen.next()); // {value: 2, done: false} +console.log(gen.next()); // {value: 3, done: false} +console.log(gen.next()); // {value: 4, done: false} +console.log(gen.next()); // {value: 5, done: false} +console.log(gen.next()); // {value: undefined, done: true} \ No newline at end of file diff --git a/linter/test/generators.ts.relax.json b/linter/test/generators.ts.relax.json new file mode 100644 index 000000000..8c3b5e4e6 --- /dev/null +++ b/linter/test/generators.ts.relax.json @@ -0,0 +1,163 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 19, + "column": 9, + "problem": "YieldExpression" + }, + { + "line": 23, + "column": 13, + "problem": "GeneratorFunction" + }, + { + "line": 24, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 25, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 26, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 5, + "problem": "GeneratorFunction" + }, + { + "line": 38, + "column": 13, + "problem": "YieldExpression" + }, + { + "line": 48, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 49, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 51, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 52, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 55, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 57, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 58, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 59, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 60, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 62, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 63, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 64, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 65, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 68, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 69, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 70, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 71, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 72, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 73, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/generators.ts.strict.json b/linter/test/generators.ts.strict.json new file mode 100644 index 000000000..e63e8b0ce --- /dev/null +++ b/linter/test/generators.ts.strict.json @@ -0,0 +1,208 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 16, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 17, + "column": 22, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 19, + "column": 9, + "problem": "YieldExpression" + }, + { + "line": 23, + "column": 13, + "problem": "FunctionExpression" + }, + { + "line": 23, + "column": 13, + "problem": "GeneratorFunction" + }, + { + "line": 24, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 25, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 26, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "ForOfNonArray" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 35, + "column": 5, + "problem": "GeneratorFunction" + }, + { + "line": 38, + "column": 13, + "problem": "YieldExpression" + }, + { + "line": 48, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 48, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 49, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 51, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 51, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 52, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 55, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 57, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 57, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 58, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 59, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 60, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 62, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 62, + "column": 1, + "problem": "GeneratorFunction" + }, + { + "line": 63, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 64, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 65, + "column": 5, + "problem": "YieldExpression" + }, + { + "line": 68, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 69, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 70, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 71, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 72, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 73, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/implements_class.ts b/linter/test/implements_class.ts new file mode 100644 index 000000000..6e681056c --- /dev/null +++ b/linter/test/implements_class.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class A +{ + foo() : void + { + console.log("Class A foo"); + } +}; + +class B {}; + +interface I {}; + +class C extends A implements I, B {} + +let c = new C(); +c.foo(); \ No newline at end of file diff --git a/linter/test/implements_class.ts.relax.json b/linter/test/implements_class.ts.relax.json new file mode 100644 index 000000000..25a968f4d --- /dev/null +++ b/linter/test/implements_class.ts.relax.json @@ -0,0 +1,41 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "http://www.apache.org/licenses/LICENSE-2.0", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 2, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 11, + "problem": "TopLevelStmt" + }, + { + "line": 26, + "column": 15, + "problem": "TopLevelStmt" + }, + { + "line": 28, + "column": 33, + "problem": "ImplementsClass" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/implements_class.ts.strict.json b/linter/test/implements_class.ts.strict.json new file mode 100644 index 000000000..25a968f4d --- /dev/null +++ b/linter/test/implements_class.ts.strict.json @@ -0,0 +1,41 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "http://www.apache.org/licenses/LICENSE-2.0", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 2, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 11, + "problem": "TopLevelStmt" + }, + { + "line": 26, + "column": 15, + "problem": "TopLevelStmt" + }, + { + "line": 28, + "column": 33, + "problem": "ImplementsClass" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/infered_type.ts b/linter/test/infered_type.ts new file mode 100644 index 000000000..5086025ef --- /dev/null +++ b/linter/test/infered_type.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var [a, b, c] = [1, "hello", true]; + +console.log(a); +console.log(b); +console.log(c); \ No newline at end of file diff --git a/linter/test/infered_type.ts.relax.json b/linter/test/infered_type.ts.relax.json new file mode 100644 index 000000000..75ae9dad5 --- /dev/null +++ b/linter/test/infered_type.ts.relax.json @@ -0,0 +1,33 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 19, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 20, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/infered_type.ts.strict.json b/linter/test/infered_type.ts.strict.json new file mode 100644 index 000000000..f268833b8 --- /dev/null +++ b/linter/test/infered_type.ts.strict.json @@ -0,0 +1,48 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "VarDeclaration" + }, + { + "line": 16, + "column": 5, + "problem": "DestructuringDeclaration" + }, + { + "line": 16, + "column": 17, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 18, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 19, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 20, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/instanceof.ts b/linter/test/instanceof.ts new file mode 100644 index 000000000..5d28ae8b7 --- /dev/null +++ b/linter/test/instanceof.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class X {} + +let a = (new X()) instanceof Object // true +let b = (new X()) instanceof X // true + +// left operand is a type: +let c = X instanceof Object // Compile-time error +let d = X instanceof X // Compile-time error + +// left operand may be of any reference type, like number +let e = (5.0 as Number) instanceof Number // false + +let f = (X | String) instanceof Object; + +let g = 3 instanceof Number; \ No newline at end of file diff --git a/linter/test/instanceof.ts.relax.json b/linter/test/instanceof.ts.relax.json new file mode 100644 index 000000000..281a8cda6 --- /dev/null +++ b/linter/test/instanceof.ts.relax.json @@ -0,0 +1,38 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 9, + "problem": "InstanceofUnsupported" + }, + { + "line": 23, + "column": 9, + "problem": "InstanceofUnsupported" + }, + { + "line": 28, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 30, + "column": 9, + "problem": "InstanceofUnsupported" + } + ] +} \ No newline at end of file diff --git a/linter/test/instanceof.ts.strict.json b/linter/test/instanceof.ts.strict.json new file mode 100644 index 000000000..281a8cda6 --- /dev/null +++ b/linter/test/instanceof.ts.strict.json @@ -0,0 +1,38 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 9, + "problem": "InstanceofUnsupported" + }, + { + "line": 23, + "column": 9, + "problem": "InstanceofUnsupported" + }, + { + "line": 28, + "column": 10, + "problem": "BitOpWithWrongType" + }, + { + "line": 30, + "column": 9, + "problem": "InstanceofUnsupported" + } + ] +} \ No newline at end of file diff --git a/linter/test/interfaces_optional_props.ts b/linter/test/interfaces_optional_props.ts new file mode 100644 index 000000000..e626d5150 --- /dev/null +++ b/linter/test/interfaces_optional_props.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface CompilerOptions { + strict? : boolean; + sourcePath? : string; + targetPath? : string; +} + +let options: CompilerOptions = { + strict : true, + sourcePath : "./src" +}; + +console.log(options); + +if (options.targetPath == undefined) + console.log("'targetPath' is not defined"); \ No newline at end of file diff --git a/linter/test/interfaces_optional_props.ts.relax.json b/linter/test/interfaces_optional_props.ts.relax.json new file mode 100644 index 000000000..febf34180 --- /dev/null +++ b/linter/test/interfaces_optional_props.ts.relax.json @@ -0,0 +1,43 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 18, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 19, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/interfaces_optional_props.ts.strict.json b/linter/test/interfaces_optional_props.ts.strict.json new file mode 100644 index 000000000..76db14a16 --- /dev/null +++ b/linter/test/interfaces_optional_props.ts.strict.json @@ -0,0 +1,48 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 18, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 19, + "column": 5, + "problem": "InterfaceOptionalProp" + }, + { + "line": 22, + "column": 32, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/interfaces_props.ts b/linter/test/interfaces_props.ts new file mode 100644 index 000000000..85b7d908d --- /dev/null +++ b/linter/test/interfaces_props.ts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Mover { + move(): void; + getStatus(): {speed: number; }; +} + +interface Shaker { + shake(): void; + getStatus(): { frequency: number; }; +} + +interface MoverShaker extends Mover, Shaker { + getStatus(): {speed: number; frequency: number; } +} + +class C implements MoverShaker { + move() : void { + console.log("move"); + } + + shake() : void { + console.log("shake"); + } + + getStatus() { + let speed: number = 100; + let frequency: number = 300; + return {speed, frequency}; + } +} + +let c = new C(); +c.move(); +c.shake(); + +let st = c.getStatus(); +console.log(st); + +let obj : object = c; + +if (obj && obj.move && obj.shake && obj.getStatus) { + let moverShaker = obj as MoverShaker; + + console.log(moverShaker); +} \ No newline at end of file diff --git a/linter/test/interfaces_props.ts.relax.json b/linter/test/interfaces_props.ts.relax.json new file mode 100644 index 000000000..5c0252d89 --- /dev/null +++ b/linter/test/interfaces_props.ts.relax.json @@ -0,0 +1,108 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 23, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 26, + "column": 1, + "problem": "IntefaceExtendDifProps" + }, + { + "line": 27, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 47, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 48, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 51, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 55, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 55, + "column": 12, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 24, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 37, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 12, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 24, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 37, + "problem": "ObjectRuntimeCheck" + } + ] +} \ No newline at end of file diff --git a/linter/test/interfaces_props.ts.strict.json b/linter/test/interfaces_props.ts.strict.json new file mode 100644 index 000000000..56b9d680e --- /dev/null +++ b/linter/test/interfaces_props.ts.strict.json @@ -0,0 +1,123 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 23, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 26, + "column": 1, + "problem": "IntefaceExtendDifProps" + }, + { + "line": 27, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 39, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 42, + "column": 16, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 47, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 48, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 51, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 55, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 55, + "column": 1, + "problem": "IfWithNonBoolean" + }, + { + "line": 55, + "column": 12, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 24, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 37, + "problem": "DynamicTypeCheck" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 55, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 12, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 24, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 55, + "column": 37, + "problem": "ObjectRuntimeCheck" + } + ] +} \ No newline at end of file diff --git a/linter/test/jsx.tsx b/linter/test/jsx.tsx new file mode 100644 index 000000000..50fe6d8a9 --- /dev/null +++ b/linter/test/jsx.tsx @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +export const HelloWorld = () =>

Hello world

; + +export const ATag = () => ; + +const a = ( +
+ {[10, 20].map((i: number) => {i / 2}) } +
+); \ No newline at end of file diff --git a/linter/test/jsx.tsx.relax.json b/linter/test/jsx.tsx.relax.json new file mode 100644 index 000000000..332ba9ce9 --- /dev/null +++ b/linter/test/jsx.tsx.relax.json @@ -0,0 +1,38 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 33, + "problem": "JsxElement" + }, + { + "line": 19, + "column": 27, + "problem": "JsxElement" + }, + { + "line": 22, + "column": 5, + "problem": "JsxElement" + }, + { + "line": 23, + "column": 38, + "problem": "JsxElement" + } + ] +} \ No newline at end of file diff --git a/linter/test/jsx.tsx.strict.json b/linter/test/jsx.tsx.strict.json new file mode 100644 index 000000000..67600bd6d --- /dev/null +++ b/linter/test/jsx.tsx.strict.json @@ -0,0 +1,63 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 27, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 17, + "column": 33, + "problem": "JsxElement" + }, + { + "line": 19, + "column": 21, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 19, + "column": 27, + "problem": "JsxElement" + }, + { + "line": 22, + "column": 5, + "problem": "JsxElement" + }, + { + "line": 23, + "column": 10, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 23, + "column": 10, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 23, + "column": 23, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 23, + "column": 38, + "problem": "JsxElement" + } + ] +} \ No newline at end of file diff --git a/linter/test/mapped_types.ts b/linter/test/mapped_types.ts new file mode 100644 index 000000000..e50d41533 --- /dev/null +++ b/linter/test/mapped_types.ts @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +type OptionsFlags = { + [Property in keyof Type]: boolean; +}; +type FeatureFlags = { + darkMode: () => void; + newUserProfile: () => void; +}; +type FeatureOptions = OptionsFlags; + +// Removes 'readonly' attributes from a type's properties +type CreateMutable = { + -readonly [Property in keyof Type]: Type[Property]; +}; +type LockedAccount = { + readonly id: string; + readonly name: string; +}; +type UnlockedAccount = CreateMutable; + +// Removes 'optional' attributes from a type's properties +type Concrete = { + [Property in keyof Type]-?: Type[Property]; +}; +type MaybeUser = { + id: string; + name?: string; + age?: number; +}; +type User = Concrete; + +// Creates new property names from prior ones: +type Getters = { + [Property in keyof Type as `get${Capitalize}`]: () => Type[Property] +}; +interface Person { + name: string; + age: number; + location: string; +} +type LazyPerson = Getters; + +// Combine with Conditional type: +type ExtractPII = { + [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false; +}; +type DBFields = { + id: { format: "incrementing" }; + name: { type: string; pii: true }; +}; +type ObjectsNeedingGDPRDeletion = ExtractPII; \ No newline at end of file diff --git a/linter/test/mapped_types.ts.relax.json b/linter/test/mapped_types.ts.relax.json new file mode 100644 index 000000000..6cea31102 --- /dev/null +++ b/linter/test/mapped_types.ts.relax.json @@ -0,0 +1,138 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 27, + "problem": "MappedType" + }, + { + "line": 17, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 19, + "column": 21, + "problem": "ObjectTypeLiteral" + }, + { + "line": 26, + "column": 28, + "problem": "MappedType" + }, + { + "line": 27, + "column": 28, + "problem": "KeyOfOperator" + }, + { + "line": 27, + "column": 41, + "problem": "IndexedAccessType" + }, + { + "line": 29, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 36, + "column": 23, + "problem": "MappedType" + }, + { + "line": 37, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 37, + "column": 33, + "problem": "IndexedAccessType" + }, + { + "line": 39, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 47, + "column": 22, + "problem": "MappedType" + }, + { + "line": 48, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 48, + "column": 49, + "problem": "IntersectionType" + }, + { + "line": 48, + "column": 78, + "problem": "IndexedAccessType" + }, + { + "line": 58, + "column": 25, + "problem": "MappedType" + }, + { + "line": 59, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 59, + "column": 31, + "problem": "ConditionalType" + }, + { + "line": 59, + "column": 31, + "problem": "IndexedAccessType" + }, + { + "line": 59, + "column": 54, + "problem": "ObjectTypeLiteral" + }, + { + "line": 61, + "column": 17, + "problem": "ObjectTypeLiteral" + }, + { + "line": 62, + "column": 9, + "problem": "ObjectTypeLiteral" + }, + { + "line": 62, + "column": 19, + "problem": "StringLiteralType" + }, + { + "line": 63, + "column": 11, + "problem": "ObjectTypeLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/mapped_types.ts.strict.json b/linter/test/mapped_types.ts.strict.json new file mode 100644 index 000000000..6cea31102 --- /dev/null +++ b/linter/test/mapped_types.ts.strict.json @@ -0,0 +1,138 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 27, + "problem": "MappedType" + }, + { + "line": 17, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 19, + "column": 21, + "problem": "ObjectTypeLiteral" + }, + { + "line": 26, + "column": 28, + "problem": "MappedType" + }, + { + "line": 27, + "column": 28, + "problem": "KeyOfOperator" + }, + { + "line": 27, + "column": 41, + "problem": "IndexedAccessType" + }, + { + "line": 29, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 36, + "column": 23, + "problem": "MappedType" + }, + { + "line": 37, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 37, + "column": 33, + "problem": "IndexedAccessType" + }, + { + "line": 39, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 47, + "column": 22, + "problem": "MappedType" + }, + { + "line": 48, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 48, + "column": 49, + "problem": "IntersectionType" + }, + { + "line": 48, + "column": 78, + "problem": "IndexedAccessType" + }, + { + "line": 58, + "column": 25, + "problem": "MappedType" + }, + { + "line": 59, + "column": 18, + "problem": "KeyOfOperator" + }, + { + "line": 59, + "column": 31, + "problem": "ConditionalType" + }, + { + "line": 59, + "column": 31, + "problem": "IndexedAccessType" + }, + { + "line": 59, + "column": 54, + "problem": "ObjectTypeLiteral" + }, + { + "line": 61, + "column": 17, + "problem": "ObjectTypeLiteral" + }, + { + "line": 62, + "column": 9, + "problem": "ObjectTypeLiteral" + }, + { + "line": 62, + "column": 19, + "problem": "StringLiteralType" + }, + { + "line": 63, + "column": 11, + "problem": "ObjectTypeLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/modules.ts b/linter/test/modules.ts new file mode 100644 index 000000000..0918ef2a6 --- /dev/null +++ b/linter/test/modules.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import "./short_test.ts" // import from path + +import { test } from "./short_test.ts" + +function withStmt() { + var radius = 12; + with (Math) { + var area = PI * radius * radius; + } +} + +namespace X { + export class C {} + export interface I {} + export let n: number = 15; + export enum E {} + export function foo(a: number): number { return a * a; } + export type N = number; + + export namespace XX { + export class D {} + } + + console.log("Namespace X is initialized"); + { + console.log("Block statement"); + let blockVar = 10; + } +} +const xc = new X.C(); +class IImpl implements X.I {} +let xn: X.N = X.foo(100); +let d: X.XX.D = new X.XX.D(); + +namespace Y.Z { + export function bar(): void {} +} +Y.Z.bar(); + +// Namespace used as an object or type. +let x = X; +console.log(x.n); + +let xxx = X.XX; +let dd = new xxx.D(); + +function xfoo(x: typeof X): void { + x.foo(25); +} +xfoo(X); + +function yzbar(yz: typeof Y.Z): void { + yz.bar(); +} +yzbar(Y.Z); + +import { default as def } from "module"; // default import + +interface I {} +export default I; // default interface export +export default function (n: number) {}; // default function export +export default class MyClass {}; // default class export + +// type-only import +import type { APIResponseType } from "./api"; +import type * as P from "foo"; +import { type T1, type T2 as T3 } from "foobar"; + +// type-only export +export type { TypeA as TypeB }; +export { type TypeFoo as TypeBar }; + +class SomeClass {} +export { SomeClass as AnotherClass }; // Export renaming + +export { Foo, Bar as Baz, Goo as Zar}; // Export list declaration + +export { SomeFunction } from "module"; // Re-exporting + +class Point {} +export = Point; + +import Validator = require("module"); +import Button = Components.Button; \ No newline at end of file diff --git a/linter/test/modules.ts.relax.json b/linter/test/modules.ts.relax.json new file mode 100644 index 000000000..78790e1a1 --- /dev/null +++ b/linter/test/modules.ts.relax.json @@ -0,0 +1,123 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "ImportFromPath" + }, + { + "line": 22, + "column": 5, + "problem": "WithStatement" + }, + { + "line": 39, + "column": 5, + "problem": "NonDeclarationInNamespace" + }, + { + "line": 40, + "column": 5, + "problem": "NonDeclarationInNamespace" + }, + { + "line": 53, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 56, + "column": 9, + "problem": "NamespaceAsObject" + }, + { + "line": 57, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 59, + "column": 13, + "problem": "NamespaceAsObject" + }, + { + "line": 62, + "column": 25, + "problem": "NamespaceAsObject" + }, + { + "line": 65, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 65, + "column": 6, + "problem": "NamespaceAsObject" + }, + { + "line": 67, + "column": 29, + "problem": "NamespaceAsObject" + }, + { + "line": 70, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 70, + "column": 9, + "problem": "NamespaceAsObject" + }, + { + "line": 76, + "column": 39, + "problem": "TopLevelStmt" + }, + { + "line": 77, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 77, + "column": 32, + "problem": "TopLevelStmt" + }, + { + "line": 93, + "column": 1, + "problem": "ReExporting" + }, + { + "line": 96, + "column": 1, + "problem": "ExportAssignment" + }, + { + "line": 98, + "column": 1, + "problem": "ImportAssignment" + }, + { + "line": 99, + "column": 1, + "problem": "ImportAssignment" + } + ] +} \ No newline at end of file diff --git a/linter/test/modules.ts.strict.json b/linter/test/modules.ts.strict.json new file mode 100644 index 000000000..057295883 --- /dev/null +++ b/linter/test/modules.ts.strict.json @@ -0,0 +1,243 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "ImportFromPath" + }, + { + "line": 20, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 21, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 22, + "column": 5, + "problem": "WithStatement" + }, + { + "line": 23, + "column": 9, + "problem": "VarDeclaration" + }, + { + "line": 39, + "column": 5, + "problem": "NonDeclarationInNamespace" + }, + { + "line": 40, + "column": 5, + "problem": "NonDeclarationInNamespace" + }, + { + "line": 53, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 56, + "column": 9, + "problem": "NamespaceAsObject" + }, + { + "line": 57, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 59, + "column": 13, + "problem": "NamespaceAsObject" + }, + { + "line": 62, + "column": 25, + "problem": "NamespaceAsObject" + }, + { + "line": 65, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 65, + "column": 6, + "problem": "NamespaceAsObject" + }, + { + "line": 67, + "column": 29, + "problem": "NamespaceAsObject" + }, + { + "line": 70, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 70, + "column": 9, + "problem": "NamespaceAsObject" + }, + { + "line": 72, + "column": 10, + "problem": "DefaultImport" + }, + { + "line": 75, + "column": 1, + "problem": "DefaultExport" + }, + { + "line": 76, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 76, + "column": 1, + "problem": "DefaultExport" + }, + { + "line": 76, + "column": 39, + "problem": "TopLevelStmt" + }, + { + "line": 77, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 77, + "column": 1, + "problem": "DefaultExport" + }, + { + "line": 77, + "column": 32, + "problem": "TopLevelStmt" + }, + { + "line": 80, + "column": 8, + "problem": "TypeOnlyImport" + }, + { + "line": 81, + "column": 8, + "problem": "TypeOnlyImport" + }, + { + "line": 82, + "column": 10, + "problem": "TypeOnlyImport" + }, + { + "line": 82, + "column": 19, + "problem": "TypeOnlyImport" + }, + { + "line": 85, + "column": 1, + "problem": "TypeOnlyExport" + }, + { + "line": 85, + "column": 13, + "problem": "ExportListDeclaration" + }, + { + "line": 85, + "column": 15, + "problem": "ExportRenaming" + }, + { + "line": 86, + "column": 8, + "problem": "ExportListDeclaration" + }, + { + "line": 86, + "column": 10, + "problem": "ExportRenaming" + }, + { + "line": 86, + "column": 10, + "problem": "TypeOnlyExport" + }, + { + "line": 89, + "column": 8, + "problem": "ExportListDeclaration" + }, + { + "line": 89, + "column": 10, + "problem": "ExportRenaming" + }, + { + "line": 91, + "column": 8, + "problem": "ExportListDeclaration" + }, + { + "line": 91, + "column": 15, + "problem": "ExportRenaming" + }, + { + "line": 91, + "column": 27, + "problem": "ExportRenaming" + }, + { + "line": 93, + "column": 1, + "problem": "ReExporting" + }, + { + "line": 93, + "column": 8, + "problem": "ExportListDeclaration" + }, + { + "line": 96, + "column": 1, + "problem": "ExportAssignment" + }, + { + "line": 98, + "column": 1, + "problem": "ImportAssignment" + }, + { + "line": 99, + "column": 1, + "problem": "ImportAssignment" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_literals.ts b/linter/test/object_literals.ts new file mode 100644 index 000000000..d7a2cfd4e --- /dev/null +++ b/linter/test/object_literals.ts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface I { + a: number; + b: string; +} + +class C { + a: number; + b: string; +} + +class C2 { + q: {x: number, y: string}; + w: any; + e: I; + r: C; +} + +function object_literals(): void { + + // Variable declaration + let a1 = {a: 1, b: "a"}; // NOT OK + let a2: any = {a: 2, b: "b"}; // NOT OK + let a3: {a: number, b: string} = {a: 30, b: "c"}; // NOT OK + let a4: I = {a: 4, b: "d"}; // NOT OK + let a5: C = {a: 5, b: "e"}; // OK + let a6: C2 = { // OK + q: {x: 6, y: "f"}, // NOT OK + w: {a: 7, b: "g"}, // NOT OK + e: {a: 8, b: "h"}, // NOT OK + r: {a: 9, b: "i"} // OK + }; + + // Assignment + a1 = {a: 11, b: "a"}; // NOT OK + a2 = {a: 12, b: "b"}; // NOT OK + a3 = {a: 13, b: "c"}; // NOT OK + a4 = {a: 14, b: "d"}; // NOT OK + a5 = {a: 15, b: "e"}; // OK + a6 = { // OK + q: {x: 16, y: "f"}, // NOT OK + w: {a: 17, b: "g"}, // NOT OK + e: {a: 18, b: "h"}, // NOT OK + r: {a: 19, b: "i"} // OK + }; + + // Default parameter value + function foo(x = {a: 21, b: "a"}) { console.log(x.a, x.b); } // NOT OK + function foo2(x: any = {a: 22, b: "b"}) { console.log(x.a, x.b); } // NOT OK + function foo3(x: {a: number, b: string} = {a: 23, b: "c"}) { console.log(x.a, x.b); } // NOT OK + function foo4(x: I = {a: 24, b: "d"}) { console.log(x.a, x.b); } // NOT OK + function foo5(x: C = {a: 25, b: "e"}) { console.log(x.a, x.b); } // OK + + // Function call + foo({a: 21, b: "a"}); // NOT OK + foo2({a: 22, b: "b"}); // NOT OK + foo3({a: 23, b: "c"}); // NOT OK + foo4({a: 24, b: "d"}); // NOT OK + foo5({a: 25, b: "e"}); // OK + + // Return from function + function bar() { return {a: 31, b: "a"} } // NOT OK + function bar2(): any { return {a: 32, b: "b"} } // NOT OK + function bar3(): {a: number, b: string} { return {a: 33, b: "c"}; } // NOT OK + function bar4(): I { return {a: 34, b: "d"}; } // NOT OK + function bar5(): C { return {a: 35, b: "e"}; } // OK + + // In ternary operator + let condition = true; + a1 = (condition) ? {a: 41, b: "a"} : {a: 42, b: "b"}; // NOT OK + a2 = (condition) ? {a: 43, b: "c"} : {a: 44, b: "d"}; // NOT OK + a3 = (condition) ? {a: 45, b: "e"} : {a: 46, b: "f"}; // NOT OK + a4 = (condition) ? {a: 47, b: "g"} : {a: 48, b: "h"}; // NOT OK + a5 = (condition) ? {a: 49, b: "i"} : {a: 50, b: "j"}; // OK + + // In array literal + let arr1 = [ {a: 51, b: "a"}, {a: 52, b: "b"} ]; // NOT OK + let arr2: any[] = [ {a: 53, b: "c"}, {a: 54, b: "d"} ]; // NOT OK + let arr3: {a: number, b: string}[] = [ {a: 55, b: "e"}, {a: 56, b: "f"} ]; // NOT OK + let arr4: I[] = [ {a: 57, b: "g"}, {a: 58, b: "h"} ]; // NOT OK + let arr5: C[] = [ {a: 59, b: "i"}, {a: 60, b: "j"} ]; // OK +} \ No newline at end of file diff --git a/linter/test/object_literals.ts.relax.json b/linter/test/object_literals.ts.relax.json new file mode 100644 index 000000000..dda37ee3b --- /dev/null +++ b/linter/test/object_literals.ts.relax.json @@ -0,0 +1,68 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 27, + "column": 8, + "problem": "ObjectTypeLiteral" + }, + { + "line": 28, + "column": 8, + "problem": "AnyType" + }, + { + "line": 37, + "column": 13, + "problem": "AnyType" + }, + { + "line": 38, + "column": 13, + "problem": "ObjectTypeLiteral" + }, + { + "line": 63, + "column": 22, + "problem": "AnyType" + }, + { + "line": 64, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 77, + "column": 22, + "problem": "AnyType" + }, + { + "line": 78, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 92, + "column": 15, + "problem": "AnyType" + }, + { + "line": 93, + "column": 15, + "problem": "ObjectTypeLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_literals.ts.strict.json b/linter/test/object_literals.ts.strict.json new file mode 100644 index 000000000..ec6ff6fab --- /dev/null +++ b/linter/test/object_literals.ts.strict.json @@ -0,0 +1,363 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 27, + "column": 8, + "problem": "ObjectTypeLiteral" + }, + { + "line": 28, + "column": 8, + "problem": "AnyType" + }, + { + "line": 36, + "column": 14, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 37, + "column": 13, + "problem": "AnyType" + }, + { + "line": 37, + "column": 19, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 38, + "column": 13, + "problem": "ObjectTypeLiteral" + }, + { + "line": 38, + "column": 38, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 39, + "column": 17, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 42, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 43, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 44, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 49, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 50, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 51, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 52, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 55, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 56, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 57, + "column": 12, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 62, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 62, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 62, + "column": 22, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 63, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 63, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 63, + "column": 22, + "problem": "AnyType" + }, + { + "line": 63, + "column": 28, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 64, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 64, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 64, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 64, + "column": 47, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 65, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 65, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 65, + "column": 26, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 66, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 66, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 69, + "column": 9, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 70, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 71, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 72, + "column": 10, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 76, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 76, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 76, + "column": 29, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 77, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 77, + "column": 22, + "problem": "AnyType" + }, + { + "line": 77, + "column": 35, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 78, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 78, + "column": 22, + "problem": "ObjectTypeLiteral" + }, + { + "line": 78, + "column": 54, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 79, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 79, + "column": 33, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 80, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 84, + "column": 24, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 84, + "column": 42, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 85, + "column": 24, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 85, + "column": 42, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 86, + "column": 24, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 86, + "column": 42, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 87, + "column": 24, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 87, + "column": 42, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 91, + "column": 16, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 91, + "column": 18, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 91, + "column": 35, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 92, + "column": 15, + "problem": "AnyType" + }, + { + "line": 92, + "column": 25, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 92, + "column": 42, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 93, + "column": 15, + "problem": "ObjectTypeLiteral" + }, + { + "line": 93, + "column": 44, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 93, + "column": 61, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 94, + "column": 23, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 94, + "column": 40, + "problem": "ObjectLiteralNoContextType" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_runtime_check.ts b/linter/test/object_runtime_check.ts new file mode 100644 index 000000000..51f66cc6a --- /dev/null +++ b/linter/test/object_runtime_check.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class A { + s: string; + b: boolean = false; +} + +let a = new A(); +let aExists: boolean = !!a; + +if (a) { } +if (a.s) { } +if (a.b) { } +if (aExists) { } + +if ((a) && (a.s) && a.b && aExists) { } +if (a.s || a.b) { } +if (a || aExists) { } +if (!a || !(a.s) || !a.b || !aExists) { } + +while (a) { break; } +while (a.s) { break; } +while (a.b) { break; } +while (aExists) { break; } + +do { break; } while (a); +do { break; } while (a.s); +do { break; } while (a.b); +do { break; } while (aExists); + +for (let x = 0; a; x++) { if (x > 5) break; } +for (let x = 0; a.s; x++) { if (x > 5) break; } +for (let x = 0; a.b; x++) { if (x > 5) break; } +for (let x = 0; aExists; x++) { if (x > 5) break; } + +let x = a ? 1 : 2; +x = (a.s) ? 3 : 4; +x = a.b ? 5 : 6; +x = (aExists) ? 5 : 6; \ No newline at end of file diff --git a/linter/test/object_runtime_check.ts.relax.json b/linter/test/object_runtime_check.ts.relax.json new file mode 100644 index 000000000..a4e839b42 --- /dev/null +++ b/linter/test/object_runtime_check.ts.relax.json @@ -0,0 +1,253 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 25, + "problem": "LogNotWithNotBool" + }, + { + "line": 22, + "column": 26, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 24, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 25, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 25, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 26, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 29, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 29, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 29, + "column": 13, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 30, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 30, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 30, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 31, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 5, + "problem": "LogNotWithNotBool" + }, + { + "line": 32, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 32, + "column": 11, + "problem": "LogNotWithNotBool" + }, + { + "line": 32, + "column": 13, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 34, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 34, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 37, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 39, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 39, + "column": 22, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 40, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 40, + "column": 22, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 41, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 44, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 44, + "column": 17, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 45, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 45, + "column": 17, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 47, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 49, + "column": 9, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 50, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 50, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 51, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 52, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_runtime_check.ts.strict.json b/linter/test/object_runtime_check.ts.strict.json new file mode 100644 index 000000000..3d94a57e0 --- /dev/null +++ b/linter/test/object_runtime_check.ts.strict.json @@ -0,0 +1,293 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 22, + "column": 25, + "problem": "LogNotWithNotBool" + }, + { + "line": 22, + "column": 26, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 24, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 1, + "problem": "IfWithNonBoolean" + }, + { + "line": 24, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 25, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 25, + "column": 1, + "problem": "IfWithNonBoolean" + }, + { + "line": 25, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 26, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 27, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 29, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 29, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 29, + "column": 13, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 30, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 30, + "column": 1, + "problem": "IfWithNonBoolean" + }, + { + "line": 30, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 30, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 1, + "problem": "IfWithNonBoolean" + }, + { + "line": 31, + "column": 5, + "problem": "LogicalWithNonBoolean" + }, + { + "line": 31, + "column": 5, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 5, + "problem": "LogNotWithNotBool" + }, + { + "line": 32, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 32, + "column": 11, + "problem": "LogNotWithNotBool" + }, + { + "line": 32, + "column": 13, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 34, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 34, + "column": 1, + "problem": "WhileWithNonBoolean" + }, + { + "line": 34, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 35, + "column": 1, + "problem": "WhileWithNonBoolean" + }, + { + "line": 35, + "column": 8, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 37, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 39, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 39, + "column": 1, + "problem": "DoWithNonBoolean" + }, + { + "line": 39, + "column": 22, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 40, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 40, + "column": 1, + "problem": "DoWithNonBoolean" + }, + { + "line": 40, + "column": 22, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 41, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 42, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 44, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 44, + "column": 17, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 45, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 45, + "column": 17, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 46, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 47, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 49, + "column": 9, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 50, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 50, + "column": 6, + "problem": "ObjectRuntimeCheck" + }, + { + "line": 51, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 52, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_spread.ts b/linter/test/object_spread.ts new file mode 100644 index 000000000..be641d65d --- /dev/null +++ b/linter/test/object_spread.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const pt2D = {x : 1, y: 2}; + +console.log(pt2D); + +const pt3D = {...pt2D, z : 3}; + +console.log(pt3D); \ No newline at end of file diff --git a/linter/test/object_spread.ts.relax.json b/linter/test/object_spread.ts.relax.json new file mode 100644 index 000000000..bfc4fa855 --- /dev/null +++ b/linter/test/object_spread.ts.relax.json @@ -0,0 +1,33 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 20, + "column": 15, + "problem": "SpreadAssignment" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/object_spread.ts.strict.json b/linter/test/object_spread.ts.strict.json new file mode 100644 index 000000000..0b88383cf --- /dev/null +++ b/linter/test/object_spread.ts.strict.json @@ -0,0 +1,43 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 14, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 18, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 20, + "column": 14, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 20, + "column": 15, + "problem": "SpreadAssignment" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/parameter_properties.ts b/linter/test/parameter_properties.ts new file mode 100644 index 000000000..b6224e527 --- /dev/null +++ b/linter/test/parameter_properties.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class Params { + constructor( + public readonly x: number, + protected y: number, + private z: number + ) { } + + foo(): void { + console.log(this.x + this.y + this.z); + } +} + +class DerivedParams extends Params { + bar(): void { + console.log(this.x + this.y); + } +} + +const a = new Params(1, 2, 3); +console.log(a.x); \ No newline at end of file diff --git a/linter/test/parameter_properties.ts.relax.json b/linter/test/parameter_properties.ts.relax.json new file mode 100644 index 000000000..0b1b99523 --- /dev/null +++ b/linter/test/parameter_properties.ts.relax.json @@ -0,0 +1,23 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/parameter_properties.ts.strict.json b/linter/test/parameter_properties.ts.strict.json new file mode 100644 index 000000000..59a30375d --- /dev/null +++ b/linter/test/parameter_properties.ts.strict.json @@ -0,0 +1,38 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 18, + "column": 9, + "problem": "ParameterProperties" + }, + { + "line": 19, + "column": 9, + "problem": "ParameterProperties" + }, + { + "line": 20, + "column": 9, + "problem": "ParameterProperties" + }, + { + "line": 35, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/string_literal_type.ts b/linter/test/string_literal_type.ts new file mode 100644 index 000000000..b5a0c01bb --- /dev/null +++ b/linter/test/string_literal_type.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +type Easing = "ease-in" | "ease-out" | "ease-in-out"; + +function foo(arg: Easing) { + console.log(arg); +} + +foo("ease-in"); +foo("ease-out"); +foo("ease-in-out"); \ No newline at end of file diff --git a/linter/test/string_literal_type.ts.relax.json b/linter/test/string_literal_type.ts.relax.json new file mode 100644 index 000000000..98593b759 --- /dev/null +++ b/linter/test/string_literal_type.ts.relax.json @@ -0,0 +1,53 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 15, + "problem": "UnionType" + }, + { + "line": 16, + "column": 15, + "problem": "StringLiteralType" + }, + { + "line": 16, + "column": 27, + "problem": "StringLiteralType" + }, + { + "line": 16, + "column": 40, + "problem": "StringLiteralType" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 23, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/string_literal_type.ts.strict.json b/linter/test/string_literal_type.ts.strict.json new file mode 100644 index 000000000..f3d35d535 --- /dev/null +++ b/linter/test/string_literal_type.ts.strict.json @@ -0,0 +1,58 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 15, + "problem": "UnionType" + }, + { + "line": 16, + "column": 15, + "problem": "StringLiteralType" + }, + { + "line": 16, + "column": 27, + "problem": "StringLiteralType" + }, + { + "line": 16, + "column": 40, + "problem": "StringLiteralType" + }, + { + "line": 18, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 22, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 23, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 24, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/switch_statements.ts b/linter/test/switch_statements.ts new file mode 100644 index 000000000..b08162f26 --- /dev/null +++ b/linter/test/switch_statements.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface I {} + +function foo(a: string, b: string, i: I): void { + switch (a) { + case '0': + console.log("0"); + break; + case b: + console.log(b); + break; + } + + switch (i) { + case null: + console.log("null interace"); + break; + } + + switch (undefined) { + case console.log(1): + case console.log(2): + void console.log(3); + } + + let x = 10, y = 20, z = 30; + let foo = (n: number) => n; + switch (x) { + case x + y: + console.log("x + y = " + (x + y)); + break; + case foo(z): + console.log("foo(z) = " + foo(z)); + break; + default: + console.log("default case"); + } +} \ No newline at end of file diff --git a/linter/test/switch_statements.ts.relax.json b/linter/test/switch_statements.ts.relax.json new file mode 100644 index 000000000..7f9d26cd6 --- /dev/null +++ b/linter/test/switch_statements.ts.relax.json @@ -0,0 +1,58 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 28, + "column": 13, + "problem": "SwitchSelectorInvalidType" + }, + { + "line": 29, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 34, + "column": 13, + "problem": "SwitchSelectorInvalidType" + }, + { + "line": 35, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 36, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 43, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 46, + "column": 14, + "problem": "CaseExpressionNonConst" + } + ] +} \ No newline at end of file diff --git a/linter/test/switch_statements.ts.strict.json b/linter/test/switch_statements.ts.strict.json new file mode 100644 index 000000000..3e18f93ba --- /dev/null +++ b/linter/test/switch_statements.ts.strict.json @@ -0,0 +1,63 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 23, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 28, + "column": 13, + "problem": "SwitchSelectorInvalidType" + }, + { + "line": 29, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 34, + "column": 13, + "problem": "SwitchSelectorInvalidType" + }, + { + "line": 35, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 36, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 41, + "column": 15, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 43, + "column": 14, + "problem": "CaseExpressionNonConst" + }, + { + "line": 46, + "column": 14, + "problem": "CaseExpressionNonConst" + } + ] +} \ No newline at end of file diff --git a/linter/test/template_literals.ts b/linter/test/template_literals.ts new file mode 100644 index 000000000..86da8ed7d --- /dev/null +++ b/linter/test/template_literals.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function template_literals(): void { + let empty = ``; + let template_text = `First line \n second line +third line \n fourth line`; + let template_head = `template-head ${20 + 40}`; + let template_tail = `${empty.length > 0 ? 100 : 200} template-tail`; + let template_compound = `apple ${400} orange \n ${500} +"banana" ${600} 'grapes'`; + let nested = `outer ${`inner ${1000} inner-end`} outer-end` +} + +function tag1(strings: TemplateStringsArray): void { + console.log(strings); +} +function tag2(strings: TemplateStringsArray, ...values: any[]): void { + console.log(strings, values); +} +function recursiveTag(strings: TemplateStringsArray, ...values: any[]): typeof recursiveTag { + console.log(strings, values); + return recursiveTag; +} + +function tagged_templates(arg: string): void { + tag1`Birds are singing`; + tag2`This product costs ${arg} per month` + recursiveTag`Hello``World`; +} \ No newline at end of file diff --git a/linter/test/template_literals.ts.relax.json b/linter/test/template_literals.ts.relax.json new file mode 100644 index 000000000..bd1b21c7d --- /dev/null +++ b/linter/test/template_literals.ts.relax.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 30, + "column": 57, + "problem": "AnyType" + }, + { + "line": 33, + "column": 65, + "problem": "AnyType" + } + ] +} \ No newline at end of file diff --git a/linter/test/template_literals.ts.strict.json b/linter/test/template_literals.ts.strict.json new file mode 100644 index 000000000..45668d5f8 --- /dev/null +++ b/linter/test/template_literals.ts.strict.json @@ -0,0 +1,83 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 17, + "problem": "TemplateLiteral" + }, + { + "line": 18, + "column": 25, + "problem": "TemplateLiteral" + }, + { + "line": 20, + "column": 25, + "problem": "TemplateLiteral" + }, + { + "line": 21, + "column": 25, + "problem": "TemplateLiteral" + }, + { + "line": 22, + "column": 29, + "problem": "TemplateLiteral" + }, + { + "line": 24, + "column": 18, + "problem": "TemplateLiteral" + }, + { + "line": 24, + "column": 27, + "problem": "TemplateLiteral" + }, + { + "line": 30, + "column": 57, + "problem": "AnyType" + }, + { + "line": 33, + "column": 65, + "problem": "AnyType" + }, + { + "line": 39, + "column": 9, + "problem": "TemplateLiteral" + }, + { + "line": 40, + "column": 9, + "problem": "TemplateLiteral" + }, + { + "line": 41, + "column": 17, + "problem": "TemplateLiteral" + }, + { + "line": 41, + "column": 24, + "problem": "TemplateLiteral" + } + ] +} \ No newline at end of file diff --git a/linter/test/this_type.ts b/linter/test/this_type.ts new file mode 100644 index 000000000..5c38e5217 --- /dev/null +++ b/linter/test/this_type.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Adder { + addFoo(): this; + + addBar(): this; + + addGreeting(name: string): this; +}; + +class StringAdder implements Adder { + value: string = ''; + + getValue(): string { + return this.value; + } + + addFoo(): this { + this.value += 'foo'; + return this; + } + + addBar(): this { + this.value += 'bar'; + return this; + } + + addGreeting(name: string): this { + this.value += `Hi ${name}`; + return this; + } +}const stringAdder: StringAdder = new StringAdder(); + +const str = stringAdder + .addFoo() + .addBar() + .addGreeting('Jane') + .getValue(); + +console.log(str); \ No newline at end of file diff --git a/linter/test/this_type.ts.relax.json b/linter/test/this_type.ts.relax.json new file mode 100644 index 000000000..f85586d4b --- /dev/null +++ b/linter/test/this_type.ts.relax.json @@ -0,0 +1,58 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 13, + "problem": "ThisType" + }, + { + "line": 19, + "column": 13, + "problem": "ThisType" + }, + { + "line": 21, + "column": 30, + "problem": "ThisType" + }, + { + "line": 22, + "column": 2, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 13, + "problem": "ThisType" + }, + { + "line": 36, + "column": 13, + "problem": "ThisType" + }, + { + "line": 41, + "column": 30, + "problem": "ThisType" + }, + { + "line": 53, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/this_type.ts.strict.json b/linter/test/this_type.ts.strict.json new file mode 100644 index 000000000..bfde984a2 --- /dev/null +++ b/linter/test/this_type.ts.strict.json @@ -0,0 +1,63 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 13, + "problem": "ThisType" + }, + { + "line": 19, + "column": 13, + "problem": "ThisType" + }, + { + "line": 21, + "column": 30, + "problem": "ThisType" + }, + { + "line": 22, + "column": 2, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 13, + "problem": "ThisType" + }, + { + "line": 36, + "column": 13, + "problem": "ThisType" + }, + { + "line": 41, + "column": 30, + "problem": "ThisType" + }, + { + "line": 42, + "column": 19, + "problem": "TemplateLiteral" + }, + { + "line": 53, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/type_declarations.ts b/linter/test/type_declarations.ts new file mode 100644 index 000000000..4915e2b51 --- /dev/null +++ b/linter/test/type_declarations.ts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Control { + state: any; +} + +interface SelectableControl extends Control { + select(): void; +} + +enum Mammals { + Humans = 'Humans', + Bats = 'Bats', + Dolphins = 'Dolphins', +} + +enum Reptiles { + Snakes = 'Snakes', + Alligators = 'Alligators', + Lizards = 'Lizards', +} + +if( "snakes" in Mammals) + console.log("?") + +type Animal = Mammals | Reptiles + +class Proc { + private state: any; + private pipe: number; + get Pipe() { return this.pipe; } + set Pipe(p: number) { this.pipe = p; } +} + +let cntr: Proc = new Proc(); +cntr.Pipe = 1; +let pp = cntr.Pipe; + +interface ActiveProc extends Proc { + activate(): void; +} + +interface ActiveProc extends Proc { + deactivate(): void; +} + +enum Colors { red, orange, yellow } +enum Colors { green, blue, purple } + + +function classExpressionTest() { + const Foo = class { + constructor() {} + bar() { + return "Hello World!"; + } + }; + const fooInstance = new Foo(); + fooInstance.bar(); + + const Rectangle = class { + constructor(height, width) { + this.height = height; + this.width = width; + } + area() { + return this.height * this.width; + } + }; + console.log(new Rectangle(5, 8).area()); +} + +interface Box { + contents: any; +} + +enum E { + A, + B = 10, + C +} \ No newline at end of file diff --git a/linter/test/type_declarations.ts.relax.json b/linter/test/type_declarations.ts.relax.json new file mode 100644 index 000000000..2e20e96be --- /dev/null +++ b/linter/test/type_declarations.ts.relax.json @@ -0,0 +1,118 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 12, + "problem": "AnyType" + }, + { + "line": 25, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 26, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 27, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 31, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 32, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 33, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 36, + "column": 14, + "problem": "InOperator" + }, + { + "line": 39, + "column": 15, + "problem": "UnionType" + }, + { + "line": 42, + "column": 20, + "problem": "AnyType" + }, + { + "line": 49, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 52, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 52, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 56, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 56, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 60, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 61, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 87, + "column": 15, + "problem": "AnyType" + }, + { + "line": 92, + "column": 5, + "problem": "EnumMemberWithInitializer" + } + ] +} \ No newline at end of file diff --git a/linter/test/type_declarations.ts.strict.json b/linter/test/type_declarations.ts.strict.json new file mode 100644 index 000000000..52b0c6112 --- /dev/null +++ b/linter/test/type_declarations.ts.strict.json @@ -0,0 +1,143 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 12, + "problem": "AnyType" + }, + { + "line": 25, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 26, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 27, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 31, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 32, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 33, + "column": 5, + "problem": "EnumMemberWithInitializer" + }, + { + "line": 36, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 36, + "column": 14, + "problem": "InOperator" + }, + { + "line": 39, + "column": 15, + "problem": "UnionType" + }, + { + "line": 42, + "column": 20, + "problem": "AnyType" + }, + { + "line": 49, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 52, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 52, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 56, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 56, + "column": 1, + "problem": "InterfaceExtendsClass" + }, + { + "line": 60, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 61, + "column": 1, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 64, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 65, + "column": 17, + "problem": "ClassExpression" + }, + { + "line": 67, + "column": 9, + "problem": "FuncWithoutReturnType" + }, + { + "line": 74, + "column": 23, + "problem": "ClassExpression" + }, + { + "line": 79, + "column": 9, + "problem": "FuncWithoutReturnType" + }, + { + "line": 87, + "column": 15, + "problem": "AnyType" + }, + { + "line": 92, + "column": 5, + "problem": "EnumMemberWithInitializer" + } + ] +} \ No newline at end of file diff --git a/linter/test/types.ts b/linter/test/types.ts new file mode 100644 index 000000000..2b042609d --- /dev/null +++ b/linter/test/types.ts @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function Animations() { + var anyvar: any + let symvar: symbol + let unknown_t: unknown + let undef_t: undefined + let null_t: null + let state = 0 + + let flag: boolean = false; + + let status = { name:"A", idx:0, handler:"foo" } + + type Person = [string, number]; + var user: Person; + user = ["John", 32]; + let age = user[1] + + type Point = { x: number; y: number }; + type P = keyof Point; + type AxeX = Point["x"]; + type P_NULL = P | null; + type P_UNDEF = P | undefined; + type P_ANY = P | any; + type P_P = P | Person; + type P_P_NULL = P | Person | null; + + let typeU = typeof user; + + function isNumber(x: any): x is number { + return typeof x === "number"; + } + + var regex = /go*d/; + + throw "labuda"; +} + +const c = "c"; +const d = 10; +type ComputedPropertyT = { + a: string; // String-like name + 5: string; // Number-like name + [c]: string; // String-like name + [d]: string; // Number-like name +} + +class LiteralAsPropertyName { + 2:string; + "Two": number; +} + +let litAsPropName: LiteralAsPropertyName = { + 2:"two", + "Two":2 +} + + +type Dictionary = { + [key: string]: unknown; +} +let dict: Dictionary; + +function bar(key: string, val: any) { + if (key in dict) { + dict[key] = val; + } +} + +interface I1 { + m1(): number; + m2(): void; +} + +interface I2 { + m2(): string; + m3(): boolean; +} + +type IntersectionT = I1 & I2; + +type DescribableFunction = { + description:string; + (someArg: number): boolean +} +function callFunctionObject(fn: DescribableFunction) { + console.log(fn.description + " returned " + fn(5)); +} +const funcWithDescr: DescribableFunction = (x: number) => x % 2 == 0; +funcWithDescr.description = "isEven"; +callFunctionObject(funcWithDescr); + +class G { + val: T; + getVal(): T { return this.val; } +} +class H extends G<{x: 2}> {} +let g: G<{y: string}> = new G<{y: "constant"}>(); +function generic(t: T): void {} +generic<{z: boolean}>({z: true}); + +function type_assertions(): void { + let num = 1; + const myCanvas = document.getElementById("main_canvas"); +} + +function dynamic_properties(): void { + let x = { a: 5, b: "text" }; + x["c"] = 100200; + console.log(x["c"]); + + let y: any = { q: 100, w: true }; + y.e = "dynamic"; + console.log(y.e); +} + +function generic_array_type(): void { + let x: Array = ["1", "2", "3"]; + let y: Array = new Array(1, 2, 3); + let z: number[] = [1, 2, 3]; + + function arrayFunc(array: Array): Array { + return array.map(x => x.toString()); + } +} \ No newline at end of file diff --git a/linter/test/types.ts.relax.json b/linter/test/types.ts.relax.json new file mode 100644 index 000000000..dfda9c55c --- /dev/null +++ b/linter/test/types.ts.relax.json @@ -0,0 +1,298 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 17, + "column": 17, + "problem": "AnyType" + }, + { + "line": 18, + "column": 17, + "problem": "SymbolType" + }, + { + "line": 19, + "column": 20, + "problem": "UnknownType" + }, + { + "line": 20, + "column": 18, + "problem": "UndefinedType" + }, + { + "line": 28, + "column": 19, + "problem": "TupleType" + }, + { + "line": 31, + "column": 15, + "problem": "PropertyAccessByIndex" + }, + { + "line": 33, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 34, + "column": 14, + "problem": "KeyOfOperator" + }, + { + "line": 35, + "column": 17, + "problem": "IndexedAccessType" + }, + { + "line": 35, + "column": 23, + "problem": "StringLiteralType" + }, + { + "line": 37, + "column": 20, + "problem": "UnionType" + }, + { + "line": 37, + "column": 24, + "problem": "UndefinedType" + }, + { + "line": 38, + "column": 18, + "problem": "UnionType" + }, + { + "line": 38, + "column": 22, + "problem": "AnyType" + }, + { + "line": 39, + "column": 16, + "problem": "UnionType" + }, + { + "line": 40, + "column": 21, + "problem": "UnionType" + }, + { + "line": 42, + "column": 17, + "problem": "TypeOfExpression" + }, + { + "line": 44, + "column": 26, + "problem": "AnyType" + }, + { + "line": 44, + "column": 32, + "problem": "IsOperator" + }, + { + "line": 45, + "column": 16, + "problem": "TypeOfExpression" + }, + { + "line": 48, + "column": 17, + "problem": "RegexLiteral" + }, + { + "line": 55, + "column": 26, + "problem": "ObjectTypeLiteral" + }, + { + "line": 58, + "column": 5, + "problem": "ComputedPropertyName" + }, + { + "line": 59, + "column": 5, + "problem": "ComputedPropertyName" + }, + { + "line": 63, + "column": 5, + "problem": "LiteralAsPropertyName" + }, + { + "line": 64, + "column": 5, + "problem": "LiteralAsPropertyName" + }, + { + "line": 68, + "column": 4, + "problem": "LiteralAsPropertyName" + }, + { + "line": 69, + "column": 4, + "problem": "LiteralAsPropertyName" + }, + { + "line": 73, + "column": 19, + "problem": "ObjectTypeLiteral" + }, + { + "line": 74, + "column": 5, + "problem": "IndexMember" + }, + { + "line": 74, + "column": 20, + "problem": "UnknownType" + }, + { + "line": 78, + "column": 32, + "problem": "AnyType" + }, + { + "line": 79, + "column": 13, + "problem": "InOperator" + }, + { + "line": 80, + "column": 9, + "problem": "PropertyAccessByIndex" + }, + { + "line": 94, + "column": 22, + "problem": "IntersectionType" + }, + { + "line": 96, + "column": 28, + "problem": "ObjectTypeLiteral" + }, + { + "line": 98, + "column": 5, + "problem": "CallSignature" + }, + { + "line": 104, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 105, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 111, + "column": 19, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 10, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 31, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 35, + "problem": "StringLiteralType" + }, + { + "line": 114, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 114, + "column": 9, + "problem": "ObjectTypeLiteral" + }, + { + "line": 117, + "column": 15, + "problem": "TypeAssertion" + }, + { + "line": 117, + "column": 16, + "problem": "AnyType" + }, + { + "line": 118, + "column": 22, + "problem": "TypeAssertion" + }, + { + "line": 123, + "column": 5, + "problem": "PropertyAccessByIndex" + }, + { + "line": 124, + "column": 17, + "problem": "PropertyAccessByIndex" + }, + { + "line": 126, + "column": 12, + "problem": "AnyType" + }, + { + "line": 132, + "column": 12, + "problem": "GenericArrayType" + }, + { + "line": 133, + "column": 12, + "problem": "GenericArrayType" + }, + { + "line": 133, + "column": 28, + "problem": "GenericArrayType" + }, + { + "line": 136, + "column": 49, + "problem": "GenericArrayType" + }, + { + "line": 136, + "column": 60, + "problem": "GenericArrayType" + } + ] +} \ No newline at end of file diff --git a/linter/test/types.ts.strict.json b/linter/test/types.ts.strict.json new file mode 100644 index 000000000..8a84e7236 --- /dev/null +++ b/linter/test/types.ts.strict.json @@ -0,0 +1,388 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 17, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 17, + "column": 17, + "problem": "AnyType" + }, + { + "line": 18, + "column": 17, + "problem": "SymbolType" + }, + { + "line": 19, + "column": 20, + "problem": "UnknownType" + }, + { + "line": 20, + "column": 18, + "problem": "UndefinedType" + }, + { + "line": 26, + "column": 18, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 28, + "column": 19, + "problem": "TupleType" + }, + { + "line": 29, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 30, + "column": 12, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 31, + "column": 15, + "problem": "PropertyAccessByIndex" + }, + { + "line": 33, + "column": 18, + "problem": "ObjectTypeLiteral" + }, + { + "line": 34, + "column": 14, + "problem": "KeyOfOperator" + }, + { + "line": 35, + "column": 17, + "problem": "IndexedAccessType" + }, + { + "line": 35, + "column": 23, + "problem": "StringLiteralType" + }, + { + "line": 37, + "column": 20, + "problem": "UnionType" + }, + { + "line": 37, + "column": 24, + "problem": "UndefinedType" + }, + { + "line": 38, + "column": 18, + "problem": "UnionType" + }, + { + "line": 38, + "column": 22, + "problem": "AnyType" + }, + { + "line": 39, + "column": 16, + "problem": "UnionType" + }, + { + "line": 40, + "column": 21, + "problem": "UnionType" + }, + { + "line": 42, + "column": 17, + "problem": "TypeOfExpression" + }, + { + "line": 44, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 44, + "column": 26, + "problem": "AnyType" + }, + { + "line": 44, + "column": 32, + "problem": "IsOperator" + }, + { + "line": 45, + "column": 16, + "problem": "TypeOfExpression" + }, + { + "line": 48, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 48, + "column": 17, + "problem": "RegexLiteral" + }, + { + "line": 50, + "column": 5, + "problem": "ThrowStatement" + }, + { + "line": 55, + "column": 26, + "problem": "ObjectTypeLiteral" + }, + { + "line": 58, + "column": 5, + "problem": "ComputedPropertyName" + }, + { + "line": 59, + "column": 5, + "problem": "ComputedPropertyName" + }, + { + "line": 63, + "column": 5, + "problem": "LiteralAsPropertyName" + }, + { + "line": 64, + "column": 5, + "problem": "LiteralAsPropertyName" + }, + { + "line": 68, + "column": 4, + "problem": "LiteralAsPropertyName" + }, + { + "line": 69, + "column": 4, + "problem": "LiteralAsPropertyName" + }, + { + "line": 73, + "column": 19, + "problem": "ObjectTypeLiteral" + }, + { + "line": 74, + "column": 5, + "problem": "IndexMember" + }, + { + "line": 74, + "column": 20, + "problem": "UnknownType" + }, + { + "line": 78, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 78, + "column": 32, + "problem": "AnyType" + }, + { + "line": 79, + "column": 13, + "problem": "InOperator" + }, + { + "line": 80, + "column": 9, + "problem": "PropertyAccessByIndex" + }, + { + "line": 94, + "column": 22, + "problem": "IntersectionType" + }, + { + "line": 96, + "column": 28, + "problem": "ObjectTypeLiteral" + }, + { + "line": 98, + "column": 5, + "problem": "CallSignature" + }, + { + "line": 100, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 103, + "column": 44, + "problem": "ArrowFunctionWithOmittedTypes" + }, + { + "line": 104, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 105, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 111, + "column": 19, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 10, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 31, + "problem": "ObjectTypeLiteral" + }, + { + "line": 112, + "column": 35, + "problem": "StringLiteralType" + }, + { + "line": 114, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 114, + "column": 9, + "problem": "ObjectTypeLiteral" + }, + { + "line": 114, + "column": 23, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 117, + "column": 15, + "problem": "TypeAssertion" + }, + { + "line": 117, + "column": 16, + "problem": "AnyType" + }, + { + "line": 118, + "column": 22, + "problem": "TypeAssertion" + }, + { + "line": 122, + "column": 13, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 123, + "column": 5, + "problem": "PropertyAccessByIndex" + }, + { + "line": 124, + "column": 17, + "problem": "PropertyAccessByIndex" + }, + { + "line": 126, + "column": 12, + "problem": "AnyType" + }, + { + "line": 126, + "column": 18, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 132, + "column": 12, + "problem": "GenericArrayType" + }, + { + "line": 133, + "column": 12, + "problem": "GenericArrayType" + }, + { + "line": 133, + "column": 28, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 133, + "column": 28, + "problem": "GenericArrayType" + }, + { + "line": 136, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 136, + "column": 49, + "problem": "GenericArrayType" + }, + { + "line": 136, + "column": 60, + "problem": "GenericArrayType" + }, + { + "line": 137, + "column": 16, + "problem": "GenericCallNoTypeArgs" + }, + { + "line": 137, + "column": 26, + "problem": "ArrowFunctionWithOmittedTypes" + } + ] +} \ No newline at end of file diff --git a/linter/test/unary_wrong_types.ts b/linter/test/unary_wrong_types.ts new file mode 100644 index 000000000..43ea15638 --- /dev/null +++ b/linter/test/unary_wrong_types.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function gets() : string { + return "ss"; +} + +let a1 = +"3"; +let a2 = -"3"; +let a3 = ~"3"; +let a4 = +gets(); + +let b1 = !"b"; +let b2 = !""; + +console.log(a1); +console.log(a2); +console.log(a3); +console.log(a4); +console.log(b1); +console.log(b2); \ No newline at end of file diff --git a/linter/test/unary_wrong_types.ts.relax.json b/linter/test/unary_wrong_types.ts.relax.json new file mode 100644 index 000000000..bfce327ea --- /dev/null +++ b/linter/test/unary_wrong_types.ts.relax.json @@ -0,0 +1,78 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 20, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 21, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 22, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 23, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 25, + "column": 10, + "problem": "LogNotWithNotBool" + }, + { + "line": 26, + "column": 10, + "problem": "LogNotWithNotBool" + }, + { + "line": 28, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 30, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 33, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/unary_wrong_types.ts.strict.json b/linter/test/unary_wrong_types.ts.strict.json new file mode 100644 index 000000000..bfce327ea --- /dev/null +++ b/linter/test/unary_wrong_types.ts.strict.json @@ -0,0 +1,78 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 20, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 21, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 22, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 23, + "column": 10, + "problem": "UnaryArithmNotNumber" + }, + { + "line": 25, + "column": 10, + "problem": "LogNotWithNotBool" + }, + { + "line": 26, + "column": 10, + "problem": "LogNotWithNotBool" + }, + { + "line": 28, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 29, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 30, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 31, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 32, + "column": 1, + "problem": "TopLevelStmt" + }, + { + "line": 33, + "column": 1, + "problem": "TopLevelStmt" + } + ] +} \ No newline at end of file diff --git a/linter/test/unique_names.ts b/linter/test/unique_names.ts new file mode 100644 index 000000000..1e12fc1c7 --- /dev/null +++ b/linter/test/unique_names.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Global-scoped duplicate declarations + +import A from "x"; +interface A { } +class A implements A { + m(); // Not duplicate, method overload + m(a?: number) {} // Not duplicate, method overload +} + +namespace A { + export interface B { a: number; } + export class B extends A {} + export interface C { a: number; } // Not duplicate, interface C has two merging declarations +} + +namespace A { + export interface B { b: string; } + export interface C { b: string; } // Not duplicate, interface C has two merging declarations +} + +import * as B from "y"; +interface B { } +class B { } + +import { C, X as D, E, Y as F } from "z"; // E and F are not duplicates +interface C { } +class C extends A implements C { } + +function D() {} +interface D {} + +function X(); // Not duplicate, function overload +function X(x?: number) { // Not duplicate, function overload + let ab = new A.B(); +} + +export function unique_names() { + // Function-scoped duplicate declarations + + let A: number = 1000; + interface A { } + + let B: string = "Text"; + type B = number[]; + + class C { } + interface C { } + + function D () {} + type D = number; + + function E () {} + interface E { } + + // Destructuring declarations + interface F { a: number; } + interface H { s: string; } + let [F, G, ...H] = [1, 2, 3, 4, 5]; + + interface I { b: boolean; } + interface K { i: I; } + interface M { k: K; } + let { I, J: { K, L: [M, N], O} } = { I: 10, J: { K: "foo", L: [30, 40], O: "bar" } }; + + { + // Block-scoped duplicate declarations. + let A: number = 54; + interface A { } + } + + switch (A) { + case 1: + let XX = 10; + type XX = number; + + function XY() {} + break; + case 25: + interface XY {} + + function XZ() {} + break; + default: + type XZ = string[]; + break; + } +} + +class PrivateIdentifiers { + x: number; + #x: string; + + y(x: number): number { return 10; } + #y(x: number): number { return 20; } + + z: boolean; + #z(x: number): number { return 30; } +} \ No newline at end of file diff --git a/linter/test/unique_names.ts.relax.json b/linter/test/unique_names.ts.relax.json new file mode 100644 index 000000000..e0eb5b8d1 --- /dev/null +++ b/linter/test/unique_names.ts.relax.json @@ -0,0 +1,328 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 47, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 48, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 8, + "problem": "DeclWithDuplicateName" + }, + { + "line": 19, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 20, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 20, + "column": 20, + "problem": "ImplementsClass" + }, + { + "line": 21, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 22, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 25, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 26, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 26, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 27, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 28, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 31, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 32, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 32, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 33, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 36, + "column": 8, + "problem": "DeclWithDuplicateName" + }, + { + "line": 37, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 38, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 40, + "column": 10, + "problem": "DeclWithDuplicateName" + }, + { + "line": 40, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 41, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 42, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 42, + "column": 30, + "problem": "ImplementsClass" + }, + { + "line": 44, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 45, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 48, + "column": 12, + "problem": "FuncOptionalParams" + }, + { + "line": 55, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 56, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 58, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 59, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 61, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 62, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 64, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 65, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 67, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 68, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 71, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 72, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 73, + "column": 10, + "problem": "DeclWithDuplicateName" + }, + { + "line": 73, + "column": 19, + "problem": "DeclWithDuplicateName" + }, + { + "line": 75, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 76, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 77, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 11, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 19, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 26, + "problem": "DeclWithDuplicateName" + }, + { + "line": 82, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 83, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 88, + "column": 17, + "problem": "DeclWithDuplicateName" + }, + { + "line": 89, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 91, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 94, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 96, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 99, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 105, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 106, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 108, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 109, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 111, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 112, + "column": 5, + "problem": "DeclWithDuplicateName" + } + ] +} \ No newline at end of file diff --git a/linter/test/unique_names.ts.strict.json b/linter/test/unique_names.ts.strict.json new file mode 100644 index 000000000..8069e2652 --- /dev/null +++ b/linter/test/unique_names.ts.strict.json @@ -0,0 +1,443 @@ +{ + "copyright": [ + "Copyright (c) 2023-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 47, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 48, + "column": 1, + "problem": "FunctionOverload" + }, + { + "line": 18, + "column": 8, + "problem": "DeclWithDuplicateName" + }, + { + "line": 19, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 20, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 20, + "column": 20, + "problem": "ImplementsClass" + }, + { + "line": 21, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 22, + "column": 5, + "problem": "FunctionOverload" + }, + { + "line": 21, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 22, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 25, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 26, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 26, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 27, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 28, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 31, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 32, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 32, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 33, + "column": 5, + "problem": "InterfaceOrEnumMerging" + }, + { + "line": 36, + "column": 8, + "problem": "DeclWithDuplicateName" + }, + { + "line": 37, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 38, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 40, + "column": 10, + "problem": "DeclWithDuplicateName" + }, + { + "line": 40, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 41, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 42, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 42, + "column": 30, + "problem": "ImplementsClass" + }, + { + "line": 44, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 44, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 45, + "column": 1, + "problem": "DeclWithDuplicateName" + }, + { + "line": 47, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 48, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 48, + "column": 12, + "problem": "FuncOptionalParams" + }, + { + "line": 52, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 55, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 56, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 58, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 59, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 61, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 62, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 64, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 64, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 64, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 65, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 67, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 67, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 67, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 68, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 71, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 72, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 73, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 73, + "column": 10, + "problem": "DeclWithDuplicateName" + }, + { + "line": 73, + "column": 19, + "problem": "DeclWithDuplicateName" + }, + { + "line": 73, + "column": 24, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 75, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 76, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 77, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 9, + "problem": "DestructuringDeclaration" + }, + { + "line": 78, + "column": 11, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 19, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 26, + "problem": "DeclWithDuplicateName" + }, + { + "line": 78, + "column": 40, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 78, + "column": 52, + "problem": "ObjectLiteralNoContextType" + }, + { + "line": 78, + "column": 67, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 82, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 83, + "column": 9, + "problem": "DeclWithDuplicateName" + }, + { + "line": 88, + "column": 17, + "problem": "DeclWithDuplicateName" + }, + { + "line": 89, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 91, + "column": 13, + "problem": "FuncWithoutReturnType" + }, + { + "line": 91, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 91, + "column": 13, + "problem": "LocalFunction" + }, + { + "line": 94, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 96, + "column": 13, + "problem": "FuncWithoutReturnType" + }, + { + "line": 96, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 96, + "column": 13, + "problem": "LocalFunction" + }, + { + "line": 99, + "column": 13, + "problem": "DeclWithDuplicateName" + }, + { + "line": 105, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 106, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 108, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 109, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 111, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 112, + "column": 5, + "problem": "DeclWithDuplicateName" + }, + { + "line": 106, + "column": 5, + "problem": "PrivateIdentifier" + }, + { + "line": 109, + "column": 5, + "problem": "PrivateIdentifier" + }, + { + "line": 112, + "column": 5, + "problem": "PrivateIdentifier" + } + ] +} \ No newline at end of file diff --git a/linter/test/update-test-results.bat b/linter/test/update-test-results.bat new file mode 100644 index 000000000..cd84328b1 --- /dev/null +++ b/linter/test/update-test-results.bat @@ -0,0 +1,16 @@ +REM +REM Copyright (c) 2023-2023 Huawei Device Co., Ltd. +REM Licensed under the Apache License, Version 2.0 (the "License"); +REM you may not use this file except in compliance with the License. +REM You may obtain a copy of the License at +REM +REM http://www.apache.org/licenses/LICENSE-2.0 +REM +REM Unless required by applicable law or agreed to in writing, software +REM distributed under the License is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM See the License for the specific language governing permissions and +REM limitations under the License. +REM + +node ./update-test-results.mjs \ No newline at end of file diff --git a/linter/test/update-test-results.mjs b/linter/test/update-test-results.mjs new file mode 100644 index 000000000..bd080731c --- /dev/null +++ b/linter/test/update-test-results.mjs @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from "fs"; + +const TS_EXT = ".ts"; +const TSX_EXT = ".tsx"; +const JSON_EXT = ".json" +const STRICT_EXT = ".strict"; +const RELAX_EXT = ".relax"; + +function readTestFile(filePath) { + try { + let resultFile = fs.readFileSync(filePath).toString(); + return JSON.parse(resultFile); + } catch (error) { + return undefined; + } +} + +function updateTest(testFile, strictMode) { + let resultExt = (strictMode ? STRICT_EXT : RELAX_EXT) + JSON_EXT; + let testFileWithExt = testFile + resultExt; + + let expectedResult = readTestFile(testFileWithExt); + if (!expectedResult || !expectedResult.copyright) { + console.log(`Failed to update ${testFileWithExt}: couldn't read EXPECTED result file.`); + return; + } + + let actualResult = readTestFile("results/" + testFileWithExt); + if (!actualResult || !actualResult.nodes) { + console.log(`Failed to update ${testFileWithExt}: couldn't read ACTUAL result file.`); + return; + } + + // Write file with actual test results. + let newResultJSON = JSON.stringify({ copyright: expectedResult.copyright, nodes: actualResult.nodes }, null, 4); + fs.writeFileSync(testFileWithExt, newResultJSON); + + console.log(`Updated ${testFileWithExt}`); +} + +if (!fs.existsSync("results")) { + console.log("The 'results' dir does not exist!"); + process.exit(0); +} + +// Get tests from test directory. +let testFiles = fs.readdirSync(".").filter(x => x.trimEnd().endsWith(TS_EXT) || x.trimEnd().endsWith(TSX_EXT)); + +if (!testFiles || testFiles.length == 0) { + console.log("No tests to update."); + process.exit(0); +} + +// Update result for each test for Strict and Relax modes: +for (let testFile of testFiles) { + updateTest(testFile, false); + updateTest(testFile, true); +} \ No newline at end of file diff --git a/linter/test/update-test-results.sh b/linter/test/update-test-results.sh new file mode 100644 index 000000000..e11a183a7 --- /dev/null +++ b/linter/test/update-test-results.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# +# Copyright (c) 2023-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +node ./update-test-results.mjs \ No newline at end of file diff --git a/linter/test/var_declarations.ts b/linter/test/var_declarations.ts new file mode 100644 index 000000000..de692c6a2 --- /dev/null +++ b/linter/test/var_declarations.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function varDeclaration() { + var x = 20; + + function f(shouldInitialize: boolean) { + if (shouldInitialize) { + var y = 10; + } + return y; + } + f(true); // returns '10' + f(false); // returns 'undefined'" + + var array = [1, 2, 3, 4]; + for (var i = 0; i < array.length; i++) + console.log(array[i]); + + for (var j in array) + console.log(array[j]); + + for (var e of array) + console.log(e); +} diff --git a/linter/test/var_declarations.ts.relax.json b/linter/test/var_declarations.ts.relax.json new file mode 100644 index 000000000..d38218bb9 --- /dev/null +++ b/linter/test/var_declarations.ts.relax.json @@ -0,0 +1,28 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 32, + "column": 5, + "problem": "ForInStatement" + }, + { + "line": 33, + "column": 21, + "problem": "PropertyAccessByIndex" + } + ] +} \ No newline at end of file diff --git a/linter/test/var_declarations.ts.strict.json b/linter/test/var_declarations.ts.strict.json new file mode 100644 index 000000000..591a4cf88 --- /dev/null +++ b/linter/test/var_declarations.ts.strict.json @@ -0,0 +1,78 @@ +{ + "copyright": [ + "Copyright (c) 2022-2023 Huawei Device Co., Ltd.", + "Licensed under the Apache License, Version 2.0 (the 'License');", + "you may not use this file except in compliance with the License.", + "You may obtain a copy of the License at", + "", + "http://www.apache.org/licenses/LICENSE-2.0", + "", + "Unless required by applicable law or agreed to in writing, software", + "distributed under the License is distributed on an 'AS IS' BASIS,", + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", + "See the License for the specific language governing permissions and", + "limitations under the License." + ], + "nodes": [ + { + "line": 16, + "column": 1, + "problem": "FuncWithoutReturnType" + }, + { + "line": 17, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 19, + "column": 5, + "problem": "FuncWithoutReturnType" + }, + { + "line": 19, + "column": 5, + "problem": "LocalFunction" + }, + { + "line": 21, + "column": 13, + "problem": "VarDeclaration" + }, + { + "line": 28, + "column": 5, + "problem": "VarDeclaration" + }, + { + "line": 28, + "column": 17, + "problem": "ArrayLiteralNoContextType" + }, + { + "line": 29, + "column": 10, + "problem": "VarDeclaration" + }, + { + "line": 32, + "column": 5, + "problem": "ForInStatement" + }, + { + "line": 32, + "column": 10, + "problem": "VarDeclaration" + }, + { + "line": 33, + "column": 21, + "problem": "PropertyAccessByIndex" + }, + { + "line": 35, + "column": 10, + "problem": "VarDeclaration" + } + ] +} \ No newline at end of file diff --git a/linter/test_linter.sh b/linter/test_linter.sh new file mode 100644 index 000000000..414a1d798 --- /dev/null +++ b/linter/test_linter.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# +# Copyright (c) 2022-2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +echo +echo "=======================" +echo "test linter in IDE mode" +echo "=======================" +node ./dist/tslinter.js --deveco-plugin-mode < ./test/linter/problems.ts +echo +echo "===========" +echo "end of test" +echo "===========" diff --git a/linter/tsconfig.json b/linter/tsconfig.json new file mode 100644 index 000000000..4263a7a58 --- /dev/null +++ b/linter/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "CommonJS", + "target": "ES6", + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "outDir": "build" + }, + + "include": ["src/**/*"] +} \ No newline at end of file diff --git a/linter/tslinter.cmd b/linter/tslinter.cmd new file mode 100644 index 000000000..98905edb3 --- /dev/null +++ b/linter/tslinter.cmd @@ -0,0 +1,18 @@ +:: +:: Copyright (c) 2022-2023 Huawei Device Co., Ltd. +:: Licensed under the Apache License, Version 2.0 (the "License"); +:: you may not use this file except in compliance with the License. +:: You may obtain a copy of the License at +:: +:: http://www.apache.org/licenses/LICENSE-2.0 +:: +:: Unless required by applicable law or agreed to in writing, software +:: distributed under the License is distributed on an "AS IS" BASIS, +:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +:: See the License for the specific language governing permissions and +:: limitations under the License. +:: +@echo off +@set TSLINTER_HOME_PATH=%~dp0 + +node %TSLINTER_HOME_PATH%./dist/tslinter.js %* diff --git a/linter/tslinter.sh b/linter/tslinter.sh new file mode 100644 index 000000000..f0e371296 --- /dev/null +++ b/linter/tslinter.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# +# Copyright (c) 2022-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# get absolute path to linter folder for possible use in future +TSLINTER_HOME_PATH=`cd $(dirname $0) && pwd` + +# use relative path due to node.js error under cygwin environment +node $(dirname $0)/./dist/tslinter.js $@ diff --git a/linter/webpack.config.js b/linter/webpack.config.js new file mode 100644 index 000000000..206c587d1 --- /dev/null +++ b/linter/webpack.config.js @@ -0,0 +1,14 @@ +let path = require('path'); + +module.exports = { + mode: "development", + target: "node", + entry: './build/main.js', + externalsType: 'commonjs', + externals: { + typescript: "typescript" + }, + output: { + filename: "tslinter.js" + } +} -- Gitee