diff --git a/.travis.yml b/.travis.yml index 356f7b1..310d1a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,8 @@ script: after_script: - greenkeeper-lockfile-upload - - github_changelog_generator --no-verbose -u buehler -p typescript-hero --enhancement-labels "enhancement,feature" --include-labels "bug,enhancement,feature" + - npm run semantic-release-pre + - github_changelog_generator --no-verbose -u buehler -p typescript-hero --enhancement-labels "enhancement,feature" --include-labels "bug,enhancement,feature" --future-release $(node -p "require('./package.json').version") - npm install -g vsce - npm run semantic-release diff --git a/.vscode/launch.json b/.vscode/launch.json index 77c6864..98daa37 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -31,26 +31,7 @@ "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ] - }, - { - "name": "Attach Server", - "type": "node", - "protocol": "auto", - "request": "attach", - "port": 6004, - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/out/**/*.js" - ] } ], - "compounds": [ - { - "name": "Launch Extension & Server", - "configurations": [ - "Launch Extension", - "Attach Server" - ] - } - ] + "compounds": [] } diff --git a/README.md b/README.md index 7b7c2ac..6b7c889 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,15 @@ If you search for this feature: here's the solution (and many more). Typescript in the future and there are many features in the pipeline that will enhance the way you work with typescript. +[![Travis build](https://img.shields.io/travis/buehler/typescript-hero.svg)](https://travis-ci.org/buehler/typescript-hero) +[![Marketplace](https://vsmarketplacebadge.apphb.com/version-short/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) +[![Installs](https://vsmarketplacebadge.apphb.com/installs/rbbit.typescript-hero.svg)](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) +[![GitHub issues](https://img.shields.io/github/issues/buehler/typescript-hero.svg)](https://github.com/buehler/typescript-hero/issues) +[![GitHub pull requests](https://img.shields.io/github/issues-pr/buehler/typescript-hero.svg)](https://github.com/buehler/typescript-hero/pulls) +[![Semantic release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) +[![Greenkeeper](https://badges.greenkeeper.io/buehler/typescript-hero.svg)](https://greenkeeper.io/) +[![License](https://img.shields.io/github/license/buehler/typescript-hero.svg)](https://github.com/buehler/typescript-hero/blob/master/LICENSE) + ## Features at a glance Here is a brief list, of what TypeScript Hero is capable of (more at the end): @@ -73,6 +82,7 @@ The following settings do have the prefix `resolver`. So an example setting coul | multiLineTrailingComma | When multiline imports are created, `true` inserts a trailing comma to the last line | | disableImportSorting | Disable sorting during organize imports action | | importGroups | The groups that are used for sorting the imports (description below) | +| ignoreImportsForOrganize | Imports that are never removed during organize import (e.g. react) | ### Code outline view diff --git a/package-lock.json b/package-lock.json index b603b7f..1ca1ec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,9 +66,9 @@ "dev": true }, "@types/node": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.10.tgz", - "integrity": "sha512-ATKQAMGah+e3qNBVdJoCIJk3+RWBkPYtmlluGewO1+t/JmkXEoLnt/WDgHynfGvJyQWTKMq+N1az1E/5YASYGg==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.13.tgz", + "integrity": "sha512-Y3EAG7VA7NVNbZek/fjJtILnmTk/ZfpJuWZGDBqDZ1dVIxgJJJ82fXPW7pKnqyV9CD/9bcPOCi7eErUqGMHOrA==", "dev": true }, "@types/reflect-metadata": { @@ -315,27 +315,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", - "dev": true, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } + "dev": true }, "block-stream": { "version": "0.0.9", @@ -344,9 +324,9 @@ "dev": true }, "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", "dev": true }, "boom": { @@ -355,16 +335,34 @@ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=" }, "boxen": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.1.0.tgz", - "integrity": "sha1-sbad1SIwXoB6md7ud329blFnsQI=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.2.0.tgz", + "integrity": "sha512-tfKK3nq0qXXOxvXEYW1k1XNRrDuQzO2oFPvLD3Fs1I58n0leuTNlftBmu3seUCyZvDfiqgRaxlqZs9WJAbSA7g==", "dev": true, "dependencies": { + "ansi-styles": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", + "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", + "dev": true + }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "dev": true + }, + "supports-color": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.0.tgz", + "integrity": "sha512-Ts0Mu/A1S1aZxEJNG88I4Oc9rcZSBFNac5e27yh4j2mqbhZSSzR1Ah79EYwSn9Zuh7lrlGD2cVGzw1RKGzyLSg==", + "dev": true } } }, @@ -450,6 +448,12 @@ "integrity": "sha1-jn9YRCJzGCAYvhho5Twir2WiGUg=", "dev": true, "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", + "dev": true + }, "lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", @@ -514,6 +518,18 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "dev": true + }, + "color-name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz", + "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=", + "dev": true + }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", @@ -540,7 +556,21 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true + "dev": true, + "dependencies": { + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true + } + } }, "config-chain": { "version": "1.1.11", @@ -566,12 +596,6 @@ "integrity": "sha1-XgIWYA9GhhkPDILvuws90RtJzjQ=", "dev": true, "dependencies": { - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true - }, "lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", @@ -621,10 +645,10 @@ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "dev": true }, - "cross-spawn-async": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", - "integrity": "sha1-hF/wwINKPe2dFg2sptOQkGuyiMw=", + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true }, "cryptiles": { @@ -657,15 +681,15 @@ } }, "dateformat": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", - "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true }, "debug": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", - "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "dev": true }, "decamelize": { @@ -746,6 +770,12 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=", "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true } } }, @@ -767,17 +797,17 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true } } }, @@ -842,9 +872,9 @@ "dev": true }, "execa": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz", - "integrity": "sha1-TrZGejaglfq7KXD/nV4/t7zm68M=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true }, "expand-brackets": { @@ -1796,18 +1826,18 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", @@ -1884,18 +1914,18 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", @@ -1968,6 +1998,12 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "dependencies": { + "dateformat": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", + "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=", + "dev": true + }, "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", @@ -1988,18 +2024,18 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", @@ -2031,9 +2067,9 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=" }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, "has-gulplog": { @@ -2293,9 +2329,9 @@ "dev": true }, "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { @@ -2308,15 +2344,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } + "dev": true }, "isstream": { "version": "0.1.2", @@ -2721,6 +2749,12 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true }, + "debug": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", @@ -2733,6 +2767,18 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, "supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", @@ -2748,9 +2794,9 @@ "dev": true }, "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "multimatch": { @@ -2827,9 +2873,9 @@ "dev": true }, "npm-run-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", - "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true }, "npmconf": { @@ -2937,6 +2983,12 @@ "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, "p-map": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", @@ -2992,9 +3044,9 @@ "dev": true }, "path-key": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", - "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-object": { @@ -3013,7 +3065,15 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true + "dev": true, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } }, "path-type": { "version": "1.1.0", @@ -3162,18 +3222,10 @@ "dev": true }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true }, "readdirp": { "version": "2.1.0", @@ -3255,15 +3307,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.1.tgz", "integrity": "sha1-fuxWyJMXqCLL/qmbA5zlQ8LhX2c=", - "dev": true, - "dependencies": { - "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", - "dev": true - } - } + "dev": true }, "request-promise-core": { "version": "1.1.1", @@ -3361,6 +3405,18 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, "shell-quote": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", @@ -3374,9 +3430,9 @@ "dev": true }, "sinon": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.7.tgz", - "integrity": "sha1-FFFhSi6qsFu02HbBM1zUATLsUSc=", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.8.tgz", + "integrity": "sha1-Md4G/tj7o6Zx5XbdltClhjeW8lw=", "dev": true }, "sinon-chai": { @@ -3504,9 +3560,9 @@ "dev": true }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, "string-width": { @@ -3581,9 +3637,9 @@ "dev": true }, "term-size": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-0.1.1.tgz", - "integrity": "sha1-hzYLljlsq1dgljcUzaDQy+7K2co=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "dev": true }, "text-encoding": { @@ -3602,7 +3658,21 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true + "dev": true, + "dependencies": { + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true + } + } }, "through2-filter": { "version": "2.0.0", @@ -3681,15 +3751,7 @@ "version": "1.0.0-node-0.10-support", "resolved": "https://registry.npmjs.org/travis-deploy-once/-/travis-deploy-once-1.0.0-node-0.10-support.tgz", "integrity": "sha1-mOzOfZWy9Lpdze7r9Uud+HcT1eY=", - "dev": true, - "dependencies": { - "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", - "dev": true - } - } + "dev": true }, "trim-newlines": { "version": "1.0.0", @@ -3749,9 +3811,9 @@ } }, "tsutils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.6.0.tgz", - "integrity": "sha1-5emceaiszTl3zhjYP98dI1psLrs=", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.7.1.tgz", + "integrity": "sha1-QRoOlGZSWisoaSYKVWINcpIVXiQ=", "dev": true }, "tunnel-agent": { @@ -3783,9 +3845,9 @@ "integrity": "sha1-w8yxbdqgsjFN4DHn5v7onlujRrw=" }, "typescript-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typescript-parser/-/typescript-parser-1.2.0.tgz", - "integrity": "sha512-DaoOHmU7TlqfC+tp9fjnWgp5u1xV6l3DK6zTZKpb04KQ/zIwj6G9miT+eiFbuuoC2k0qdmo3nojx7ZU/ecBbrg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/typescript-parser/-/typescript-parser-1.2.1.tgz", + "integrity": "sha512-Nuomi2vdwm2vjAHW10ebEZ/N1u9hcrn5PzAbRmUPu4uxTmcS8TwAD6xc3k1Y3kj4aC/RpFaHcYArkH1H+nrxig==" }, "uid-number": { "version": "0.0.5", @@ -3889,18 +3951,18 @@ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "through2": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", @@ -3936,9 +3998,9 @@ } }, "vscode": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.2.tgz", - "integrity": "sha1-GKKedChTzVPzwUd67CinKJVyHck=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.4.tgz", + "integrity": "sha1-Hx1NZi1VyaKLxGeqy2MikfcKaG0=", "dev": true }, "walk": { diff --git a/package.json b/package.json index b3326db..c995cfa 100644 --- a/package.json +++ b/package.json @@ -85,12 +85,13 @@ "lint": "tslint -c tslint.json --project ./config/tsconfig.build.json", "build": "del-cli ./out && tsc -p ./config/tsconfig.build.json", "package": "npm run build && del-cli './*.vsix' && vsce package", - "semantic-release": "semantic-release pre && vsce package && vsce publish -p $VSCE_TOKEN && npm install semantic-release && semantic-release post" + "semantic-release-pre": "semantic-release pre", + "semantic-release": "npm run semantic-release-pre && vsce package && vsce publish -p $VSCE_TOKEN && npm install && semantic-release post" }, "devDependencies": { "@types/chai": "^4.0.1", "@types/mocha": "^2.2.41", - "@types/node": "^8.0.10", + "@types/node": "^8.0.13", "@types/reflect-metadata": "0.0.5", "@types/sinon": "^2.3.2", "@types/sinon-chai": "^2.7.28", @@ -100,12 +101,12 @@ "mocha-testdata": "^1.2.0", "semantic-release": "^6.3.6", "semantic-release-visualstudio-marketplace-version": "^1.0.0", - "sinon": "^2.3.7", + "sinon": "^2.3.8", "sinon-chai": "^2.11.0", "tslint": "^5.5.0", "tslint-config-airbnb": "^5.2.1", - "tsutils": "^2.6.0", - "vscode": "^1.1.2" + "tsutils": "^2.7.1", + "vscode": "^1.1.4" }, "dependencies": { "inversify": "^4.2.0", @@ -113,7 +114,7 @@ "reflect-metadata": "^0.1.10", "tslib": "^1.7.1", "typescript": "^2.4.1", - "typescript-parser": "^1.2.0" + "typescript-parser": "^1.2.1" }, "activationEvents": [ "onLanguage:typescript", @@ -145,6 +146,10 @@ "command": "typescriptHero.codeFix.executeCodeAction", "title": "TS Hero (internal): Execute a code action" }, + { + "command": "typescriptHero.codeCompletion.executeIntellisenseItem", + "title": "TS Hero (internal): Execute the command for a intellisense item" + }, { "command": "typescriptHero.documentCodeOutline.gotoNode", "title": "TS Hero (internal): Jump to the given nodes location" @@ -242,6 +247,17 @@ "default": false, "description": "Defines if sorting is disable during organize imports." }, + "typescriptHero.resolver.ignoreImportsForOrganize": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true, + "default": [ + "react" + ], + "description": "Defines imports (libraries, so the 'from' part), which are not removed during 'organize imports'." + }, "typescriptHero.resolver.importGroups": { "type": "array", "items": { diff --git a/src/common/config/ResolverConfig.ts b/src/common/config/ResolverConfig.ts index eabfbf0..a4ddc6e 100644 --- a/src/common/config/ResolverConfig.ts +++ b/src/common/config/ResolverConfig.ts @@ -88,6 +88,14 @@ export interface ResolverConfig { */ disableImportSorting: boolean; + /** + * List of import libraries ("from" part) which are ignored during the organize import function. + * + * @type {string[]} + * @memberof ResolverConfig + */ + ignoreImportsForOrganize: string[]; + /** * Returns the configured import groups. On a parsing error, a default should be provided. * diff --git a/src/extension/VscodeExtensionConfig.ts b/src/extension/VscodeExtensionConfig.ts index 3ecb975..3dd49cf 100644 --- a/src/extension/VscodeExtensionConfig.ts +++ b/src/extension/VscodeExtensionConfig.ts @@ -165,6 +165,17 @@ class VscodeResolverConfig implements ResolverConfig { return workspace.getConfiguration().get('editor.tabSize') || 4; } + /** + * Returns the list of imports that should be ignored during organize import feature. + * + * @readonly + * @type {string[]} + * @memberof VscodeResolverConfig + */ + public get ignoreImportsForOrganize(): string[] { + return workspace.getConfiguration(sectionKey).get('resolver.ignoreImportsForOrganize') || []; + } + /** * Returns the configured import groups. On a parsing error, the default is used. * diff --git a/src/extension/extensions/CodeCompletionExtension.ts b/src/extension/extensions/CodeCompletionExtension.ts index e1d874f..1ac667f 100644 --- a/src/extension/extensions/CodeCompletionExtension.ts +++ b/src/extension/extensions/CodeCompletionExtension.ts @@ -1,7 +1,8 @@ import { inject, injectable } from 'inversify'; -import { DeclarationIndex, TypescriptParser } from 'typescript-parser'; +import { DeclarationIndex, DeclarationInfo, TypescriptParser } from 'typescript-parser'; import { CancellationToken, + commands, CompletionItem, CompletionItemProvider, ExtensionContext, @@ -49,6 +50,14 @@ export class CodeCompletionExtension extends BaseExtension implements Completion this.context.subscriptions.push(languages.registerCompletionItemProvider('typescript', this)); this.context.subscriptions.push(languages.registerCompletionItemProvider('typescriptreact', this)); + this.context.subscriptions.push( + commands.registerCommand( + 'typescriptHero.codeCompletion.executeIntellisenseItem', + (document: TextDocument, declaration: DeclarationInfo) => + this.executeIntellisenseItem(document, declaration), + ), + ); + this.logger.info('Initialized'); } @@ -95,7 +104,7 @@ export class CodeCompletionExtension extends BaseExtension implements Completion !this.index.indexReady || (lineText.substring(0, position.character).match(/["'`]/g) || []).length % 2 === 1 || lineText.match(/^\s*(\/\/|\/\*\*|\*\/|\*)/g) || - lineText.match(/^import .*$/g) || + lineText.startsWith('import ') || lineText.substring(0, position.character).match(new RegExp(`(\w*[.])+${searchWord}`, 'g'))) { return Promise.resolve(null); } @@ -103,8 +112,6 @@ export class CodeCompletionExtension extends BaseExtension implements Completion this.logger.info('Search completion for word.', { searchWord }); const parsed = await this.parser.parseSource(document.getText()); - const manager = await ImportManager.create(document); - const declarations = getDeclarationsFilteredByImports( this.index.declarationInfos, document.fileName, @@ -120,13 +127,30 @@ export class CodeCompletionExtension extends BaseExtension implements Completion ) { const item = new CompletionItem(declaration.declaration.name, getItemKind(declaration.declaration)); - manager.addDeclarationImport(declaration); item.detail = declaration.from; - item.additionalTextEdits = manager.calculateTextEdits(); + item.command = { + arguments: [document, declaration], + title: 'Execute intellisense insert', + command: 'typescriptHero.codeCompletion.executeIntellisenseItem', + }; items.push(item); - - manager.reset(); } return items; } + + /** + * Executes a intellisense item that provided a document and a declaration to add. + * Does make the calculation of the text edits async. + * + * @private + * @param {TextDocument} document + * @param {DeclarationInfo} declaration + * @returns {Promise} + * @memberof CodeCompletionExtension + */ + private async executeIntellisenseItem(document: TextDocument, declaration: DeclarationInfo): Promise { + const manager = await ImportManager.create(document); + manager.addDeclarationImport(declaration); + await manager.commit(); + } } diff --git a/src/extension/extensions/ImportResolveExtension.ts b/src/extension/extensions/ImportResolveExtension.ts index 7ce02e7..d7013bf 100644 --- a/src/extension/extensions/ImportResolveExtension.ts +++ b/src/extension/extensions/ImportResolveExtension.ts @@ -6,6 +6,7 @@ import { commands, ExtensionContext, FileSystemWatcher, + ProgressLocation, StatusBarAlignment, StatusBarItem, Uri, @@ -221,18 +222,11 @@ export class ImportResolveExtension extends BaseExtension { * @memberof ImportResolveExtension */ private async buildIndex(): Promise { - this.statusBarItem.text = resolverSyncing; - - const files = await findFiles(this.config, this.rootPath); - this.logger.info(`Building index for ${files.length} files.`); - try { + await this.abstractIndexFunction('Create index.', async () => { + const files = await findFiles(this.config, this.rootPath); + this.logger.info(`Calculating index for ${files.length} files.`); await this.index.buildIndex(files); - this.logger.info('Index successfully built'); - this.statusBarItem.text = resolverOk; - } catch (e) { - this.logger.error('There was an error during the index creation', e); - this.statusBarItem.text = resolverErr; - } + }); } /** @@ -244,16 +238,43 @@ export class ImportResolveExtension extends BaseExtension { * @memberof ImportResolveExtension */ private async rebuildForFileChanges(changes: FileChanges): Promise { - this.logger.info('Rebuilding index for changed files.', changes); - this.statusBarItem.text = resolverSyncing; + this.abstractIndexFunction('Reindex changes.', async () => { + await this.index.reindexForChanges(changes); + }); + } - try { - this.index.reindexForChanges(changes); - this.statusBarItem.text = resolverOk; - } catch (e) { - this.logger.error('There was an error during the index rebuild', e); - this.statusBarItem.text = resolverErr; - } + /** + * Abstracts the build and rebuild functions to be just one call withProgress. + * + * @private + * @param {string} title + * @param {() => Promise} func + * @returns {Promise} + * @memberof ImportResolveExtension + */ + private async abstractIndexFunction(title: string, func: () => Promise): Promise { + await window.withProgress( + { + title, + location: ProgressLocation.Window, + }, + async (progress) => { + this.logger.info('(Re-)Calculating index.'); + progress.report({ message: '(Re-)Calculating index.' }); + this.statusBarItem.text = resolverSyncing; + + try { + await func(); + this.logger.info('(Re-)Calculate finished.'); + progress.report({ message: '(Re-)Calculate finished.' }); + this.statusBarItem.text = resolverOk; + } catch (e) { + this.logger.error('There was an error during the index (re)calculation.', e); + progress.report({ message: 'There was an error during the index (re)calculation.' }); + this.statusBarItem.text = resolverErr; + } + }, + ); } /** diff --git a/src/extension/managers/ImportManager.ts b/src/extension/managers/ImportManager.ts index 1b507c7..2924720 100644 --- a/src/extension/managers/ImportManager.ts +++ b/src/extension/managers/ImportManager.ts @@ -212,6 +212,10 @@ export class ImportManager implements ObjectManager { let keep: Import[] = []; for (const actImport of this.imports) { + if (ImportManager.config.resolver.ignoreImportsForOrganize.indexOf(actImport.libraryName) >= 0) { + keep.push(actImport); + continue; + } if (actImport instanceof NamespaceImport || actImport instanceof ExternalModuleImport) { if (this._parsedDocument.nonLocalUsages.indexOf(actImport.alias) > -1) { @@ -321,42 +325,27 @@ export class ImportManager implements ObjectManager { edits.push(TextEdit.delete(importRange(this.document, imp.start, imp.end))); } } - const proxies = this._parsedDocument.imports.filter(o => o instanceof ImportProxy); - for (const group of this.importGroups) { - const grpImports = group.sortedImports; - for (const imp of grpImports) { - if (imp instanceof ImportProxy && - proxies.some((o: ImportProxy) => o.isEqual(imp as ImportProxy))) { - continue; - } - - const physicalFirstImport = grpImports.find(grpImp => grpImp.start !== undefined); - const physicalLastImport = [...grpImports].reverse().find(grpImp => grpImp.end !== undefined); - - if (physicalFirstImport && physicalLastImport) { - // If the group has more than 0 imports, delete the whole group (like in organize) - // and regenerate it at the start of it's first import that has a start position - // if there is an import that is there already - edits.push(TextEdit.replace( - new Range( - this.document.positionAt(physicalFirstImport.start!), - this.document.lineAt( - this.document.positionAt(physicalLastImport.end!).line, - ).rangeIncludingLineBreak.end, - ), - ImportManager.generator.generate(group as any), - )); - } else { - // Since the group has no imports, generate it at the top of the file. - edits.push(TextEdit.insert( - getImportInsertPosition( - window.activeTextEditor, - ), - ImportManager.generator.generate(group as any) + '\n', - )); - } - - break; + const actualDocumentsProxies = this._parsedDocument.imports.filter(o => o instanceof ImportProxy); + for (const imp of this.imports) { + if (imp instanceof ImportProxy && + actualDocumentsProxies.some((o: ImportProxy) => o.isEqual(imp as ImportProxy))) { + continue; + } + if (imp.isNew) { + edits.push(TextEdit.insert( + getImportInsertPosition( + window.activeTextEditor, + ), + ImportManager.generator.generate(imp) + '\n', + )); + } else { + edits.push(TextEdit.replace( + new Range( + this.document.positionAt(imp.start!), + this.document.positionAt(imp.end!), + ), + ImportManager.generator.generate(imp), + )); } } } diff --git a/test/_workspace/.vscode/settings.json b/test/_workspace/.vscode/settings.json index a7e4b04..fca224e 100755 --- a/test/_workspace/.vscode/settings.json +++ b/test/_workspace/.vscode/settings.json @@ -11,5 +11,6 @@ ], "typescriptHero.verbosity": "Warnings", "tslint.enable": false, - "typescript.check.tscVersion": false + "typescript.check.tscVersion": false, + "typescriptHero.codeOutline.enabled": true } diff --git a/test/_workspace/extension/managers/ImportManagerFile.tsx b/test/_workspace/extension/managers/ImportManagerFile.tsx new file mode 100644 index 0000000..a491196 --- /dev/null +++ b/test/_workspace/extension/managers/ImportManagerFile.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; + +export function doSomething(): any { + return ( +
+ ); +} diff --git a/test/extension/extensions/CodeActionExtension.test.ts b/test/extension/extensions/CodeActionExtension.test.ts index 6c9b50b..f9d0acc 100644 --- a/test/extension/extensions/CodeActionExtension.test.ts +++ b/test/extension/extensions/CodeActionExtension.test.ts @@ -25,10 +25,11 @@ class SpyCodeAction implements CodeAction { } } +const rootPath = Container.get(iocSymbols.rootPath); + describe('CodeActionExtension', () => { let extension: any; - const rootPath = Container.get(iocSymbols.rootPath); before(async () => { const ctx = Container.get(iocSymbols.extensionContext); diff --git a/test/extension/extensions/CodeCompletionExtension.test.ts b/test/extension/extensions/CodeCompletionExtension.test.ts index b83f18f..cff8905 100644 --- a/test/extension/extensions/CodeCompletionExtension.test.ts +++ b/test/extension/extensions/CodeCompletionExtension.test.ts @@ -10,6 +10,8 @@ import { iocSymbols } from '../../../src/extension/IoCSymbols'; const should = chai.should(); +const rootPath = Container.get(iocSymbols.rootPath); + describe('CodeCompletionExtension', () => { const token = new vscode.CancellationTokenSource().token; @@ -17,8 +19,6 @@ describe('CodeCompletionExtension', () => { let extension: CodeCompletionExtension; before(async () => { - const rootPath = Container.get(iocSymbols.rootPath); - const file = join( rootPath, 'extension/extensions/codeCompletionExtension/codeCompletionFile.ts', @@ -79,25 +79,20 @@ describe('CodeCompletionExtension', () => { result![0].detail!.should.equal('/server/indices/MyClass'); }); - it('shoud add an insert text edit if import would be new', async () => { + it('shoud add an insert command text edit if import would be new', async () => { const result = await extension.provideCompletionItems(document, new vscode.Position(6, 5), token); should.exist(result); - result![0].additionalTextEdits!.should.be.an('array').with.lengthOf(1); - result![0].additionalTextEdits![0].newText.should.equal( - `import { MyClass } from '../../../server/indices/MyClass';\n` + - `import { AlreadyImported } from './codeCompletionImports';\n`, - ); + result![0].command!.command.should.equal('typescriptHero.codeCompletion.executeIntellisenseItem'); + result![0].command!.arguments![1].declaration.name.should.equal('MyClass'); }); - it('shoud add a replace text edit if import will be updated with new specifier', async () => { + it('shoud add a replace command text edit if import will be updated with new specifier', async () => { const result = await extension.provideCompletionItems(document, new vscode.Position(9, 10), token); should.exist(result); - result![0].additionalTextEdits!.should.be.an('array').with.lengthOf(1); - result![0].additionalTextEdits![0].newText.should.equal( - `import { AlreadyImported, ShouldBeImported } from './codeCompletionImports';\n`, - ); + result![0].command!.command.should.equal('typescriptHero.codeCompletion.executeIntellisenseItem'); + result![0].command!.arguments![1].declaration.name.should.equal('ShouldBeImported'); }); it('shoud resolve to no import if import is already imported', async () => { diff --git a/test/extension/extensions/DocumentSymbolStructureExtension.test.ts b/test/extension/extensions/DocumentSymbolStructureExtension.test.ts index 44e0c47..5e178d8 100644 --- a/test/extension/extensions/DocumentSymbolStructureExtension.test.ts +++ b/test/extension/extensions/DocumentSymbolStructureExtension.test.ts @@ -19,13 +19,14 @@ import { NotParseableStructureTreeItem, } from '../../../src/extension/provider-items/document-structure/NotParseableStructureTreeItem'; +const rootPath = Container.get(iocSymbols.rootPath); + describe('DocumentSymbolStructureExtension', () => { let extension: DocumentSymbolStructureExtension; let document: vscode.TextDocument; before(async () => { - const rootPath = Container.get(iocSymbols.rootPath); const file = join( rootPath, 'extension/extensions/documentSymbolStructureExtension/documentSymbolFile.ts', @@ -76,7 +77,7 @@ describe('DocumentSymbolStructureExtension', () => { const elements = await extension.getChildren() as BaseStructureTreeItem[]; elements[0].should.be.instanceof(DisabledStructureTreeItem); } finally { - await config.update('codeOutline.enabled', undefined); + await config.update('codeOutline.enabled', true); } }); diff --git a/test/extension/extensions/ImportResolveExtension.test.ts b/test/extension/extensions/ImportResolveExtension.test.ts index 97428da..0bfd96b 100644 --- a/test/extension/extensions/ImportResolveExtension.test.ts +++ b/test/extension/extensions/ImportResolveExtension.test.ts @@ -11,13 +11,13 @@ import { iocSymbols } from '../../../src/extension/IoCSymbols'; chai.should(); +const rootPath = Container.get(iocSymbols.rootPath); + describe('ImportResolveExtension', () => { - let rootPath: string; let extension: any; before(async () => { - rootPath = Container.get(iocSymbols.rootPath); const file = join( rootPath, 'extension/extensions/importResolveExtension/addImportToDocument.ts', @@ -57,7 +57,6 @@ describe('ImportResolveExtension', () => { }); describe('addImportToDocument', () => { - const rootPath = Container.get(iocSymbols.rootPath); const file = join( rootPath, 'extension/extensions/importResolveExtension/addImportToDocument.ts', @@ -85,7 +84,7 @@ describe('ImportResolveExtension', () => { docuemntPath: document.fileName, }); await extension.addImportToDocument(items[0]); - document.getText().should.equal(`import * as bodyParser from 'body-parser';\n\n`); + document.getText().should.equal(`import * as bodyParser from 'body-parser';\n`); }); it('shoud write a named import correctly', async () => { @@ -95,7 +94,7 @@ describe('ImportResolveExtension', () => { docuemntPath: document.fileName, }); await extension.addImportToDocument(items[0]); - document.getText().should.equal(`import { Class1 } from '../../../server/indices/MyClass';\n\n`); + document.getText().should.equal(`import { Class1 } from '../../../server/indices/MyClass';\n`); }); it('shoud update a named import correcty', async () => { @@ -106,7 +105,7 @@ describe('ImportResolveExtension', () => { }); await extension.addImportToDocument(items[0]); await extension.addImportToDocument(items[1]); - document.getText().should.equal(`import { Class1, Class2 } from '../../../server/indices/MyClass';\n\n`); + document.getText().should.equal(`import { Class1, Class2 } from '../../../server/indices/MyClass';\n`); }); it('shoud use the correct relative path', async () => { diff --git a/test/extension/import-grouping/KeywordImportGroup.test.ts b/test/extension/import-grouping/KeywordImportGroup.test.ts index 65ed0c4..b63f8d6 100644 --- a/test/extension/import-grouping/KeywordImportGroup.test.ts +++ b/test/extension/import-grouping/KeywordImportGroup.test.ts @@ -10,6 +10,8 @@ import { iocSymbols } from '../../../src/extension/IoCSymbols'; chai.should(); +const rootPath = Container.get(iocSymbols.rootPath); + describe('KeywordImportGroup', () => { let file: File; @@ -18,7 +20,6 @@ describe('KeywordImportGroup', () => { let generator: TypescriptCodeGenerator; before(async () => { - const rootPath = Container.get(iocSymbols.rootPath); const parser = Container.get(iocSymbols.typescriptParser); config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); diff --git a/test/extension/import-grouping/RegexImportGroup.test.ts b/test/extension/import-grouping/RegexImportGroup.test.ts index b769228..74b2ed1 100644 --- a/test/extension/import-grouping/RegexImportGroup.test.ts +++ b/test/extension/import-grouping/RegexImportGroup.test.ts @@ -10,6 +10,8 @@ import { iocSymbols } from '../../../src/extension/IoCSymbols'; chai.should(); +const rootPath = Container.get(iocSymbols.rootPath); + describe('RegexImportGroup', () => { let file: File; @@ -19,7 +21,6 @@ describe('RegexImportGroup', () => { before(async () => { const parser = Container.get(iocSymbols.typescriptParser); - const rootPath = Container.get(iocSymbols.rootPath); config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); file = await parser.parseFile( diff --git a/test/extension/import-grouping/RemainImportGroup.test.ts b/test/extension/import-grouping/RemainImportGroup.test.ts index 4c56ea6..54209a0 100644 --- a/test/extension/import-grouping/RemainImportGroup.test.ts +++ b/test/extension/import-grouping/RemainImportGroup.test.ts @@ -10,6 +10,8 @@ import { iocSymbols } from '../../../src/extension/IoCSymbols'; chai.should(); +const rootPath = Container.get(iocSymbols.rootPath); + describe('RemainImportGroup', () => { let file: File; @@ -19,7 +21,6 @@ describe('RemainImportGroup', () => { before(async () => { const parser = Container.get(iocSymbols.typescriptParser); - const rootPath = Container.get(iocSymbols.rootPath); config = Container.get(iocSymbols.configuration); generator = Container.get(iocSymbols.generatorFactory)(); file = await parser.parseFile( diff --git a/test/extension/managers/ClassManager.test.ts b/test/extension/managers/ClassManager.test.ts index 6c07b95..c596860 100644 --- a/test/extension/managers/ClassManager.test.ts +++ b/test/extension/managers/ClassManager.test.ts @@ -19,9 +19,10 @@ import { VscodeExtensionConfig } from '../../../src/extension/VscodeExtensionCon const should = chai.should(); chai.use(sinonChai); +const rootPath = Container.get(iocSymbols.rootPath); + describe('ClassManager', () => { - const rootPath = Container.get(iocSymbols.rootPath); const file = join(rootPath, 'extension/managers/ClassManagerFile.ts'); let document: TextDocument; let documentText: string; diff --git a/test/extension/managers/ImportManager.test.ts b/test/extension/managers/ImportManager.test.ts index c6f1a68..ea2603c 100644 --- a/test/extension/managers/ImportManager.test.ts +++ b/test/extension/managers/ImportManager.test.ts @@ -36,9 +36,10 @@ function restoreInputBox(stub: sinon.SinonStub): void { stub.restore(); } +const rootPath = Container.get(iocSymbols.rootPath); + describe('ImportManager', () => { - const rootPath = Container.get(iocSymbols.rootPath); const file = join(rootPath, 'extension/managers/ImportManagerFile.ts'); let document: TextDocument; let documentText: string; @@ -564,18 +565,18 @@ describe('ImportManager', () => { document.lineAt(0).text.should.equals(`import {Class1} from '../resourceIndex';`); }); - it('should add a single new import to the document (@correct place)', async () => { + it('should add a single new import to the document top', async () => { const ctrl = await ImportManager.create(document); const declaration = index.declarationInfos.find(o => o.declaration.name === 'NotBarelExported'); ctrl.addDeclarationImport(declaration!); (await ctrl.commit()).should.be.true; - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { NotBarelExported } from '../../server/indices/NotBarelExported';`, ); }); - it('should add two new imports to the document (@correct place)', async () => { + it('should add two new imports to the document top', async () => { const ctrl = await ImportManager.create(document); const declaration = index.declarationInfos.find(o => o.declaration.name === 'NotBarelExported'); const declaration2 = index.declarationInfos.find(o => o.declaration.name === 'isString'); @@ -583,7 +584,7 @@ describe('ImportManager', () => { ctrl.addDeclarationImport(declaration!).addDeclarationImport(declaration2!); (await ctrl.commit()).should.be.true; - document.lineAt(2).text.should.equals( + document.lineAt(0).text.should.equals( `import { NotBarelExported } from '../../server/indices/NotBarelExported';`, ); document.lineAt(1).text.should.equals( @@ -591,7 +592,7 @@ describe('ImportManager', () => { ); }); - it('should add three new imports to the document (@correct place)', async () => { + it('should add three new imports to the document top', async () => { const ctrl = await ImportManager.create(document); const declaration = index.declarationInfos.find(o => o.declaration.name === 'NotBarelExported'); const declaration2 = index.declarationInfos.find(o => o.declaration.name === 'isString'); @@ -603,7 +604,7 @@ describe('ImportManager', () => { (await ctrl.commit()).should.be.true; - document.lineAt(3).text.should.equals( + document.lineAt(0).text.should.equals( `import { NotBarelExported } from '../../server/indices/NotBarelExported';`, ); document.lineAt(1).text.should.equals( @@ -614,7 +615,7 @@ describe('ImportManager', () => { ); }); - it('should add a single new module import to the document (@correct place)', async () => { + it('should add a single new module import to the document top', async () => { const ctrl = await ImportManager.create(document); const declaration = index.declarationInfos.find(o => o.from === 'body-parser'); ctrl.addDeclarationImport(declaration!); @@ -623,7 +624,7 @@ describe('ImportManager', () => { document.lineAt(0).text.should.equals(`import * as bodyParser from 'body-parser';`); }); - it('should add a single default import to the document (@correct place)', async () => { + it('should add a single default import to the document top', async () => { const stub = mockInputBox('DEFAULT_IMPORT'); try { const ctrl = await ImportManager.create(document); @@ -634,7 +635,7 @@ describe('ImportManager', () => { (await ctrl.commit()).should.be.true; stub.should.be.calledWithMatch({ value: 'myDefaultExportedFunction' }); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import DEFAULT_IMPORT from '../../server/indices/defaultExport/lateDefaultExportedElement';`, ); } finally { @@ -653,7 +654,7 @@ describe('ImportManager', () => { document.lineAt(0).text.should.equal( `import { FancierLibraryClass } from 'fancy-library/FancierLibraryClass';`, ); - document.lineAt(2).text.should.equal( + document.lineAt(1).text.should.equal( `import { Class1, FancierLibraryClass as ALIASED_IMPORT } from '../../server/indices';`, ); } finally { @@ -696,7 +697,7 @@ describe('ImportManager', () => { } (await ctrl.commit()).should.be.true; - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { default as DEFAULT_IMPORT, MultiExportClass } ` + `from '../../server/indices/defaultExport/multiExport';`, ); @@ -714,10 +715,10 @@ describe('ImportManager', () => { .addDeclarationImport(declaration2!) .commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { myComponent } from '../../server/indices/MyReactTemplate';`, ); - document.lineAt(0).text.should.equals(`import { Class1, Class2 } from '../../server/indices';`); + document.lineAt(1).text.should.equals(`import { Class1, Class2 } from '../../server/indices';`); }); it('should convert a default import when a normal specifier is added', async () => { @@ -727,14 +728,14 @@ describe('ImportManager', () => { let declaration = index.declarationInfos.find(o => o.declaration.name === 'multiExport'); await ctrl.addDeclarationImport(declaration!).commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import DEFAULT_IMPORT from '../../server/indices/defaultExport/multiExport';`, ); declaration = index.declarationInfos.find(o => o.declaration.name === 'MultiExportClass'); await ctrl.addDeclarationImport(declaration!).commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { default as DEFAULT_IMPORT, MultiExportClass } ` + `from '../../server/indices/defaultExport/multiExport';`, ); @@ -750,7 +751,7 @@ describe('ImportManager', () => { let declaration = index.declarationInfos.find(o => o.declaration.name === 'MultiExportClass'); await ctrl.addDeclarationImport(declaration!).commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { MultiExportClass } from '../../server/indices/defaultExport/multiExport';`, ); @@ -758,7 +759,7 @@ describe('ImportManager', () => { ctrl.addDeclarationImport(declaration!); await ctrl.commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { default as DEFAULT_IMPORT, MultiExportClass } ` + `from '../../server/indices/defaultExport/multiExport';`, ); @@ -780,10 +781,10 @@ describe('ImportManager', () => { .addDeclarationImport(declaration2!) .commit(); - document.lineAt(1).text.should.equals( + document.lineAt(0).text.should.equals( `import { MultiExportClass } from '../../server/indices/defaultExport/multiExport';`, ); - document.lineAt(0).text.should.equals( + document.lineAt(1).text.should.equals( `import { Class1, Class2 } from '../../server/indices';`, ); @@ -832,3 +833,45 @@ describe('ImportManager', () => { }); }); + +describe('ImportManager with .tsx files', () => { + + const file = join(rootPath, 'extension/managers/ImportManagerFile.tsx'); + let document: TextDocument; + let documentText: string; + let index: DeclarationIndex; + let files: string[]; + + before(async () => { + const config = new VscodeExtensionConfig(); + files = await findFiles(config, rootPath); + + index = index = Container.get(iocSymbols.declarationIndex); + await index.buildIndex(files); + + document = await workspace.openTextDocument(file); + await window.showTextDocument(document); + + documentText = document.getText(); + }); + + afterEach(async () => { + await window.activeTextEditor!.edit((builder) => { + builder.delete(new Range( + new Position(0, 0), + document.lineAt(document.lineCount - 1).rangeIncludingLineBreak.end, + )); + builder.insert(new Position(0, 0), documentText); + }); + + }); + + it('should not remove "react" since it is ignored in config', async () => { + const ctrl = await ImportManager.create(document); + ctrl.organizeImports(); + + (ctrl as any).imports.should.have.lengthOf(1); + (ctrl as any).imports[0].libraryName.should.equal('react'); + }); + +}); diff --git a/test/index.ts b/test/index.ts index f28e4d4..31f24fd 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,7 +1,9 @@ import 'reflect-metadata'; + +import { ExtensionContext, Memento } from 'vscode'; + import { Container } from '../src/extension/IoC'; import { iocSymbols } from '../src/extension/IoCSymbols'; -import { ExtensionContext, Memento } from 'vscode'; // tslint:disable